9 Commits

Author SHA1 Message Date
lwvmobile
4924bd249a Remove Remnants of ITPP; #331
Tweaks to Decrypted MBE Playback; #298 #329
2026-01-05 12:56:07 -05:00
lwvmobile
a5e000a14c Remove ITPP Dependencies; #331
Rework P25p1 NID code from KA1RBI's OP25 code;

Remove ITPP Cmake, build config scripts, docs, etc.
2026-01-04 20:31:30 -05:00
lwvmobile
53eaccc892 .mbe file playback DMRA Forced ALG, KEY, Late Entry IV for DMR; #298 #329
Working RC4;

WIP on Moto BP Forced;
2026-01-02 01:41:18 -05:00
lwvmobile
e95cd4dd3a Fix AES-OFB and Misc Issues on .mbe file playback; #329 WIP 2026-01-01 23:00:41 -05:00
lwvmobile
48b0c4025b Add defined(__CYGWIN__) Fix for #330 2025-12-31 18:29:36 -05:00
lwvmobile
2171df515d Merge pull request #330 from Coriou/fix/macos-oss-build
macOS: disable OSS backend cleanly and fix build/link errors
2025-12-31 17:47:50 -05:00
Benjamin Coriou
83d7460a0b macOS: disable OSS backend cleanly and fix build/link errors
macOS has no OSS (/dev/dsp) support, but dsd-fme currently compiles and links OSS code unconditionally, leading to build and link failures.

This PR:

* disables OSS backend cleanly on macOS

* provides a no-op openOSSOutput() stub to satisfy callers

* guards OSS-specific headers and ioctl usage

* preserves existing behavior on Linux/OSS platforms

This allows dsd-fme to build and run correctly on macOS using PulseAudio/CoreAudio paths.
2025-12-31 15:03:37 +01:00
lwvmobile
38ad11dbef Fix AES-OFB type on .mbe file playback; #329 2025-12-29 22:36:47 -05:00
lwvmobile
eddd6cb8b1 Add DES(56) and AES(128/256) OFB Decryption to P25 .mbe file playback; #329
This does not include DES-XL due to needing to know HDU or LDU2 and complications of SDRtrunk P1 ESS handling, and also unknown Phase 2 method for XL.

Nor TDEA (never observed on P25 despite in spec);
2025-12-29 22:25:23 -05:00
19 changed files with 445 additions and 160 deletions

View File

@@ -52,14 +52,13 @@ git_describe(GIT_TAG)
find_package(LibSndFile REQUIRED) find_package(LibSndFile REQUIRED)
find_package(MBE REQUIRED) find_package(MBE REQUIRED)
find_package(ITPP REQUIRED)
find_package(RTLSDR) find_package(RTLSDR)
find_package(Curses REQUIRED) find_package(Curses REQUIRED)
find_package(PulseAudio REQUIRED) find_package(PulseAudio REQUIRED)
find_package(CODEC2) find_package(CODEC2)
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIRS}) include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIRS})
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES}) set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES})
if(RTLSDR_FOUND) if(RTLSDR_FOUND)
find_package(Threads) find_package(Threads)

View File

@@ -1,15 +0,0 @@
# - Try to find ITPP
# 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
#
find_path(ITPP_INCLUDE_DIR itpp/itcomm.h)
set(ITPP_NAMES ${ITPP_NAMES} itpp libitpp libitpp.dll)
FIND_LIBRARY(ITPP_LIBRARY NAMES ${ITPP_NAMES})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ITPP DEFAULT_MSG ITPP_LIBRARY ITPP_INCLUDE_DIR)

View File

@@ -61,10 +61,6 @@ if [ "$RELEASE" = "y" ]; then
#start copying things to the lib folder #start copying things to the lib folder
cp -r /lib/pulseaudio/ dsd-fme-portable/lib/ cp -r /lib/pulseaudio/ dsd-fme-portable/lib/
#support for LAPACK, BLAS, and FFTW3 (SIMD math libraries and dependencies)
cp /lib/lapack/* dsd-fme-portable/dsd-fme/
cp /bin/cyggfortran* dsd-fme-portable/dsd-fme/
#start copying things into the dsd-fme folder #start copying things into the dsd-fme folder
cp dsd-fme/build/dsd-fme.exe dsd-fme-portable/dsd-fme/ cp dsd-fme/build/dsd-fme.exe dsd-fme-portable/dsd-fme/
cp -r dsd-fme/examples dsd-fme-portable/dsd-fme/ cp -r dsd-fme/examples dsd-fme-portable/dsd-fme/
@@ -98,7 +94,6 @@ if [ "$RELEASE" = "y" ]; then
#compiled items into release dsd-fme folder #compiled items into release dsd-fme folder
cp codec2/build/src/cygcodec2* dsd-fme-portable/dsd-fme/ cp codec2/build/src/cygcodec2* dsd-fme-portable/dsd-fme/
cp itpp-4.3.1/build/itpp/cygitpp* dsd-fme-portable/dsd-fme/
cp rtl-sdr/build/src/cyg* dsd-fme-portable/dsd-fme/ cp rtl-sdr/build/src/cyg* dsd-fme-portable/dsd-fme/
cp mbelib/build/cygmbe* dsd-fme-portable/dsd-fme/ cp mbelib/build/cygmbe* dsd-fme-portable/dsd-fme/

View File

@@ -17,11 +17,6 @@ if [ "$ANSWER" = "y" ]; then
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
printf "Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal\n"
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
sudo rm -R itpp-4.3.1-3-x86_64.pkg.tar.xz
git clone https://github.com/lwvmobile/mbelib git clone https://github.com/lwvmobile/mbelib
cd mbelib cd mbelib
git checkout ambe_tones git checkout ambe_tones

View File

@@ -19,22 +19,6 @@ if [ "$ANSWER" = "y" ]; then
export LD_LIBRARY_PATH export LD_LIBRARY_PATH
echo $LD_LIBRARY_PATH echo $LD_LIBRARY_PATH
#ITPP
cd $cdir
printf "Installing itpp 4.3.1 from source http://sourceforge.net/projects/itpp/files/latest/download?source=files\n Please wait!\n"
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
tar xjf itpp-latest.tar.bz2
cd itpp-4.3.1/
#newer Cygwin has Cmake 4.1.3 (or newer) so we need to replace the line with cmake_minimum_required to a newer version
#this doesn't seem to break anything, its just that cmake will refuse to run properly without a newer min version in it
#I'm just going to use the version that is used for most all my other cmake projects, seems to still be okay with new cmake
sed -i '/^cmake_minimum_required *( *VERSION *2\.8\.6 *)$/c\cmake_minimum_required(VERSION 3.10.2)' CMakeLists.txt
mkdir build
cd build
cmake ..
make -j $(nproc)
make install
#MBELIB #MBELIB
cd $cdir cd $cdir
printf "Installing mbelib\n Please wait!\n" printf "Installing mbelib\n Please wait!\n"

View File

@@ -12,13 +12,7 @@ read -p "Have you viewed the patent notice? y/N " ANSWER
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]') ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
if [ "$ANSWER" = "y" ]; then if [ "$ANSWER" = "y" ]; then
sudo apt update sudo apt update
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncurses-dev libncurses6 libcodec2-dev sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncurses-dev libncurses6 libcodec2-dev
chkitpp=$(dpkg -l libitpp-dev 2>/dev/null | awk '/^ii/ {print 1} END {if (NR == 0) print 0}')
if [ "$chkitpp" -lt "1" ];then
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
read -p "Press Enter to exit..." x
exit 1
fi
git clone https://github.com/lwvmobile/mbelib git clone https://github.com/lwvmobile/mbelib
cd mbelib cd mbelib
git checkout ambe_tones git checkout ambe_tones

View File

@@ -12,13 +12,7 @@ read -p "Have you viewed the patent notice? y/N " ANSWER
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]') ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
if [ "$ANSWER" = "y" ]; then if [ "$ANSWER" = "y" ]; then
sudo apt update sudo apt update
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncursesw5-dev libcodec2-dev
chkitpp=$(dpkg -l libitpp-dev 2>/dev/null | awk '/^ii/ {print 1} END {if (NR == 0) print 0}')
if [ "$chkitpp" -lt "1" ];then
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
read -p "Press Enter to exit..." x
exit 1
fi
git clone https://github.com/lwvmobile/mbelib git clone https://github.com/lwvmobile/mbelib
cd mbelib cd mbelib
git checkout ambe_tones git checkout ambe_tones

View File

@@ -43,9 +43,9 @@ Debian/Mint/Ubuntu/Pi
``` ```
sudo apt update sudo apt update
#Ubuntu 22.04 lts / Debian 11 and lower #Ubuntu 22.04 lts / Debian 11 and lower
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libcodec2-dev sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libcodec2-dev
#Ubuntu 24.04 lts / Debian 12 #Ubuntu 24.04 lts / Debian 12
#sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncurses-dev libncurses6 libcodec2-dev #sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncurses-dev libncurses6 libcodec2-dev
``` ```
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99 Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
@@ -60,8 +60,6 @@ Arch -- https://github.com/lwvmobile/dsd-fme/issues/153 and https://github.com/l
``` ```
sudo pacman -Syu sudo pacman -Syu
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
``` ```
## Headless Ubuntu Server/Pi ## Headless Ubuntu Server/Pi
@@ -69,24 +67,7 @@ sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately. If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
``` ```
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev pulsemixer pulseaudio libcodec2-dev sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncursesw5-dev pulsemixer pulseaudio libcodec2-dev
```
### Build and Install ITPP - ONLY IF NOT IN REPO!!
```
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
tar xjf itpp*
#if you can't cd into this folder, double check folder name first
cd itpp-4.3.1
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
cd ..
cd ..
``` ```
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice") MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice")
@@ -135,7 +116,7 @@ Open Windows PowerShell (not Command Prompt) and copy and paste all of this in a
``` ```
Invoke-WebRequest https://cygwin.com/setup-x86_64.exe -OutFile setup-x86_64.exe Invoke-WebRequest https://cygwin.com/setup-x86_64.exe -OutFile setup-x86_64.exe
.\setup-x86_64.exe --packages nano,libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,zip,unzip,wget,gcc-g++,libsndfile-devel,libopenblas,liblapack-devel,libfftw3-devel .\setup-x86_64.exe --packages nano,libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,zip,unzip,wget,gcc-g++,libsndfile-devel
``` ```

View File

@@ -7,8 +7,6 @@
* *
* Code adapted from http://www.aqdi.com/golay.htm * Code adapted from http://www.aqdi.com/golay.htm
* *
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
* expected from the P25 transmissions that I have tested. This implementation does work.
*/ */
#include <stdio.h> #include <stdio.h>

View File

@@ -5,9 +5,6 @@
/** /**
* Code taken and adapted from www.eccpage.com/rs.c * Code taken and adapted from www.eccpage.com/rs.c
* Credit goes to Mr Simon Rockliff. * Credit goes to Mr Simon Rockliff.
*
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
* expected from the P25 transmissions that I have tested. This implementation does work.
*/ */
/* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in /* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in

View File

@@ -59,8 +59,9 @@
#include "p25p1_heuristics.h" #include "p25p1_heuristics.h"
//OSS support //OSS support
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)
#include <sys/soundcard.h> #include <sys/soundcard.h>
#endif
#include <pulse/pulseaudio.h> //PULSE AUDIO #include <pulse/pulseaudio.h> //PULSE AUDIO
#include <pulse/simple.h> //PULSE AUDIO #include <pulse/simple.h> //PULSE AUDIO
#include <pulse/error.h> //PULSE AUDIO #include <pulse/error.h> //PULSE AUDIO
@@ -1643,6 +1644,7 @@ unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len);
void hytera_enhanced_alg_refresh(dsd_state * state); void hytera_enhanced_alg_refresh(dsd_state * state);
//LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES //LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES
void lfsr_64_to_128(uint8_t * iv);
void LFSR128(dsd_state * state); void LFSR128(dsd_state * state);
void LFSR128n(dsd_state * state); void LFSR128n(dsd_state * state);
void LFSR128d(dsd_state * state); void LFSR128d(dsd_state * state);
@@ -1669,6 +1671,9 @@ int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
int isch_lookup (uint64_t isch); //isch map lookup int isch_lookup (uint64_t isch); //isch map lookup
//Phase 1 NID Check
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,26 +0,0 @@
#ifndef P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
#define P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
#ifdef __cplusplus
extern "C" {
#endif
/**
* Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID.
* \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID. This includes the
* NAC (12 bits), DUID (4 bits) and 47 bits of BCH parity.
* \param new_nac Output. An address where to store the calculated NAC value after error correction. Should
* be large enough to accommodate for an integer.
* \param new_duid Output. An address where to store the calculated DUID value after error correction. Should
* be able to accommodate 3 chars.
* \param parity Input. The parity value read.
* \return 0 if there were errors processing the NID.
*/
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
#ifdef __cplusplus
}
#endif
#endif // P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a

View File

@@ -6,7 +6,6 @@
, ncurses , ncurses
, pulseaudio , pulseaudio
, rtl-sdr , rtl-sdr
, itpp
, codec2 , codec2
, portaudioSupport ? true , portaudioSupport ? true
, portaudio ? null , portaudio ? null
@@ -23,7 +22,6 @@ stdenv.mkDerivation {
buildInputs = [ buildInputs = [
mbelib mbelib
libsndfile libsndfile
itpp
rtl-sdr rtl-sdr
ncurses.dev ncurses.dev
pulseaudio.dev pulseaudio.dev
@@ -39,7 +37,7 @@ stdenv.mkDerivation {
tap audio and synthesize the decoded speech. Speech synthesis requires tap audio and synthesize the decoded speech. Speech synthesis requires
mbelib, which is a separate package. mbelib, which is a separate package.
''; '';
homepage = "https://github.com/szechyjs/dsd"; homepage = "https://github.com/lwvmobile/dsd-fme";
license = licenses.mit; license = licenses.mit;
platforms = platforms.unix; platforms = platforms.unix;
}; };

View File

@@ -189,6 +189,14 @@ void parse_pulse_output_string (dsd_opts * opts, char * input)
} }
} }
#ifdef __APPLE__
// macOS does not support OSS (/dev/dsp).
// Provide a stub so callers can link while using Pulse/CoreAudio backends.
void openOSSOutput(dsd_opts *opts)
{
(void)opts;
}
#else
void openOSSOutput (dsd_opts * opts) void openOSSOutput (dsd_opts * opts)
{ {
int fmt; int fmt;
@@ -207,6 +215,7 @@ void openOSSOutput (dsd_opts * opts)
exit(1); exit(1);
} }
fmt = 0; fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0) if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
{ {
@@ -303,6 +312,7 @@ void openOSSOutput (dsd_opts * opts)
} }
} }
} }
#endif
void void
processAudio (dsd_opts * opts, dsd_state * state) processAudio (dsd_opts * opts, dsd_state * state)

View File

@@ -18,6 +18,7 @@
#include "dsd.h" #include "dsd.h"
#include "p25p1_const.h" //for imbe fr (7200) #include "p25p1_const.h" //for imbe fr (7200)
#include "dmr_const.h" //for ambe+2 fr #include "dmr_const.h" //for ambe+2 fr
#include "bp.h" //for bp key table
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d) void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
{ {
@@ -928,9 +929,12 @@ uint16_t parse_raw_user_string (char * input, uint8_t * output)
return len; return len;
} }
//DMRA late entry items
static int ambe2_counter;
static int dmra_le;
uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str, uint8_t * ks, uint16_t ks_idx, uint8_t dmra, uint8_t is_enc, uint8_t ks_available) uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str, uint8_t * ks, uint16_t ks_idx, uint8_t dmra, uint8_t is_enc, uint8_t ks_available)
{ {
UNUSED(opts);
char ambe_fr[4][24]; memset (ambe_fr, 0, sizeof(ambe_fr)); char ambe_fr[4][24]; memset (ambe_fr, 0, sizeof(ambe_fr));
uint8_t dibit_pair = 0; uint8_t dibit_pair = 0;
@@ -976,6 +980,39 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
} }
//if using DMRA Late Entry IV mechanics, evaluate for IV
if (dmra_le)
{
//make a copy of ambe_fr codeword 3 (MI fragment)
uint8_t c3[24]; memset (c3, 0, sizeof(c3));
for (int i = 0; i < 24; i++)
c3[i] = ambe_fr[3][i];
//force slot to 0
state->currentslot = 0;
uint8_t c3_hex = (uint64_t)ConvertBitIntoBytes(c3, 4);
//debug
// fprintf (stderr, "\n AMBE#: %02d / %d / %d; F: %X;", ambe2_counter, ambe2_counter/3, ambe2_counter%3, c3_hex);
//use div and mod 3 to set current storage fragment
state->late_entry_mi_fragment[0][(ambe2_counter/3)+1][ambe2_counter%3] = c3_hex;
//run LFSR evaluate stored codewords for matching IV or replace if not match or not set
if (ambe2_counter == 17)
{
if (state->payload_mi != 0)
{
fprintf (stderr, "\n");
LFSR(state);
}
fprintf (stderr, "\n");
dmr_late_entry_mi (opts, state);
}
}
char ambe_d[49]; memset(ambe_d, 0, sizeof(ambe_d)); char ambe_d[49]; memset(ambe_d, 0, sizeof(ambe_d));
state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr); state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr);
state->errs2 = state->errs; state->errs2 = state->errs;
@@ -1052,7 +1089,6 @@ uint16_t ambe2_str_to_decode(dsd_opts * opts, dsd_state * state, char * ambe_str
uint16_t imbe_str_to_decode(dsd_opts * opts, dsd_state * state, char * imbe_str, uint8_t * ks, uint16_t ks_idx, uint8_t is_enc, uint8_t ks_available) uint16_t imbe_str_to_decode(dsd_opts * opts, dsd_state * state, char * imbe_str, uint8_t * ks, uint16_t ks_idx, uint8_t is_enc, uint8_t ks_available)
{ {
UNUSED(opts);
char imbe_fr[8][23]; memset (imbe_fr, 0, sizeof(imbe_fr)); char imbe_fr[8][23]; memset (imbe_fr, 0, sizeof(imbe_fr));
uint8_t dibit_pair = 0; uint8_t dibit_pair = 0;
@@ -1199,6 +1235,16 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
state->synctype = -1; state->synctype = -1;
state->lastsynctype = -1; state->lastsynctype = -1;
//reset encryption variables
state->payload_mi = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
if (state->keyloader == 1)
{
state->R = 0;
state->aes_key_loaded[0] = 0;
}
//watchdog for event history //watchdog for event history
watchdog_event_history(opts, state, 0); watchdog_event_history(opts, state, 0);
watchdog_event_current(opts, state, 0); watchdog_event_current(opts, state, 0);
@@ -1210,6 +1256,12 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
uint8_t ks_i[3000]; memset (ks_i, 0, sizeof(ks_i)); uint8_t ks_i[3000]; memset (ks_i, 0, sizeof(ks_i));
uint16_t ks_idx_i = 808; //keystream index value IMBE (start at 808 for out of order ESS) uint16_t ks_idx_i = 808; //keystream index value IMBE (start at 808 for out of order ESS)
int imbe_counter = 0; //count IMBE frames for when to skip 2 bytes of ks and juggle keystreams int imbe_counter = 0; //count IMBE frames for when to skip 2 bytes of ks and juggle keystreams
//Used in conjunction with DMR's DMRA Late Entry IV
ambe2_counter = 0; //count AMBE+2 frames for DMRA late entry IV mechanics (static)
dmra_le = 0; //whether or not to attempt looking for the DMRA Late Entry
if (state->forced_alg_id != 0)
state->payload_mi = 0;
source_size = fread (source_str, 1, 0x100000, opts->mbe_in_f); source_size = fread (source_str, 1, 0x100000, opts->mbe_in_f);
@@ -1344,6 +1396,77 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
} }
//if forcing a DMRA EP mode, turn on dmra_le and set alg here
if (state->forced_alg_id >= 0x21 && state->forced_alg_id <= 0x25)
{
is_dmra = 1;
dmra_le = 1;
is_enc = 1;
alg_id = state->forced_alg_id;
state->payload_algid = alg_id;
rc4_db = 256;
rc4_mod = 9;
//since we can't keyring on a forced alg, we can perhaps look it up
//via the TO field for the TG value, as long as it isn't greated than 0x1FFFF (upper bound of the array)
if (state->keyloader == 1 && state->lasttg != 0 && state->lasttg < 0x1FFFF && state->rkey_array[state->lasttg] != 0)
state->R = state->rkey_array[state->lasttg];
if (alg_id == 0x21 && state->R != 0 && state->payload_mi != 0)
{
//test when we don't have an encryption_mi in the .mbe file for DMR
//TODO: Handle multi keystream creation with a new function
uint8_t ks_bytes[375]; memset(ks_bytes, 0, sizeof(ks_bytes));
uint8_t kiv[32]; memset(kiv, 0, sizeof(kiv));
//load key into key portion of kiv
kiv[0] = ((state->R & 0xFF00000000) >> 32);
kiv[1] = ((state->R & 0xFF000000) >> 24);
kiv[2] = ((state->R & 0xFF0000) >> 16);
kiv[3] = ((state->R & 0xFF00) >> 8);
kiv[4] = ((state->R & 0xFF) >> 0);
//load IV from late entry state->payload_mi
kiv[5] = ((state->payload_mi & 0xFF000000) >> 24);
kiv[6] = ((state->payload_mi & 0xFF0000) >> 16);
kiv[7] = ((state->payload_mi & 0xFF00) >> 8);
kiv[8] = ((state->payload_mi & 0xFF) >> 0);
rc4_block_output (rc4_db, rc4_mod, 200, kiv, ks_bytes);
unpack_byte_array_into_bit_array(ks_bytes, ks, 200);
ks_available = 1;
}
}
//TODO: This
else if (state->forced_alg_id == 1) //Basic Privacy
{
//This is where the key loaded comes into play for moto vs hytera vs scrambler
if (state->K != 0)
{
uint64_t k = 0;
k = BPK[state->K];
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
k <<= 1;
k += (k >> 48) & 1;
//load that into ks
for (int i = 0; i < 18*49; i++)
ks[i] = (k >> (i%49)) & 1;
}
else if (state->H != 0)
{
//Hytera BP
}
else if (state->R != 0)
{
//NXDN Scrambler
}
}
if (strncmp ("to", str_buffer, 2) == 0) if (strncmp ("to", str_buffer, 2) == 0)
{ {
str_buffer = strtok(NULL, " : \""); //next value after any : "" string str_buffer = strtok(NULL, " : \""); //next value after any : "" string
@@ -1445,9 +1568,9 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
//TODO: Handle multi keystream creation with a new function //TODO: Handle multi keystream creation with a new function
uint8_t ks_bytes[375]; memset(ks_bytes, 0, sizeof(ks_bytes)); uint8_t ks_bytes[375]; memset(ks_bytes, 0, sizeof(ks_bytes));
uint8_t kiv[15]; memset(kiv, 0, sizeof(kiv)); uint8_t kiv[32]; memset(kiv, 0, sizeof(kiv));
//Test: Setup a simple RC4 for now (working) //RC4 (v1 tested and working on P25, v2 should be okay now)
if ( (alg_id == 0xAA || alg_id == 0x21) && state->R != 0 ) if ( (alg_id == 0xAA || alg_id == 0x21) && state->R != 0 )
{ {
@@ -1480,19 +1603,113 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
ks_available = 1; ks_available = 1;
}
} //end test //P25 DES (v1 tested and working on P1, v2 should be okay now)
else if (alg_id == 0x81 && state->R != 0)
{
//NOTE: Regarding SDRTrunk .mbe format, the ESS Encryption Sync des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
//is in the correct location on P25p2, but for P25p1, the ESS
//information preceeds LDU2, but should be AFTER the LDU2 IMBE frames,
//so, for now, we utilize a reverse lfsr function (Crypthings coming in handy)
//and recover the previous LFSR and make two keystreams in order
//to properly decrypt the initial frame, and then juggle the
//keystreams in code to provide a smooth decryption session of P25p1.
//Update: There is a pull request available now, and using a version value, if (protocol == 1) //Phase 1 IMBE start on 19 for DES-OFB (8 discard + 9 LCW + 2 reserved)
//we will be able to do either format (ESS out of order vs ESS in correct order) unpack_byte_array_into_bit_array(ks_bytes+19, ks, 256-19); //unpack starting after discard
else if (protocol == 2) //Phase 2 AMBE+2 start on 8 after discard round for DES-OFB
unpack_byte_array_into_bit_array(ks_bytes+8, ks, 256-8); //unpack starting after discard
//reverse lfsr on IV and create keystream with that as well
//due to out of order execution on P25p1 ESS sync.
if (protocol == 1 && version == 1)
{
//load the str_buffer into the IV portion of kiv (just borrowing for DES)
parse_raw_user_string(str_buffer, kiv+5);
reverse_lfsr_64_to_len (opts, kiv+5, 64);
//convert bytes back into value
iv_hex = 0;
for (int i = 0; i < 8; i++)
{
iv_hex <<= 8;
iv_hex |= kiv[i+5];
}
memset(ks_bytes, 0, sizeof(ks_bytes));
des_multi_keystream_output(iv_hex, state->R, ks_bytes, 1, 32); //32*8=256
unpack_byte_array_into_bit_array(ks_bytes+19, ks_i, 256-19); //unpack starting after discard
}
ks_available = 1;
}
//P25 AES (v1 and v2 tested working on P1)
else if ( (alg_id == 0x84 || alg_id == 0x89) && state->aes_key_loaded[0] == 1 )
{
uint8_t aes_key[32];
memset(aes_key, 0, sizeof(aes_key));
//Load key from A1 - A4
for (int i = 0; i < 8; i++)
{
aes_key[i+0] = (state->A1[0] >> (56-(i*8))) & 0xFF;
aes_key[i+8] = (state->A2[0] >> (56-(i*8))) & 0xFF;
aes_key[i+16] = (state->A3[0] >> (56-(i*8))) & 0xFF;
aes_key[i+24] = (state->A4[0] >> (56-(i*8))) & 0xFF;
}
uint8_t aes_iv[16];
memset(aes_iv, 0, sizeof(aes_iv));
//load the str_buffer into the IV portion of aes_iv
parse_raw_user_string(str_buffer, aes_iv);
//backup copy of current IV to reverse and expand, if needed
uint8_t aes_last_iv[16];
memset(aes_last_iv, 0, sizeof(aes_last_iv));
for (int i = 0; i < 8; i++)
aes_last_iv[i] = aes_iv[i];
//Resolve the longer IV from the shorter one
lfsr_64_to_128(aes_iv);
if (alg_id == 0x89) //128, or 256
aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 0, 16); //16*16=256
else aes_ofb_keystream_output(aes_iv, aes_key, ks_bytes, 2, 16); //16*16=256
if (protocol == 1) //Phase 1 IMBE start on 27 for AES-OFB (16 discard + 9 LCW + 2 reserved)
unpack_byte_array_into_bit_array(ks_bytes+27, ks, 256-27); //unpack starting after discard
else if (protocol == 2) //Phase 2 AMBE+2 start on 16 after discard round for AES-OFB
unpack_byte_array_into_bit_array(ks_bytes+16, ks, 256-16); //unpack starting after discard
//reverse lfsr on IV and create keystream with that as well
//due to out of order execution on P25p1 ESS sync.
if (protocol == 1 && version == 1)
{
reverse_lfsr_64_to_len (opts, aes_last_iv, 64);
//Resolve the longer IV from the shorter one
lfsr_64_to_128(aes_last_iv);
memset(ks_bytes, 0, sizeof(ks_bytes));
if (alg_id == 0x89) //128, or 256
aes_ofb_keystream_output(aes_last_iv, aes_key, ks_bytes, 0, 16); //16*16=256
else aes_ofb_keystream_output(aes_last_iv, aes_key, ks_bytes, 2, 16); //16*16=256
unpack_byte_array_into_bit_array(ks_bytes+27, ks_i, 256-27); //unpack starting after discard
}
ks_available = 1;
}
//Pull request: https://github.com/DSheirer/sdrtrunk/pull/2273
//Merged into SDRTrunk nightly so should be able to handle this better now
//reset ks_idx to 0 //reset ks_idx to 0
ks_idx = 0; ks_idx = 0;
@@ -1516,6 +1733,9 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
imbe_counter++; imbe_counter++;
//debug
// fprintf (stderr, "\n IMBE# %02d; KS_IDX: %d; KS_IDX_I: %d; ", imbe_counter, ks_idx, ks_idx_i);
//36 hex characters on 'hex' which is the IMBE interleaved C codewords //36 hex characters on 'hex' which is the IMBE interleaved C codewords
if (version == 1) if (version == 1)
ks_idx_i = imbe_str_to_decode(opts, state, str_buffer, ks_i, ks_idx_i, is_enc, ks_available); ks_idx_i = imbe_str_to_decode(opts, state, str_buffer, ks_i, ks_idx_i, is_enc, ks_available);
@@ -1523,7 +1743,10 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
//skip LSD bits in-between these two IMBE voice frames //skip LSD bits in-between these two IMBE voice frames
if (imbe_counter == 8 || imbe_counter == 17) if (imbe_counter == 8 || imbe_counter == 17)
{
ks_idx_i += 16; ks_idx_i += 16;
ks_idx += 16;
}
//juggle keystreams and reset the I counter (if version 1) //juggle keystreams and reset the I counter (if version 1)
if (imbe_counter == 9 && version == 1) if (imbe_counter == 9 && version == 1)
@@ -1544,7 +1767,7 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
} }
//debug //debug
// fprintf (stderr, " # %02d; KS_IDX_I: %04d;", imbe_counter, ks_idx_i); // fprintf (stderr, "\n IMBE# %02d; KS_IDX: %d; KS_IDX_I: %d; ", imbe_counter, ks_idx, ks_idx_i);
//debug //debug
// if (is_enc == 1 && ks_available == 0) // if (is_enc == 1 && ks_available == 0)
@@ -1567,6 +1790,16 @@ void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state)
// else if (is_enc == 1 && ks_available == 1) // else if (is_enc == 1 && ks_available == 1)
// fprintf (stderr, " Enc Play;"); // fprintf (stderr, " Enc Play;");
//increment AMBE+2 counter
ambe2_counter++;
//reset if over for DMR 18 AMBE+2 frames
if (dmra_le && ambe2_counter == 18)
{
ambe2_counter = 0;
ks_idx = 0;
}
} }
} }

View File

@@ -20,8 +20,6 @@
#define NULL 0 #define NULL 0
#endif #endif
#include "p25p1_check_nid.h"
void void
printFrameInfo (dsd_opts * opts, dsd_state * state) printFrameInfo (dsd_opts * opts, dsd_state * state)
{ {

View File

@@ -3392,18 +3392,23 @@
//to a variable config, it cannot be the input as well //to a variable config, it cannot be the input as well
#ifndef __APPLE__
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0)) if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
{ {
sprintf (opts.audio_in_dev, "%s", "/dev/dsp"); sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
fprintf (stderr, "Switching to /dev/dsp.\n"); fprintf (stderr, "Switching to /dev/dsp.\n");
} }
#endif
#ifndef __APPLE__
if((strncmp(opts.audio_in_dev, "pa", 2) == 0)) if((strncmp(opts.audio_in_dev, "pa", 2) == 0))
{ {
sprintf (opts.audio_in_dev, "%s", "/dev/dsp"); sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
fprintf (stderr, "Switching to /dev/dsp.\n"); fprintf (stderr, "Switching to /dev/dsp.\n");
} }
#endif
#ifndef __APPLE__
speed = 48000; //hardset to 48000 speed = 48000; //hardset to 48000
if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0)) if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0))
{ {
@@ -3437,24 +3442,31 @@
opts.audio_in_type = 5; //5 will become OSS input type opts.audio_in_type = 5; //5 will become OSS input type
} }
#endif
//check for OSS output //check for OSS output
#ifndef __APPLE__
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0)) if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
{ {
sprintf (opts.audio_out_dev, "%s", "/dev/dsp"); sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
fprintf (stderr, "Switching to /dev/dsp.\n"); fprintf (stderr, "Switching to /dev/dsp.\n");
} }
#endif
#ifndef __APPLE__
if((strncmp(opts.audio_out_dev, "pa", 2) == 0)) if((strncmp(opts.audio_out_dev, "pa", 2) == 0))
{ {
sprintf (opts.audio_out_dev, "%s", "/dev/dsp"); sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
fprintf (stderr, "Switching to /dev/dsp.\n"); fprintf (stderr, "Switching to /dev/dsp.\n");
} }
#endif
//this will only open OSS output if its listed as a type //this will only open OSS output if its listed as a type
//changed to this so I could call it freely inside of ncurses terminal //changed to this so I could call it freely inside of ncurses terminal
#ifndef __APPLE__
if (opts.playfiles == 0) if (opts.playfiles == 0)
openOSSOutput(&opts); openOSSOutput(&opts);
#endif
if (opts.playfiles == 1) if (opts.playfiles == 1)
{ {
@@ -3466,8 +3478,10 @@
opts.pulse_digi_out_channels = 1; opts.pulse_digi_out_channels = 1;
if (opts.audio_out_type == 0) if (opts.audio_out_type == 0)
openPulseOutput(&opts); openPulseOutput(&opts);
#ifndef __APPLE__
else if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0)) else if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0))
openOSSOutput(&opts); //open after split == 1 so it will open and playback at the proper speed openOSSOutput(&opts); //open after split == 1 so it will open and playback at the proper speed
#endif
} }
//this particular if-elseif-else could be rewritten to be a lot neater and simpler //this particular if-elseif-else could be rewritten to be a lot neater and simpler

View File

@@ -130,11 +130,13 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
closePulseOutput (opts); closePulseOutput (opts);
} }
#ifndef __APPLE__
//close OSS output //close OSS output
if (opts->audio_out_type == 2 || opts->audio_out_type == 5) if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
{ {
close (opts->audio_out_fd); close (opts->audio_out_fd);
} }
#endif
if (opts->audio_in_type == 0) //close pulse input if it is the specified input method if (opts->audio_in_type == 0) //close pulse input if it is the specified input method
{ {
@@ -1585,10 +1587,12 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
openPulseOutput (opts); openPulseOutput (opts);
} }
#ifndef __APPLE__
if (opts->audio_out_type == 2 || opts->audio_out_type == 5) if (opts->audio_out_type == 2 || opts->audio_out_type == 5)
{ {
openOSSOutput (opts); openOSSOutput (opts);
} }
#endif
if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method

View File

@@ -1,17 +1,138 @@
#include <itpp/itcomm.h> // BCH decoder implementation from OP25 (Copyright 2010, KA1RBI, GPL license)
#include "dsd.h"
#include "p25p1_check_nid.h" #include <vector>
typedef std::vector<bool> bit_vector;
static const int bchGFexp[64] = {
1, 2, 4, 8, 16, 32, 3, 6, 12, 24, 48, 35, 5, 10, 20, 40,
19, 38, 15, 30, 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, 51, 37,
9, 18, 36, 11, 22, 44, 27, 54, 47, 29, 58, 55, 45, 25, 50, 39,
13, 26, 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, 57, 49, 33, 0
};
static const int bchGFlog[64] = {
-1, 0, 1, 6, 2, 12, 7, 26, 3, 32, 13, 35, 8, 48, 27, 18,
4, 24, 33, 16, 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, 19, 56,
5, 62, 25, 11, 34, 31, 17, 47, 15, 23, 53, 51, 37, 44, 55, 40,
10, 61, 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, 20, 59, 57, 58
};
using namespace itpp; int bchDec(bit_vector& Codeword)
{
int elp[24][22], S[23];
int D[23], L[24], uLu[24];
int locn[11], reg[12];
int i, j, U, q, count;
int SynError, CantDecode;
// Ideas taken from http://op25.osmocom.org/trac/wiki.png/browser/op25/gr-op25/lib/decoder_ff_impl.cc SynError = 0; CantDecode = 0;
// See also p25_training_guide.pdf page 48.
// See also tia-102-baaa-a-project_25-fdma-common_air_interface.pdf page 40.
// BCH encoder/decoder implementation from IT++. GNU GPL 3 license.
itpp::BCH bch(63, 16, 11, "6 3 3 1 1 4 1 3 6 7 2 3 5 4 5 3", true); for (i = 1; i <= 22; i++) {
S[i] = 0;
for (j = 0; j <= 62; j++) {
if (Codeword[j]) {
S[i] = S[i] ^ bchGFexp[(i * j) % 63];
}
}
if (S[i]) { SynError = 1; }
S[i] = bchGFlog[S[i]];
}
if (SynError) { // if there are errors, try to correct them
L[0] = 0; uLu[0] = -1; D[0] = 0; elp[0][0] = 0;
L[1] = 0; uLu[1] = 0; D[1] = S[1]; elp[1][0] = 1;
for (i = 1; i <= 21; i++) {
elp[0][i] = -1; elp[1][i] = 0;
}
U = 0;
do {
U = U + 1;
if (D[U] == -1) {
L[U + 1] = L[U];
for (i = 0; i <= L[U]; i++) {
elp[U + 1][i] = elp[U][i];
elp[U][i] = bchGFlog[elp[U][i]];
}
} else {
q = U - 1;
while ((D[q] == -1) && (q > 0)) { q = q - 1; }
if (q > 0) {
j = q;
do { j = j - 1; if ((D[j] != -1) && (uLu[q] < uLu[j])) { q = j; }
} while (j > 0);
}
if (L[U] > L[q] + U - q) {
L[U + 1] = L[U];
} else {
L[U + 1] = L[q] + U - q;
}
for (i = 0; i <= 21; i++) {
elp[U + 1][i] = 0;
}
for (i = 0; i <= L[q]; i++) {
if (elp[q][i] != -1) {
elp[U + 1][i + U - q] = bchGFexp[(D[U] + 63 - D[q] + elp[q][i]) % 63];
}
}
for (i = 0; i <= L[U]; i++) {
elp[U + 1][i] = elp[U + 1][i] ^ elp[U][i];
elp[U][i] = bchGFlog[elp[U][i]];
}
}
uLu[U + 1] = U - L[U + 1];
if (U < 22) {
if (S[U + 1] != -1) { D[U + 1] = bchGFexp[S[U + 1]]; } else { D[U + 1] = 0; }
for (i = 1; i <= L[U + 1]; i++) {
if ((S[U + 1 - i] != -1) && (elp[U + 1][i] != 0)) {
D[U + 1] = D[U + 1] ^ bchGFexp[(S[U + 1 - i] + bchGFlog[elp[U + 1][i]]) % 63];
}
}
D[U + 1] = bchGFlog[D[U + 1]];
}
} while ((U < 22) && (L[U + 1] <= 11));
U = U + 1;
if (L[U] <= 11) {
for (i = 0; i <= L[U]; i++) {
elp[U][i] = bchGFlog[elp[U][i]];
}
for (i = 1; i <= L[U]; i++) {
reg[i] = elp[U][i];
}
count = 0;
for (i = 1; i <= 63; i++) {
q = 1;
for (j = 1; j <= L[U]; j++) {
if (reg[j] != -1) {
reg[j] = (reg[j] + j) % 63;
q = q ^ bchGFexp[reg[j]];
}
}
if (q == 0) {
locn[count] = 63 - i;
count = count + 1;
}
}
if (count == L[U]) {
for (i = 0; i <= L[U] - 1; i++) {
Codeword[locn[i]] = Codeword[locn[i]] ^ 1;
}
CantDecode = count;
} else {
CantDecode = -1;
}
} else {
CantDecode = -2;
}
}
return CantDecode;
}
/** /**
* Convenience class to calculate the parity of the DUID values. Keeps a table with the expected outcomes * Convenience class to calculate the parity of the DUID values. Keeps a table with the expected outcomes
@@ -24,13 +145,13 @@ private:
unsigned char get_index(unsigned char x, unsigned char y) unsigned char get_index(unsigned char x, unsigned char y)
{ {
return (x<<2) + y; return (x << 2) + y;
} }
public: public:
ParityTable() ParityTable()
{ {
for (unsigned int i=0; i<sizeof(table); i++) { for (unsigned int i = 0; i < sizeof(table); i++) {
table[i] = 0; table[i] = 0;
} }
table[get_index(1,1)] = 1; table[get_index(1,1)] = 1;
@@ -39,9 +160,8 @@ public:
unsigned char get_value(unsigned char x, unsigned char y) unsigned char get_value(unsigned char x, unsigned char y)
{ {
return table[get_index(x,y)]; return table[get_index(x, y)];
} }
} parity_table; } parity_table;
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity) int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity)
@@ -49,31 +169,38 @@ int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity
int result; int result;
// Fill up with the given input // Fill up with the given input
bvec input(63); bit_vector codeword(63);
for(unsigned int i=0; i<63; i++) { for (unsigned int i = 0; i < 63; i++) {
input[i] = bch_code[i]; codeword[i] = bch_code[62-i];
} }
// Decode it // Decode it
bvec decoded, cw_isvalid; int errors = bchDec(codeword);
bool ok = bch.decode(input, decoded, cw_isvalid); bool ok = (errors >= 0);
if (!ok) { if (!ok) {
// Decode failed // Decode failed
// fprintf (stderr, "NID ERR: %d; ", errors);
result = 0; result = 0;
} else { } else {
//reload the codeword back into correct bit order
for (unsigned int i = 0; i < 63; i++) {
bch_code[i] = codeword[62-i];
}
for (unsigned int i = 0; i < 63; i++) {
codeword[i] = bch_code[i];
}
// Take the NAC from the decoded output. It's a 12 bit number starting from position 0. // Take the NAC from the decoded output. It's a 12 bit number starting from position 0.
// Just convert the output from a binary sequence to an integer.
int nac = 0; int nac = 0;
for (int i=0; i<12; i++) { for (int i = 0; i < 12; i++) {
nac <<= 1; nac <<= 1;
nac |= (int)decoded[i]; nac |= (int)codeword[i];
} }
*new_nac = nac; *new_nac = nac;
// Take the fixed DUID from the encoded output. 4 bit value starting at position 12. // Take the fixed DUID from the encoded output. 4 bit value starting at position 12.
unsigned char new_duid_0 = (((int)decoded[12])<<1) + ((int)decoded[13]); unsigned char new_duid_0 = (((int)codeword[12]) << 1) + ((int)codeword[13]);
unsigned char new_duid_1 = (((int)decoded[14])<<1) + ((int)decoded[15]); unsigned char new_duid_1 = (((int)codeword[14]) << 1) + ((int)codeword[15]);
new_duid[0] = new_duid_0 + '0'; new_duid[0] = new_duid_0 + '0';
new_duid[1] = new_duid_1 + '0'; new_duid[1] = new_duid_1 + '0';
new_duid[2] = 0; // Null terminate new_duid[2] = 0; // Null terminate
@@ -82,12 +209,12 @@ int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity
unsigned char expected_parity = parity_table.get_value(new_duid_0, new_duid_1); unsigned char expected_parity = parity_table.get_value(new_duid_0, new_duid_1);
if (expected_parity != parity) { if (expected_parity != parity) {
// Ignore, not sure what to do // Parity mismatch – optional handling
//fprintf (stderr, "Error in parity detected?"); // fprintf(stderr, "Error in parity detected?\n");
} }
result = 1; result = 1;
} }
return result; return result;
} }