mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57629cefe4 | ||
|
|
fe3a135a92 | ||
|
|
8d33c2b3d1 | ||
|
|
593ffbbd66 | ||
|
|
592d57ad87 | ||
|
|
9a31678d9a | ||
|
|
7b3a257df8 | ||
|
|
55e792a925 | ||
|
|
755f77f96c | ||
|
|
1c17757a4e | ||
|
|
abe2e61cf2 | ||
|
|
c404825451 | ||
|
|
769168da5b | ||
|
|
14284c3cf1 | ||
|
|
51f971b68d | ||
|
|
02fdb7cd90 | ||
|
|
64541a1958 | ||
|
|
0a675d3f0f | ||
|
|
e79b6fd231 | ||
|
|
d356ed0dbc | ||
|
|
495eb71090 | ||
|
|
6bf96f1df5 | ||
|
|
3a2db53c3b | ||
|
|
e038016c30 | ||
|
|
7d6269efad | ||
|
|
152f0ea7f6 | ||
|
|
13443a25f3 | ||
|
|
528f7294d9 | ||
|
|
83e3fa1061 | ||
|
|
9b3a2d96e3 | ||
|
|
0829cdbdb0 | ||
|
|
9541aef382 | ||
|
|
4caf6bb153 | ||
|
|
dd77273218 | ||
|
|
3bd3edb36f | ||
|
|
6f1cf0a279 | ||
|
|
5d045b89e4 | ||
|
|
a2c4679632 | ||
|
|
986ed27d7d | ||
|
|
bae6a1545e | ||
|
|
5240f00441 | ||
|
|
f7511e0976 | ||
|
|
bc27344b04 | ||
|
|
db97eb82a1 | ||
|
|
3f1b8ff736 | ||
|
|
54b9017146 | ||
|
|
8ccaf2d261 | ||
|
|
209770175d | ||
|
|
602079e681 | ||
|
|
82267b9ec8 | ||
|
|
87bf997b6e | ||
|
|
0a43d3202d | ||
|
|
ee04cef6f2 | ||
|
|
b6fdfe48c1 | ||
|
|
7a4bd2833f | ||
|
|
432ad448ba | ||
|
|
61be710bb0 | ||
|
|
3be8aacf77 | ||
|
|
4feb21cf0a | ||
|
|
7d8162ab99 | ||
|
|
8e230a08b5 | ||
|
|
dfc4f6f304 | ||
|
|
5a3061f942 | ||
|
|
b40281fda3 | ||
|
|
966fbf8c6a | ||
|
|
ca65f1b209 | ||
|
|
a5d73f06d2 | ||
|
|
56b0e8440e | ||
|
|
b6a12b6ceb | ||
|
|
15a12acfd3 | ||
|
|
c534e0f1fe | ||
|
|
5e68580fa6 | ||
|
|
e6d83e7305 | ||
|
|
d56cf106b4 | ||
|
|
4279ccf292 | ||
|
|
846b202192 | ||
|
|
330ebe2bf3 | ||
|
|
79b4a5e720 | ||
|
|
8186b62a91 | ||
|
|
20f0c852aa | ||
|
|
9e4ae23c0b | ||
|
|
585f6f2fa5 | ||
|
|
a4fba3b19c | ||
|
|
a2180eb5d3 | ||
|
|
514161fefa | ||
|
|
bba059f35f | ||
|
|
5977f865e3 | ||
|
|
ade7c0477f | ||
|
|
a2fded8340 | ||
|
|
005e15c45f | ||
|
|
e9962a8923 | ||
|
|
c6611eae9c | ||
|
|
261193959c | ||
|
|
e7a71eabb6 | ||
|
|
afba84e584 | ||
|
|
96faff7711 | ||
|
|
94166b493c | ||
|
|
6a0b1b2dcf | ||
|
|
5c8e3d95a7 | ||
|
|
4c91588af6 | ||
|
|
35c05654a5 | ||
|
|
fbc9b5fab8 | ||
|
|
1126ab6578 | ||
|
|
0842613b24 | ||
|
|
bf4a4b574c | ||
|
|
380657679e | ||
|
|
0a214af29b | ||
|
|
b008122149 | ||
|
|
7b6feb9e4f | ||
|
|
e4861bf94c | ||
|
|
587a3f01a2 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ build
|
||||
examples
|
||||
*.bin
|
||||
*.ans
|
||||
*.patch
|
||||
@@ -3,7 +3,7 @@
|
||||
#Arch currently on 3.26.3
|
||||
#Cygwin currently using 3.23.2 (or newer)
|
||||
cmake_minimum_required(VERSION 3.10.2)
|
||||
project(dsd-fme-zdev)
|
||||
project(dsd-fme)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
#Set curses to ncurses, and wide true for ascii
|
||||
@@ -31,12 +31,6 @@ if (PVC)
|
||||
add_definitions(-DPVCONVENTIONAL)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DNXDN=ON to enable new NXDN Sync Pattern Testing
|
||||
option(NXDN
|
||||
"Build with new NXDN Sync Pattern Testing Enabled" OFF)
|
||||
if (NXDN)
|
||||
add_definitions(-DNXDNTESTSYNC)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
|
||||
option(LZ
|
||||
@@ -45,6 +39,13 @@ if (LZ)
|
||||
add_definitions(-DLIMAZULUTWEAKS)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DTONES to change default location of the tones.wav files (lwvmobile precompiled 'Aero' releases only)
|
||||
option(TN
|
||||
"Build with tone wav files in the dsd-fme folder and not in /usr/share/" OFF)
|
||||
if (TN)
|
||||
add_definitions(-DTONES)
|
||||
endif ()
|
||||
|
||||
include(git_revision)
|
||||
git_describe(GIT_TAG)
|
||||
|
||||
@@ -54,6 +55,7 @@ find_package(ITPP REQUIRED)
|
||||
find_package(RTLSDR)
|
||||
find_package(Curses REQUIRED)
|
||||
find_package(PulseAudio REQUIRED)
|
||||
find_package(CODEC2)
|
||||
|
||||
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})
|
||||
@@ -65,6 +67,12 @@ if(RTLSDR_FOUND)
|
||||
add_definitions(-DUSE_RTLSDR)
|
||||
endif(RTLSDR_FOUND)
|
||||
|
||||
if(CODEC2_FOUND)
|
||||
include_directories(SYSTEM ${CODEC2_INCLUDE_DIRS})
|
||||
list(APPEND LIBS ${CODEC2_LIBRARIES})
|
||||
add_definitions(-DUSE_CODEC2)
|
||||
endif(CODEC2_FOUND)
|
||||
|
||||
FILE(GLOB SRCS src/*.c src/*.cpp)
|
||||
FILE(GLOB HEADERS include/*.h include/*.hpp)
|
||||
|
||||
@@ -77,24 +85,24 @@ list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c")
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
ADD_EXECUTABLE(dsd-fme-zdev ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme-zdev ${LIBS})
|
||||
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS dsd-fme-zdev DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# man page
|
||||
find_program(HELP2MAN_FOUND help2man)
|
||||
if (HELP2MAN_FOUND)
|
||||
add_custom_command(TARGET dsd-fme-zdev POST_BUILD
|
||||
add_custom_command(TARGET dsd-fme POST_BUILD
|
||||
COMMAND help2man
|
||||
ARGS -n "Digital Speech Decoder"
|
||||
--version-string=${GIT_TAG}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-zdev.1
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1
|
||||
--no-info
|
||||
$<TARGET_FILE:dsd-fme-zdev>
|
||||
$<TARGET_FILE:dsd-fme>
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-zdev.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
|
||||
18
README.md
18
README.md
@@ -1,8 +1,18 @@
|
||||
## Notice
|
||||
|
||||
This branch is for development and experimentation. Results are not gauranteed to be stable.
|
||||
This branch will also attempt to consolidate the code bases for 'Main' and 'Aero' into one codeset
|
||||
with the differences needed for Aero (Cygwin) handled by cmake option `cmake -DAERO=ON ..` when building.
|
||||
# Digital Speech Decoder - Florida Man Edition
|
||||
|
||||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
||||
|
||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thank you everybody.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Information
|
||||
|
||||
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/main/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/main/examples/trunking.sh "trunking examples").
|
||||
|
||||
## License
|
||||
Copyright (C) 2010 DSD Author
|
||||
|
||||
31
cmake/FindCODEC2.cmake
Normal file
31
cmake/FindCODEC2.cmake
Normal file
@@ -0,0 +1,31 @@
|
||||
# - Try to find CODEC2
|
||||
# Once done this will define
|
||||
|
||||
#Seems to work on Cygwin as well now -- more testing for may be required
|
||||
# Not sure what causes the 'Package 'codec2', required by 'virtual:world', not found' message, but seems to work anyways
|
||||
# -- Checking for module 'codec2'
|
||||
# -- Package 'codec2', required by 'virtual:world', not found
|
||||
# -- Found CODEC2: /usr/local/lib/libcodec2.dll.a
|
||||
|
||||
if (NOT CODEC2_FOUND)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(CODEC2_PKG codec2)
|
||||
set(CODEC2_DEFINITIONS ${PC_CODEC2_CFLAGS_OTHER})
|
||||
|
||||
find_path(CODEC2_INCLUDE_DIR
|
||||
NAMES codec2/codec2.h codec2.h
|
||||
HINTS ${CODEC2_PKG_INCLUDE_DIRS})
|
||||
|
||||
find_library(CODEC2_LIBRARY
|
||||
NAMES codec2/codec2 codec2
|
||||
HINTS ${CODEC2_PKG_LIBRARY_DIRS})
|
||||
|
||||
set(CODEC2_LIBRARIES ${CODEC2_LIBRARY})
|
||||
set(CODEC2_INCLUDE_DIRS ${CODEC2_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CODEC2 DEFAULT_MSG CODEC2_LIBRARY CODEC2_INCLUDE_DIR)
|
||||
mark_as_advanced(CODEC2_INCLUDE_DIR CODEC2_LIBRARY)
|
||||
|
||||
endif (NOT CODEC2_FOUND)
|
||||
67
download-and-install-Arch.sh
Normal file
67
download-and-install-Arch.sh
Normal file
@@ -0,0 +1,67 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer For Arch Linux
|
||||
echo This will install the required packages, clone, build, and install DSD-FME only.
|
||||
echo This has been tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal.
|
||||
echo
|
||||
echo MBELib is considered a requirement on this build.
|
||||
echo You must view this notice prior to continuing.
|
||||
echo The Patent Notice can be found at the site below.
|
||||
echo https://github.com/lwvmobile/mbelib#readme
|
||||
echo Please confirm that you have viewed the patent notice by entering y below.
|
||||
echo
|
||||
echo y/N
|
||||
read ANSWER
|
||||
Y='y'
|
||||
if [[ $Y == $ANSWER ]]; 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 -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
|
||||
|
||||
echo Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal
|
||||
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
|
||||
cd mbelib
|
||||
git checkout ambe_tones
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
#sudo cp /usr/local/lib/libmbe.a /usr/lib/libmbe.a
|
||||
sudo cp /usr/local/lib/libmbe.so /usr/lib/libmbe.so #this is the only one we need to copy
|
||||
#sudo cp /usr/local/lib/libmbe.so.1 /usr/lib/libmbe.so.1
|
||||
#sudo cp /usr/local/lib/libmbe.so.1.3 /usr/lib/libmbe.so.1.3
|
||||
cd ..
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
### For branch v2.1b - git clone --branch v2.1b https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
git checkout v2.1b
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
sudo rm -R dsd-fme
|
||||
|
||||
echo Any issues, Please report to either
|
||||
echo https://github.com/lwvmobile/dsd-fme/issues
|
||||
echo https://forums.radioreference.com/threads/dsd-fme.438137/
|
||||
|
||||
else
|
||||
echo
|
||||
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
|
||||
fi
|
||||
23
download-and-install-nodeps.sh
Normal file
23
download-and-install-nodeps.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||
echo This will clone, build, and install DSD-FME only.
|
||||
echo If you need dependencies installed, please run download-and-install.sh instead.
|
||||
echo
|
||||
|
||||
read -p "Press enter to continue"
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
67
download-and-install.sh
Normal file
67
download-and-install.sh
Normal file
@@ -0,0 +1,67 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||
echo MBELib is considered a requirement on this build.
|
||||
echo You must view this notice prior to continuing.
|
||||
echo The Patent Notice can be found at the site below.
|
||||
echo https://github.com/lwvmobile/mbelib#readme
|
||||
echo Please confirm that you have viewed the patent notice by entering y below.
|
||||
echo
|
||||
echo y/N
|
||||
read ANSWER
|
||||
Y='y'
|
||||
if [[ $Y == $ANSWER ]]; then
|
||||
|
||||
sudo apt update
|
||||
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 libncursesw5-dev libcodec2-dev
|
||||
|
||||
echo ITPP Manual Build and Install has been temporarily removed from this script due to issues with older versions of Ubuntu.
|
||||
echo Please check to see that libitpp-dev has successfully been downloaded and installed from the repo.
|
||||
read -p "Press enter to continue"
|
||||
|
||||
#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 ..
|
||||
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
else
|
||||
echo
|
||||
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
|
||||
fi
|
||||
|
||||
|
||||
|
||||
BIN
dsd-fme-qgis-map.qgz
Normal file
BIN
dsd-fme-qgis-map.qgz
Normal file
Binary file not shown.
BIN
dsd-fme2.png
Normal file
BIN
dsd-fme2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
BIN
dsd-fme3.png
Normal file
BIN
dsd-fme3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 251 KiB |
225
examples/Example_Usage.md
Normal file
225
examples/Example_Usage.md
Normal file
@@ -0,0 +1,225 @@
|
||||
### Example Usage and Notes!
|
||||
|
||||
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25. To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
|
||||
|
||||
```
|
||||
-ft XDMA decoder class (P25p1 and p2, YSF, and DMR Stereo)
|
||||
-fs DMR Stereo, also may need to use -xr if inverted DMR
|
||||
-fa Legacy Auto (not recommended)
|
||||
-fi NXDN48
|
||||
-fn NXDN96
|
||||
-fp ProVoice
|
||||
-fm dPMR, also may need to use -xd if inverted dPMR.
|
||||
-fr DMR Mono, also may need to use -xr if inverted DMR.
|
||||
-f1 P25P1
|
||||
-f2 P25P2 (may need to specify wacn/sys/nac manually)
|
||||
-fx X2-TDMA
|
||||
-fy YSF
|
||||
```
|
||||
|
||||
## Conventional Frequency "Fast Scanner"
|
||||
This feature is used to allow DSD-FME to use RIGCTL or RTL input and cycle through frequencies as fast as possible to attain a frame sync.
|
||||
|
||||
This works almost identically to how the trunkng methods work, but instead of locking onto a control channel and tuning based on its decoding, it rapidly tunes through all loaded frequencies in a CSV file and stops when it finds a frame sync. This method is meant for loading a bunch of conventional non-trunking frequencies that signal only when voice or short data bursts are present (DMR T2, Conventional P25 P1, Conventional NXDN, etc) and decode them until the frame sync stops and then resume its scan. This method uses SDR++ RIGCTL, or RTL internal handling to go through signal. -Y is the fast scanner switch.
|
||||
|
||||
To scan through a mixture of DMR and P25 Conventional, use:
|
||||
`dsd-fme -i tcp -C channel_map.csv -G group.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
To scan through NXDN48 only conventional, use:
|
||||
`dsd-fme -fi -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
To scan through NXDN96 only conventional, use:
|
||||
`dsd-fme -fn -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
The Channel Map setup will be identical to any of the channel maps found for trunking systems, channel numbers do not matter and can be arbitrarily organized, and frequencies can be duplicated to be 'scanned' more frequently in larger CSV files. Scan speed by default is 1 second, and is most stable at that speed. This can be adjusted by using the `-t 2` option, for example, to specify 2 seconds of hang time per frequency. ~~If activity occurs on a frequency, an additional 2 seconds of 'hangtime' will occur on that frequency for any follow up voice activity.~~
|
||||
|
||||
Please Note: DMR Simplex may not behave well on fast scan, I have not been able to test it as such, but given the nature of the on-off timeslot signalling on DMR Simplex, missed frame syncs and skipping/resuming scan may occur.
|
||||
|
||||
## Trunking Examples
|
||||
Please see trunking.sh for sample start up scripts or scroll down to the bottom for more explanation.
|
||||
|
||||
## Example Usage - Default Decoder, Ncurses Terminal, Pulse Input/Output, and Log Console to file
|
||||
`dsd-fme -N 2> voice.log`
|
||||
|
||||
and in a second terminal tab, same folder, run
|
||||
|
||||
`tail -n 40 -f voice.log`
|
||||
|
||||
Then you can open up your pavucontrol "Pulse Audio Volume Control" or "Volume Control" application and route input into DSD-FME from any application and DSD-FME output to the left and right speakers respectively. (unlock the channel in the application stream and adjust left and right independently)
|
||||
|
||||
### Input ###
|
||||
|
||||
--TCP Direct Audio Link with SDR++
|
||||
|
||||
`dsd-fme -i tcp` Currently defaults to localhost:7355 (SDR++ defaults)
|
||||
|
||||
`dsd-fme -i tcp:192.168.7.5:7356` (remote host and custom port)
|
||||
|
||||
--48000/9600 Mono Wav File Input
|
||||
|
||||
`dsd-fme -i filename.wav` 48k/1 Audio (SDR++, GQRX wav recordings)
|
||||
|
||||
`dsd-fme -i filename.wav -s 96000` 96k/1 (DSDPlus Raw Signal Wav Files)
|
||||
|
||||
Wav File Input Note: Due to 96000 rate audio requiring me to double the symbol rate and center, be sure to use the -s 96000 at the very end of the startup command. Also, some NXDN48/96 may have difficulties decoding properly with wav file input.
|
||||
|
||||
## Example Usage - RTL2832 Dongle Input
|
||||
Short Setup (all default values):
|
||||
|
||||
`dsd-fme -i rtl`
|
||||
|
||||
Detailed Setup:
|
||||
|
||||
`dsd-fme -ft -i rtl:0:154.9875M:26:-2:8:0:6020 `
|
||||
|
||||
```
|
||||
RTL-SDR options:
|
||||
Usage: rtl:dev:freq:gain:ppm:bw:sq:udp
|
||||
NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended
|
||||
dev <num> RTL-SDR Device Index Number
|
||||
freq <num> RTL-SDR Frequency (851800000 or 851.8M)
|
||||
gain <num> RTL-SDR Device Gain (0-49)(default = 0; Hardware AGC recommended)
|
||||
ppm <num> RTL-SDR PPM Error (default = 0)
|
||||
bw <num> RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24)
|
||||
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
|
||||
udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)
|
||||
Example: dsd-fme-zdev -fs -i rtl -C cap_plus_channel.csv -T
|
||||
Example: dsd-fme-zdev -fp -i rtl:0:851.375M:22:-2:24:0:6021
|
||||
|
||||
```
|
||||
|
||||
## Example Usage - Extra Payload/PDU Logging
|
||||
|
||||
`dsd-fme -Z -N 2> log.ans`
|
||||
|
||||
and in a second terminal tab, same folder, run
|
||||
|
||||
`tail -n 40 -f log.ans`
|
||||
|
||||
### EDACS/P25/NXDN/DMR Simple/Single VFO Trunking ###
|
||||
|
||||
EDACS Trunking (w/ channel map import)
|
||||
|
||||
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (Tested and Working on EDACS/EDACS-EA with Provoice, Analog Voice Monitoring and Per Call is Experimental)
|
||||
|
||||
`dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--NXDN48 Trunking (standard band plan) with SDR++ (untested for frequency accuracy)
|
||||
|
||||
`dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--NXDN48 Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 in channel_map.csv)
|
||||
|
||||
`dsd-fme -fi -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
|
||||
|
||||
--DMR Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 (TIII and Con+) in channel_map.csv)
|
||||
|
||||
`dsd-fme -fs -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
|
||||
|
||||
--P25 Trunking P1 and P2 (C4FM) with SDR++
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--P25 Trunking (QPSK) with P1 Control Channel (Should switch symbol rate and center on Phase 2 audio channels)
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N -mq 2> log.ans`
|
||||
|
||||
--P25 Trunking Phase 2 TDMA Control Channel systems with QPSK (non Phase 1 systems)
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N -f2 -m2 2> log.ans`
|
||||
|
||||
Trunking Note1: All samples above can also be run with the RTL input method and setting of RTL UDP remote port. In terms of performance, however, SDR++ will do a much better job on weaker/marginal signal compared to the RTL input. RTL input should only be used on strong signal.
|
||||
|
||||
`dsd-fme -fp -i rtl:0:851.8M:22:-2:24:0:6020 -T -C channel_map.csv -G group.csv -N 2> log.ans`
|
||||
|
||||
Trunking Note2: QPSK Phase 1 and Phase 2 Systems may be subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
|
||||
|
||||
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but setting a fake channel number (i.e. 999) first with the CC frequency will result in finding the CC faster on startup if desired. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus channel numbering (as best as I can figure it, but they seem consistent) into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the Cd (channel decimal) values from the log, and not the C+ (dsdplus) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
|
||||
|
||||
```
|
||||
Talkgroup Voice Channel Grant (TV_GRANT) - Logical
|
||||
Ch [036] Cd [0054] C+ [0110] - TS [1] - Target [01900500] - Source [01900505]
|
||||
```
|
||||
|
||||
Use channel 54 in your import file, which would correspond to dsdplus channels 109 and 110 (109 = TS0 / 110 = TS1).
|
||||
|
||||
For Connect Plus, enumerate your list from 1 to the last channel and add the frequency. For Capacity Plus, LSN 1 and 2 will share the same frequency, 3 and 4 will share, 5 and 6 will share, and 7-8 will share, as Capacity Plus counts each 'channel' as two seperate channels (LSN), one for each time slot. Capacity Plus Quirk: DSD-FME makes its best effort to follow the rest channel in the event that the sync is lost for longer than the hangtime, but occassionally, DSD-FME may lose the rest channel and will have to hunt through all frequencies to find it again.
|
||||
|
||||
Trunking Note4: NXDN Trunking v1 will require a channel map. Please see the example folder for an appropriate channel map. NOTICE: NXDN trunking has been fixed on the RTL (rtl_fm) input method and works correctly now using a soft squelch value to determine when to look for frame sync. Tests show this works very well, but squelch adjustments may be required to differentiate the noise floor from the signal.
|
||||
|
||||
NXDN Trunking Update: NXDN DFA (Direct Frequency Assignment) has been coded from the v2 documents, so using a channel map may not be required, as long as the DFA is configured with standard values, and not 'system definable' values. This will only work on trunking systems that use DFA (newer systems) in accordance to the v2 CAI document NXDN TS 1-A Version 2.0 September 2016. If the system uses 'system definable' values, then make sure to put the channels in a channel map csv file as as the 16-bit OFN values for proper tuning.
|
||||
|
||||
NXDN Type-D/IDAS Update: Type-D or IDAS decoding/trunking has been coded now and tested on a small two channel system. Set up a channel map much like Type-C trunking. If preferred, insert channel 31 at the top of your channel map for the 'home repeater' or go to channel of choice during a TX_REL or DISC message. Extensive testing of Type-D has not been conducted. Some cavaets may currently include iffy per call wav file saving and potentially shifting SRC and TGT ID values due to how SCCH messages are handled and how Busy Repeater Messages are handled. Private calls will need to be enabled by enabling 'data calls', if desired. During testing, only data calls came on private calls, so this was set to disabled by default, but can be enabled with data calls enabled. Also, note that some home repeater channels may or may not carry calls from all systems.
|
||||
|
||||
Channel Map and Group CSV Note: Leave the top line of the channel_map.csv and group.csv as the label, do not delete the line, if no line is there, dsd_import skips the first line so it will not import the first channel or first group in those files if there is something there that isn't a label.
|
||||
|
||||
Hytera XPT: Code has been added for XPT system slco/flco/csbk decoding and trunking. The setup will be similar to Capacity Plus trunking in the csv file, listing each LSN channel to a frequency (see examples/hytera_xpt_chan.csv). Currently, this set up is working with smaller XPT systems that I have been able to test with.
|
||||
|
||||
## NCurses Keyboard Shortcuts ##
|
||||
|
||||
Some Keyboard Shortcuts have been implemented for testing to see how users like them. Just hope nobody pushes a key on accident and doesn't know which one it was or what it does. The current list of keyboard shortcuts include:
|
||||
|
||||
```
|
||||
esc or arrow keys - ncurses menu
|
||||
q - quit
|
||||
c - toggle compact mode
|
||||
h - toggle call history
|
||||
z - toggle console payloads
|
||||
a - toggle call alert beep
|
||||
4 - force privacy/scrambler key assertion over enc identifiers (dmr and nxdn)
|
||||
6 - force rc4 key assertion over missing pi header/le enc identifiers (dmr)
|
||||
i - toggle signal inversion on types that can't auto detect (dmr, dpmr)
|
||||
m - toggle c4fm/qpsk 10/4 (everything but phase 2 signal)
|
||||
M - toggle c4fm/qpsk 8/3 (phase 2 tdma control channel)
|
||||
R - start capturing symbol capture bin (date/time name file)
|
||||
r - stop capturing symbol capture bin
|
||||
spacebar - replay last symbol capture bin (captures must be stopped first)
|
||||
s - stop playing symbol capture bin or wav input file
|
||||
P - start per call decoded wav files (Capital P)
|
||||
p - stop per call decoded wav files (Lower p)
|
||||
t - toggle trunking (needs either rtl input, or rigctl connection)
|
||||
y - toggle scanner (needs either rtl input, or rigctl connection)
|
||||
1 - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
||||
2 - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
||||
0 - Toggle Audio Smoothing - May produce crackling if enabled on RTL/TCP or wav/bin files
|
||||
w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode
|
||||
g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN)
|
||||
u - Toggle Trunking Tuning to Private Calls (DMR T3, Cap+, P25)
|
||||
d - Toggle Trunking Tuning to Data Calls (DMR T3, NXDN)
|
||||
e - Toggle Trunking Tuning to Encrypted Calls (P25)
|
||||
8 - Connect to SDR++ TCP Audio Sink with Defaults/Retry Sink Connection on Disconnect
|
||||
9 - Connect to SDR++ RIGCTL Server with Defaults/Retry RIGCTL Connection
|
||||
D - Reset DMR Site Parms/Call Strings, etc.
|
||||
Z - Simulate NoCarrier/No VC/CC sync (capital Z)
|
||||
```
|
||||
|
||||
## Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
|
||||
|
||||
Make sure to enable "Stereo Mix" from Volume Control Panel and then disable Windows Sounds.
|
||||
|
||||
`ffmpeg -f dshow -i audio="Stereo Mix (Realtek High Definition Audio)" -c:a aac -b:a 64k -content_type 'audio/aac' -vn -f adts icecast://source:password@192.168.5.251:8844/DSDFME`
|
||||
|
||||
## Sending Audio to a Icecast 2 Server via FFmpeg (Linux w/ Pulse Audio)
|
||||
|
||||
`pactl list short sources`
|
||||
|
||||
Choose Desired Device to Cast:
|
||||
|
||||
```
|
||||
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
|
||||
1 alsa_output.pci-0000_0d_00.3.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||
2 alsa_input.pci-0000_0d_00.3.analog-stereo module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||
3 virtual_sink.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
|
||||
4 virtual_sink2.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
|
||||
7 alsa_output.pci-0000_0b_00.1.hdmi-stereo-extra1.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
francis@12cores:~$ pactl list short sources
|
||||
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
|
||||
francis@12coresx:~$ ffmpeg -f pulse -i 0 -c:a libmp3lame -ab 64k -f mp3 icecast://source:password@XXXXXXXXX:8000
|
||||
|
||||
|
||||
```
|
||||
185
examples/Install_Notes.md
Normal file
185
examples/Install_Notes.md
Normal file
@@ -0,0 +1,185 @@
|
||||
## How to clone and build this branch
|
||||
|
||||
### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer:
|
||||
|
||||
Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 23.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately.
|
||||
|
||||
If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install.sh
|
||||
chmod +x download-and-install.sh
|
||||
./download-and-install.sh
|
||||
```
|
||||
|
||||
### Arch Based Distros:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/v2.1b/download-and-install-Arch.sh
|
||||
chmod +x download-and-install-Arch.sh
|
||||
./download-and-install-Arch.sh
|
||||
```
|
||||
|
||||
### Other:
|
||||
|
||||
If you have dependencies already installed, please run this instead:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install-nodeps.sh
|
||||
chmod +x download-and-install-nodeps.sh
|
||||
./download-and-install-nodeps.sh
|
||||
```
|
||||
|
||||
## Manual Install
|
||||
|
||||
First, install dependency packages. This guide will assume you are using Debian/Ubuntu based distros. Check your package manager for equivalent packages if different.
|
||||
|
||||
Debian/Mint/Ubuntu/Pi
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
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 libncursesw5-dev libcodec2-dev
|
||||
```
|
||||
|
||||
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||
|
||||
```
|
||||
sudo dnf update
|
||||
sudo dnf install libsndfile-devel fftw-devel lapack-devel rtl-sdr-devel pulseaudio-libs-devel libusb-devel cmake git ncurses ncurses-devel gcc wget pavucontrol gcc-c++ codec2-devel
|
||||
```
|
||||
|
||||
Arch -- https://github.com/lwvmobile/dsd-fme/issues/153 and https://github.com/lwvmobile/dsd-fme/issues/153
|
||||
|
||||
```
|
||||
sudo pacman -Syu
|
||||
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
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### 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") This version of MBELib is 1.3.2 and prints to STDERR, using the stock 1.3.0 MBElib may cause problems with print alignments if paired with this version of DSD-FME, or cause future compatibility issues.
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
```
|
||||
|
||||
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
|
||||
`sudo cp libmbe* /usr/lib`
|
||||
|
||||
Finish by running these steps to clone and build DSD-FME.
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
```
|
||||
|
||||
### Windows Cygwin Builds
|
||||
|
||||
If using RTL input support, you must install libusb-win32 before proceeding with Cygwin installation. You will also need to build and compile a version of librtlsdr, but this can be tricky, and personally, I had to resort to using a much older version of the source code to get it to build at all with the rtl support in the precompiled 'Aero' builds.
|
||||
|
||||
Then install all dependencies available in the repo prior to building, either directly selecting them during setup with the setup-x86.exe or setup-x64.exe or by issuing a command similar to this:
|
||||
|
||||
```
|
||||
setup-x64.exe --packages libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,xfce-pulseaudio-plugin,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,unzip,wget,gcc-g++,libsndfile-devel
|
||||
```
|
||||
|
||||
Then manually install ITPP and MBElib, see above install notes. Be sure to run `cp libmbe* /usr/lib` after compiling MBElib.
|
||||
|
||||
Then you can build and install using
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
cp tone8.wav /usr/share/
|
||||
cp tone24.wav /usr/share/
|
||||
cp tone48.wav /usr/share/
|
||||
chmod 777 /usr/share/tone8.wav
|
||||
chmod 777 /usr/share/tone24.wav
|
||||
chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
# -DAERO=ON is optional, but recommended if you want the older OSS support as well
|
||||
cmake -DAERO=ON ..
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
### Virtual Sinks
|
||||
|
||||
You may wish to direct sound into DSD-FME via Virtual Sinks. You may set up a Virtual Sink or two on your machine for routing audio in and out of applications to other applications using the following command, and opening up pavucontrol "PulseAudio Volume Control" in the menu (or `pulsemixer` in headless mode) to change line out of application to virtual sink, and line in of DSD-FME to monitor of virtual sink. This command will not persist past a reboot, so you will need to invoke them each time you reboot, or search for how to add this to your conf files for persistency if desired. Note: This setup is completely optional if using TCP Network Sink Audio and/or RTL Input.
|
||||
|
||||
```
|
||||
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||
pactl load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||
```
|
||||
|
||||
Already have this branch, and just want to pull the latest build? You can run the rebuild.sh file in the dsd-fme folder, or manually do the pull with the commands:
|
||||
|
||||
```
|
||||
##Open your clone folder##
|
||||
git pull
|
||||
##cd into your build folder##
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
```
|
||||
|
||||
If the call alert wav files aren't playing, then make sure to run the following in the dsd-fme folder to copy the wav files to the /usr/share/ folder and give them adequate permission to be accessed.
|
||||
|
||||
```
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
```
|
||||
10
examples/capacity_plus_chan.csv
Normal file
10
examples/capacity_plus_chan.csv
Normal file
@@ -0,0 +1,10 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,858606250
|
||||
2,858606250
|
||||
3,859606250
|
||||
4,859606250
|
||||
5,860606250
|
||||
6,860606250
|
||||
7,861606250
|
||||
8,861606250
|
||||
|
||||
|
19
examples/connect_plus_chan.csv
Normal file
19
examples/connect_plus_chan.csv
Normal file
@@ -0,0 +1,19 @@
|
||||
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
999,862093750,default cc (come here first), optional use non-existent channel as first entry
|
||||
1,863093750
|
||||
2,862093750
|
||||
3,861093750
|
||||
4,860093750
|
||||
5,859093750
|
||||
6,863593750
|
||||
7,862593750
|
||||
8,861593750
|
||||
9,860593750
|
||||
10,859593750
|
||||
11,863393750
|
||||
12,862393750
|
||||
13,861393750
|
||||
14,860393750
|
||||
15,859393750
|
||||
|
||||
|
||||
|
8
examples/dmr_t3_chan.csv
Normal file
8
examples/dmr_t3_chan.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
999,456318750,default cc (come here first), optional use non-existent channel as first entry
|
||||
36,455756250
|
||||
54,455981250
|
||||
81,456318750
|
||||
|
||||
|
||||
|
||||
|
6
examples/edacs_channel_map.csv
Normal file
6
examples/edacs_channel_map.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,851375000
|
||||
2,851800000
|
||||
3,855987500
|
||||
4,858487500
|
||||
5,852312500
|
||||
|
5
examples/group.csv
Normal file
5
examples/group.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
DEC,Mode(A- Allow, B - Block, DE - Digital Enc),Name of Group,Tag (do not delete this line or won't import properly)
|
||||
100,B,Example Name,Tag
|
||||
1449,A,Fire Dispatch,Fire
|
||||
929,A,Fire Tac,Fire
|
||||
22033,DE,Law Dispatch,Law
|
||||
|
10
examples/hytera_xpt_chan.csv
Normal file
10
examples/hytera_xpt_chan.csv
Normal file
@@ -0,0 +1,10 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,858606250
|
||||
2,858606250
|
||||
3,859606250
|
||||
4,859606250
|
||||
5,860606250
|
||||
6,860606250
|
||||
7,861606250
|
||||
8,861606250
|
||||
|
||||
|
6
examples/multi_key.csv
Normal file
6
examples/multi_key.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
key id or tg id (dec), key number or value (dec) //NXDN Scrambler, BP, 10-char Hytera BP only
|
||||
2,70
|
||||
1,123
|
||||
100,70
|
||||
12,48713912656
|
||||
672560,254
|
||||
|
5
examples/multi_key_hex.csv
Normal file
5
examples/multi_key_hex.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
key id(hex), key value (hex) //10-char Hytera BP, RC4
|
||||
1,1234567890
|
||||
2,ABCDEF1234
|
||||
C,0B57935150
|
||||
64,0B57935150
|
||||
|
8
examples/nxdn_chan_map.csv
Normal file
8
examples/nxdn_chan_map.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
channel(dec), freq(Hz)
|
||||
141,423862500
|
||||
142,424337500
|
||||
143,424912500
|
||||
203,424100000
|
||||
204,424625000
|
||||
271,422650000
|
||||
302,423287500
|
||||
|
5
examples/nxdn_sc_key.csv
Normal file
5
examples/nxdn_sc_key.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
key(dec) or tg(dec), value(dec), load any single keys as key 0
|
||||
0,23466
|
||||
1,12345
|
||||
2,32700
|
||||
63,32767
|
||||
|
49
examples/trunking.sh
Normal file
49
examples/trunking.sh
Normal file
@@ -0,0 +1,49 @@
|
||||
#example trunking sh scripts (SDR++ with RIGCTL and RTL Input)
|
||||
#make sure to put a # in front of all lines except the one you wish to use
|
||||
|
||||
#P25 P1 FDMA CC with C4FM
|
||||
#dsd-fme -i tcp -U 4532 -T -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:850M:0:-2:12 -T -N 2> log.ans
|
||||
|
||||
#P25 P1 FDMA CC with QPSK (Simulcast)
|
||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -mq -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -mq -N 2> log.ans
|
||||
|
||||
#P25 P2 TDMA CC with QPSK (Simulcast)
|
||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -m2 -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
|
||||
|
||||
#P25 P2 TDMA CC with C4FM
|
||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
|
||||
|
||||
#DMR TIII, Con+, Cap+, XPT
|
||||
dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans
|
||||
#dsd-fme -fs -i rtl:0:450M:44:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#EDACS/EDACS-EA Digital Only
|
||||
#dsd-fme -fp -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
#dsd-fme -fp -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#NXDN48 Type-C or Type-D Trunking with Channel Map
|
||||
#dsd-fme -fi -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
||||
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -C nxdn_channel_map.csv -N 2> log.ans
|
||||
|
||||
#NXDN48 Type-C Trunking with DFA
|
||||
#dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans
|
||||
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -N 2> log.ans
|
||||
|
||||
#NXDN96 Trunking with Channel Map
|
||||
#dsd-fme -fn -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
||||
#dsd-fme -fn -i rtl -T -C nxdn_channel_map.csv -N 2> log.ans
|
||||
|
||||
#Notes: parameters after -i tcp can be omitted if using localhost as the default hostname to connect
|
||||
#and 7355 as the default port number. -U is the port number for RIGCTL and will mirror the tcp hostname
|
||||
#running under the assumption that the user will be connnecting the VFO to the same instance of SDR++
|
||||
#You can also specify an ip address to connect to a remote SDR++ instance, make sure that the settings
|
||||
#inside of SDR++ match, i.e., change in SDR++ from 'localhost' to an IP to bind to (machine's IP address)
|
||||
|
||||
#Note2: RTL input should only be used on strong signal, the SDR++ VFO will perform much better on marginal signal
|
||||
#paramters after -i rtl can also be omitted now if using the default configurations
|
||||
|
||||
#Having a -G group.csv is purely optional, but useful if you want to block groups, or give groups names
|
||||
107
include/dsd.h
107
include/dsd.h
@@ -74,7 +74,11 @@
|
||||
#include <locale.h>
|
||||
#include <ncurses.h>
|
||||
|
||||
static volatile int exitflag;
|
||||
#ifdef USE_CODEC2
|
||||
#include <codec2/codec2.h>
|
||||
#endif
|
||||
|
||||
extern volatile uint8_t exitflag; //fix for issue #136
|
||||
|
||||
//group csv import struct
|
||||
typedef struct
|
||||
@@ -270,6 +274,7 @@ typedef struct
|
||||
int rtl_udp_port;
|
||||
int rtl_bandwidth;
|
||||
int rtl_started;
|
||||
long int rtl_rms;
|
||||
int monitor_input_audio;
|
||||
int pulse_raw_rate_in;
|
||||
int pulse_raw_rate_out;
|
||||
@@ -308,6 +313,9 @@ typedef struct
|
||||
int inverted_ysf;
|
||||
short int aggressive_framesync;
|
||||
|
||||
int frame_m17;
|
||||
int inverted_m17;
|
||||
|
||||
FILE *symbolfile;
|
||||
int call_alert;
|
||||
|
||||
@@ -357,6 +365,9 @@ typedef struct
|
||||
uint8_t dmr_dmrla_is_set; //flag to tell us dmrla is set by the user
|
||||
uint8_t dmr_dmrla_n; //n value for dmrla
|
||||
|
||||
//DMR Late Entry
|
||||
uint8_t dmr_le; //user option to turn on or turn off late entry for enc identifiers
|
||||
|
||||
//Trunking - Use Group List as Allow List
|
||||
uint8_t trunk_use_allow_list;
|
||||
|
||||
@@ -373,12 +384,15 @@ typedef struct
|
||||
uint8_t trunk_tune_enc_calls;
|
||||
|
||||
//OSS audio - slot preference
|
||||
uint8_t slot_preference;
|
||||
int slot_preference;
|
||||
|
||||
//'DSP' Format Output
|
||||
uint8_t use_dsp_output;
|
||||
char dsp_out_file[2048];
|
||||
|
||||
//Use P25p1 heuristics
|
||||
uint8_t use_heuristics;
|
||||
|
||||
} dsd_opts;
|
||||
|
||||
typedef struct
|
||||
@@ -400,6 +414,10 @@ typedef struct
|
||||
float *audio_out_temp_buf_p;
|
||||
float audio_out_temp_bufR[160];
|
||||
float *audio_out_temp_buf_pR;
|
||||
//analog/raw signal audio buffers
|
||||
short analog_out[960];
|
||||
int analog_sample_counter;
|
||||
//
|
||||
int audio_out_idx;
|
||||
int audio_out_idx2;
|
||||
int audio_out_idxR;
|
||||
@@ -699,14 +717,63 @@ typedef struct
|
||||
//Upsampled Audio Smoothing
|
||||
uint8_t audio_smoothing;
|
||||
|
||||
//YSF Fusion Call Strings and Info
|
||||
uint8_t ysf_dt; //data type -- VD1, VD2, Full Rate, etc.
|
||||
uint8_t ysf_fi; //frame information -- HC, CC, TC
|
||||
uint8_t ysf_cm; //group or private call
|
||||
char ysf_tgt[11];
|
||||
char ysf_src[11];
|
||||
char ysf_upl[11];
|
||||
char ysf_dnl[11];
|
||||
char ysf_rm1[6];
|
||||
char ysf_rm2[6];
|
||||
char ysf_rm3[6];
|
||||
char ysf_rm4[6];
|
||||
char ysf_txt[21][21]; //text storage blocks
|
||||
|
||||
//M17 Storage
|
||||
uint8_t m17_lsf[360];
|
||||
uint8_t m17_str_dt; //stream contents
|
||||
|
||||
unsigned long long int m17_dst;
|
||||
unsigned long long int m17_src;
|
||||
uint8_t m17_can;
|
||||
|
||||
char m17_dst_csd[20];
|
||||
char m17_src_csd[20];
|
||||
|
||||
char m17_src_str[50];
|
||||
char m17_dst_str[50];
|
||||
|
||||
uint8_t m17_meta[16]; //packed meta
|
||||
uint8_t m17_enc; //enc type
|
||||
uint8_t m17_enc_st; //scrambler or data subtye
|
||||
|
||||
//Codec2
|
||||
#ifdef USE_CODEC2
|
||||
struct CODEC2 *codec2_3200; //M17 fullrate
|
||||
struct CODEC2 *codec2_1600; //M17 halfrate
|
||||
#endif
|
||||
|
||||
} dsd_state;
|
||||
|
||||
/*
|
||||
* Frame sync patterns
|
||||
*/
|
||||
|
||||
#define FUSION_SYNC "31111311313113131131" //HA!
|
||||
#define INV_FUSION_SYNC "13333133131331313313" //HA!
|
||||
//The inverse of LSF also seems to be Stream Frame Type, only going to work on Stream mode for now
|
||||
#define M17_LSF "11113313"
|
||||
#define M17_STR "33331131"
|
||||
//alternating with last symbol opposite of first symbol of LSF
|
||||
#define M17_PRE "31313131"
|
||||
#define M17_PIV "13131313"
|
||||
#define M17_PRE_LSF "3131313133331131" //Preamble + LSF
|
||||
#define M17_PIV_LSF "1313131311113313" //Preamble + LSF
|
||||
// #define M17_BRT "31331111"
|
||||
// #define M17_PKT "13113333"
|
||||
|
||||
#define FUSION_SYNC "31111311313113131131"
|
||||
#define INV_FUSION_SYNC "13333133131331313313"
|
||||
|
||||
#define INV_P25P1_SYNC "333331331133111131311111"
|
||||
#define P25P1_SYNC "111113113311333313133333"
|
||||
@@ -872,14 +939,16 @@ void processX2TDMAdata (dsd_opts * opts, dsd_state * state);
|
||||
void processX2TDMAvoice (dsd_opts * opts, dsd_state * state);
|
||||
void processDSTAR_HD (dsd_opts * opts, dsd_state * state);
|
||||
void processYSF(dsd_opts * opts, dsd_state * state); //YSF
|
||||
void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR)
|
||||
void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF)
|
||||
void processP2(dsd_opts * opts, dsd_state * state); //P2
|
||||
void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block
|
||||
void processMPDU(dsd_opts * opts, dsd_state * state); //P25 Multi Block PDU (SAP 0x61 FMT 0x15 or 0x17 for Trunking Blocks)
|
||||
short dmr_filter(short sample);
|
||||
short nxdn_filter(short sample);
|
||||
short dpmr_filter(short sample);
|
||||
short m17_filter(short sample);
|
||||
|
||||
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr);
|
||||
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
|
||||
|
||||
void ncursesOpen (dsd_opts * opts, dsd_state * state);
|
||||
@@ -972,6 +1041,8 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]);
|
||||
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]);
|
||||
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18]); //simplier trellis decoder
|
||||
void beeper (dsd_opts * opts, dsd_state * state, int type); //the tone beeper function
|
||||
|
||||
//Embedded Alias and GPS
|
||||
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||
@@ -1006,10 +1077,15 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power);
|
||||
bool Hamming17123(uint8_t* d);
|
||||
uint8_t crc8(uint8_t bits[], unsigned int len);
|
||||
bool crc8_ok(uint8_t bits[], unsigned int len);
|
||||
//modified CRC functions for SB/RC
|
||||
uint8_t crc7(uint8_t bits[], unsigned int len);
|
||||
uint8_t crc3(uint8_t bits[], unsigned int len);
|
||||
uint8_t crc4(uint8_t bits[], unsigned int len);
|
||||
|
||||
//LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
//LFSR and LFSRP code courtesy of https://github.com/mattames/LFSR/
|
||||
void LFSR(dsd_state * state);
|
||||
void LFSRP(dsd_state * state);
|
||||
|
||||
void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state);
|
||||
void LFSR64(dsd_state * state);
|
||||
|
||||
@@ -1051,6 +1127,7 @@ bool QR_16_7_6_decode(unsigned char *rxBits);
|
||||
|
||||
void InitAllFecFunction(void);
|
||||
void resetState (dsd_state * state);
|
||||
void reset_dibit_buffer(dsd_state * state);
|
||||
void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660]);
|
||||
|
||||
//P25 PDU Handler
|
||||
@@ -1096,7 +1173,8 @@ unsigned long long int edacs_bch (unsigned long long int message);
|
||||
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvLCNImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvChanImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvKeyImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvKeyImportDec(dsd_opts * opts, dsd_state * state);
|
||||
int csvKeyImportHex(dsd_opts * opts, dsd_state * state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -1107,22 +1185,17 @@ void open_rtlsdr_stream(dsd_opts *opts);
|
||||
void cleanup_rtlsdr_stream();
|
||||
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state);
|
||||
void rtlsdr_sighandler();
|
||||
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
||||
long int rtl_return_rms();
|
||||
void rtl_clean_queue();
|
||||
#endif
|
||||
//DMR TRELLIS
|
||||
void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload);
|
||||
unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits);
|
||||
bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload);
|
||||
void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits);
|
||||
void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points);
|
||||
void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits);
|
||||
void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits);
|
||||
bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload);
|
||||
|
||||
|
||||
//Phase 2 Helper Functions
|
||||
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME
|
||||
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 isch_lookup (unsigned long long int isch); //isch map lookup
|
||||
int isch_lookup (uint64_t isch); //isch map lookup
|
||||
int bd_bridge (int payload[196], uint8_t decoded[12]); //bridge to Michael Ossmann Block De-interleaver and 1/2 rate trellis decoder
|
||||
int crc16_lb_bridge (int payload[190], int len);
|
||||
int crc12_xb_bridge (int payload[190], int len);
|
||||
|
||||
12
install.sh
Normal file
12
install.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
16
rebuild.sh
Normal file
16
rebuild.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition
|
||||
echo Automatic Git Pull and Rebuild
|
||||
echo
|
||||
sleep 1
|
||||
##Open your clone folder##
|
||||
git pull
|
||||
sleep 2
|
||||
##cd into your build folder##
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
136
src/dmr_34.c
Normal file
136
src/dmr_34.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_34.c
|
||||
* DMR 3/4 Rate Simple Trellis Decoder
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2023-08 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
uint8_t interleave[98] = {
|
||||
0, 1, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 56, 57, 64, 65, 72, 73, 80, 81, 88, 89, 96, 97,
|
||||
2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66, 67, 74, 75, 82, 83, 90, 91,
|
||||
4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93,
|
||||
6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 95};
|
||||
|
||||
//this is a convertion table for converting the dibit pairs into contellation points
|
||||
uint8_t constellation_map[16] = {
|
||||
11, 12, 0, 7, 14, 9, 5, 2, 10, 13, 1, 6, 15, 8, 4, 3
|
||||
};
|
||||
|
||||
//digitized dibit to OTA symbol conversion for reference
|
||||
//0 = +1; 1 = +3;
|
||||
//2 = -1; 3 = -3;
|
||||
|
||||
//finite state machine values
|
||||
uint8_t fsm[64] = {
|
||||
0, 8, 4, 12, 2, 10, 6, 14,
|
||||
4, 12, 2, 10, 6, 14, 0, 8,
|
||||
1, 9, 5, 13, 3, 11, 7, 15,
|
||||
5, 13, 3, 11, 7, 15, 1, 9,
|
||||
3, 11, 7, 15, 1, 9, 5, 13,
|
||||
7, 15, 1, 9, 5, 13, 3, 11,
|
||||
2, 10, 6, 14, 0, 8, 4, 12,
|
||||
6, 14, 0, 8, 4, 12, 2, 10};
|
||||
|
||||
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18])
|
||||
{
|
||||
int i, j;
|
||||
uint32_t irr_err = 0;
|
||||
|
||||
uint8_t deinterleaved_dibits[98];
|
||||
memset (deinterleaved_dibits, 0, sizeof(deinterleaved_dibits));
|
||||
|
||||
//deinterleave our input dibits
|
||||
for (i = 0; i < 98; i++)
|
||||
deinterleaved_dibits[interleave[i]] = input[i];
|
||||
|
||||
//pack the input into nibbles (dibit pairs)
|
||||
uint8_t nibs[49];
|
||||
memset (nibs, 0, sizeof(nibs));
|
||||
|
||||
for (i = 0; i < 49; i++)
|
||||
nibs[i] = (deinterleaved_dibits[i*2+0] << 2) | (deinterleaved_dibits[i*2+1] << 0);
|
||||
|
||||
//convert our dibit pairs into constellation point values
|
||||
uint8_t point[49];
|
||||
memset (point, 0xFF, sizeof(point));
|
||||
|
||||
for (i = 0; i < 49; i++)
|
||||
point[i] = constellation_map[nibs[i]];
|
||||
|
||||
//debug view points -- point[0] should be zero
|
||||
// fprintf (stderr, "\n P =");
|
||||
// for (i = 0; i < 49; i++)
|
||||
// fprintf (stderr, " %02d", point[i]);
|
||||
|
||||
//free-bee on err correction, point[0] should always be zero (flush bits)
|
||||
point[0] = 0;
|
||||
|
||||
//convert constellation points into tribit values using the FSM
|
||||
uint8_t state = 0;
|
||||
uint32_t tribits[49];
|
||||
memset (tribits, 0xF, sizeof(tribits));
|
||||
|
||||
for (i = 0; i < 49; i++)
|
||||
{
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if ( fsm[(state*8)+j] == point[i] )
|
||||
{
|
||||
//return our tribit value and state for the next point
|
||||
tribits[i] = state = (uint8_t)j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if tribit value is greater than 7, then we have a decoding error
|
||||
if (tribits[i] > 7)
|
||||
{
|
||||
irr_err++; //tally number of errors
|
||||
|
||||
//debug position of error and state value
|
||||
// fprintf (stderr, " %d:%d;", i, state);
|
||||
|
||||
//Make a hard decision and flip point to fit in current state
|
||||
point[i] ^= 7; //lucky number 7 (0111)
|
||||
|
||||
//NOTE: Ideally, a full path metric to find the surviving path
|
||||
//is the best way to correct this, but it is also complex and no garauntee to fix errs
|
||||
|
||||
//decrement one and try again
|
||||
if (i != 0) i--;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//debug view tribits/states
|
||||
// fprintf (stderr, "\n T =");
|
||||
// for (i = 0; i < 49; i++)
|
||||
// fprintf (stderr, " %02d", tribits[i]);
|
||||
|
||||
//convert tribits into a return payload
|
||||
uint32_t temp = 0;
|
||||
if (1 == 1) //irr_err == 0
|
||||
{
|
||||
//break into chunks of 24 bit values and shuffle into 8-bit (byte) treturn values
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
temp = (tribits[(i*8)+0] << 21) + (tribits[(i*8)+1] << 18) + (tribits[(i*8)+2] << 15) + (tribits[(i*8)+3] << 12) + (tribits[(i*8)+4] << 9) + (tribits[(i*8)+5] << 6) + (tribits[(i*8)+6] << 3) + (tribits[(i*8)+7] << 0);
|
||||
|
||||
treturn[(i*3)+0] = (temp >> 16) & 0xFF;
|
||||
treturn[(i*3)+1] = (temp >> 8) & 0xFF;
|
||||
treturn[(i*3)+2] = (temp >> 0) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
//trellis point/state err tally
|
||||
if (irr_err != 0)
|
||||
fprintf (stderr, " ERR = %d", irr_err);
|
||||
|
||||
return (irr_err);
|
||||
}
|
||||
|
||||
@@ -776,9 +776,9 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
||||
memset (state->cap_plus_block_num, 0, sizeof(state->cap_plus_block_num));
|
||||
memset (state->data_header_valid, 0, sizeof(state->data_header_valid));
|
||||
memset (state->data_header_format, 7, sizeof(state->data_header_format));
|
||||
//reset some strings
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
//reset some strings -- resetting call string here causes random blink on ncurses terminal (cap+)
|
||||
// sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
// sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
||||
sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
||||
}
|
||||
35
src/dmr_bs.c
35
src/dmr_bs.c
@@ -96,6 +96,10 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//Run Loop while the getting is good
|
||||
while (loop == 1) {
|
||||
|
||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||
|
||||
internalslot = -1; //reset here so we know if this value is being set properly
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -339,8 +343,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity
|
||||
dmr_sbrc (opts, state, power);
|
||||
//check the single burst/reverse channel opportunity -- moved
|
||||
// dmr_sbrc (opts, state, power);
|
||||
|
||||
}
|
||||
|
||||
if (internalslot == 1 && vc2 == 6)
|
||||
@@ -348,8 +353,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity
|
||||
dmr_sbrc (opts, state, power);
|
||||
//check the single burst/reverse channel opportunity -- moved
|
||||
// dmr_sbrc (opts, state, power);
|
||||
|
||||
}
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||
@@ -361,23 +367,14 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
// if ( opts->audio_in_type == 5 && internalslot == 0 && state->dmrburstR != 16 ) //(OSS shim)
|
||||
// {
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
// }
|
||||
// if ( opts->audio_in_type == 5 && internalslot == 1 && state->dmrburstL != 16 ) //(OSS shim)
|
||||
// {
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
// }
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
|
||||
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
||||
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
||||
if (internalslot == 1 && vc2 == 6) dmr_sbrc (opts, state, power);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
@@ -501,6 +498,10 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
|
||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||
|
||||
//memcpy of ambe_fr for late entry
|
||||
char m1[4][24];
|
||||
char m2[4][24];
|
||||
|
||||
@@ -249,13 +249,15 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -684,7 +686,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
if (gi == 0) target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
|
||||
source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[64], 16);
|
||||
int rest = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[60], 4);
|
||||
fprintf (stderr, "Source: %d - Target: %d - Rest Channel: %d", source, target, rest);
|
||||
fprintf (stderr, "Source: %d - Target: %d - Rest LSN: %d", source, target, rest);
|
||||
}
|
||||
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
|
||||
|
||||
@@ -818,7 +820,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
|
||||
fprintf (stderr, " Capacity Plus Channel Status - FL: %d TS: %d RS: %d - Rest Channel %d", fl, ts, res, rest_channel);
|
||||
fprintf (stderr, " Capacity Plus Channel Status - FL: %d TS: %d RS: %d - Rest LSN: %d", fl, ts, res, rest_channel);
|
||||
if (fl == 0) fprintf (stderr, " - Appended Block"); //have not yet observed a system use this fl value
|
||||
if (fl == 1) fprintf (stderr, " - Final Block");
|
||||
if (fl == 2) fprintf (stderr, " - Initial Block");
|
||||
@@ -1016,6 +1018,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//Skip tuning group calls if group calls are disabled -- moved to individual switches in the parsing phase
|
||||
// if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
|
||||
|
||||
//Test allowing a group in the white list to preempt a call in progress and tune to a white listed call
|
||||
if (opts->trunk_use_allow_list == 1) state->last_vc_sync_time = 0;
|
||||
|
||||
//don't tune if vc on the current channel
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
@@ -1055,14 +1060,16 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
j = 11; //break loop
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1198,15 +1205,17 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[lcn]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_chan_map[lcn]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[lcn];
|
||||
opts->p25_is_tuned = 1;
|
||||
state->is_con_plus = 1; //flag on
|
||||
state->last_vc_sync_time = time(NULL); //bugfix: set sync here so we don't immediately tune back to CC constantly.
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1348,6 +1357,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//Skip tuning calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPXPT;
|
||||
|
||||
//Test allowing a group in the white list to preempt a call in progress and tune to a white listed call
|
||||
if (opts->trunk_use_allow_list == 1) state->last_vc_sync_time = 0;
|
||||
|
||||
//don't tune if vc on the current channel
|
||||
if ( (time(NULL) - state->last_vc_sync_time) > 2 ) //parenthesis error fixed
|
||||
{
|
||||
@@ -1393,17 +1405,19 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
//debug
|
||||
fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
|
||||
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+xpt_bank+1]);
|
||||
rtl_dev_tune (opts, state->trunk_chan_map[j+xpt_bank+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+xpt_bank+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
j = 11; //break loop
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -258,7 +258,6 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1;
|
||||
else
|
||||
{
|
||||
SlotTypeOk = -1;
|
||||
SlotTypeOk = 0;
|
||||
goto END;
|
||||
}
|
||||
@@ -336,8 +335,9 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
else if (opts->audio_in_type == 3) //rtl_fm tuning
|
||||
{
|
||||
//UDP command to tune the RTL dongle
|
||||
rtl_udp_tune(opts, state, state->p25_cc_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune(opts, state->p25_cc_freq);
|
||||
#endif
|
||||
}
|
||||
opts->p25_is_tuned = 0;
|
||||
//zero out vc frequencies
|
||||
|
||||
@@ -45,6 +45,13 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
uint8_t LC_DataBytes[10];
|
||||
int Burst = -1;
|
||||
|
||||
memset (BPTCDeInteleavedData, 0, sizeof(BPTCDeInteleavedData));
|
||||
memset (BPTCDmrDataBit, 0, sizeof(BPTCDmrDataBit));
|
||||
memset (BPTCDmrDataByte, 0, sizeof(BPTCDmrDataByte));
|
||||
memset (BptcDataMatrix, 0, sizeof(BptcDataMatrix));
|
||||
memset (LC_DataBit, 0, sizeof(LC_DataBit));
|
||||
memset (LC_DataBytes, 0, sizeof(LC_DataBytes));
|
||||
|
||||
//PDU Bytes and Bits
|
||||
uint8_t DMR_PDU[25];
|
||||
uint8_t DMR_PDU_bits[196];
|
||||
@@ -411,34 +418,29 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
|
||||
}
|
||||
|
||||
//the ugly one
|
||||
//the sexy one
|
||||
if (is_trellis)
|
||||
{
|
||||
CRCExtracted = 0;
|
||||
CRCComputed = 0;
|
||||
IrrecoverableErrors = 1;
|
||||
bool trellis_good = TRUE;
|
||||
|
||||
uint8_t tdibits[98];
|
||||
memset (tdibits, 0, sizeof(tdibits));
|
||||
|
||||
//reconstitute info bits into reverse ordered dibits for the trellis decoder
|
||||
//reconstitute info bits into dibits for the trellis decoder
|
||||
for (i = 0; i < 98; i++)
|
||||
{
|
||||
tdibits[97-i] = (info[i*2] << 1) | info[i*2+1];
|
||||
}
|
||||
tdibits[i] = (info[i*2] << 1) | info[i*2+1];
|
||||
|
||||
unsigned char TrellisReturn[18];
|
||||
uint8_t TrellisReturn[18];
|
||||
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
||||
IrrecoverableErrors = dmr_34(tdibits, TrellisReturn);
|
||||
|
||||
trellis_good = CDMRTrellisDecode(tdibits, TrellisReturn);
|
||||
if (trellis_good == TRUE) IrrecoverableErrors = 0;
|
||||
// else (fprintf (stderr, " Trellis Failure")); //debug print
|
||||
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
|
||||
//they may have been successfully corrected, the CRC will reveal as much
|
||||
|
||||
for (i = 0; i < pdu_len; i++) //18
|
||||
{
|
||||
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
|
||||
}
|
||||
for (i = 0; i < pdu_len; i++)
|
||||
DMR_PDU[i] = TrellisReturn[i+pdu_start];
|
||||
|
||||
for(i = 0, j = 0; i < 18; i++, j+=8)
|
||||
{
|
||||
@@ -464,7 +466,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
CRCExtracted = CRCExtracted ^ crcmask;
|
||||
|
||||
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
|
||||
//confirmed working now!
|
||||
for(i = 0; i < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
|
||||
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
|
||||
|
||||
@@ -475,10 +476,8 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
state->data_block_crc_valid[slot][blockcounter] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix
|
||||
state->data_block_crc_valid[slot][blockcounter] = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -498,7 +497,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
|
||||
}
|
||||
|
||||
if (is_full) //Rate 1 Data
|
||||
if (is_full) //Rate 1 Data -- todo: fix padding bits, the four padding bits are on bit 96,97,98,99
|
||||
{
|
||||
CRCExtracted = 0;
|
||||
CRCComputed = 0;
|
||||
@@ -598,7 +597,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
|
||||
// }
|
||||
|
||||
if (IrrecoverableErrors != 0 && databurst != 0x09) //&& databurst != 0x05
|
||||
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, " (FEC ERR)");
|
||||
|
||||
@@ -342,6 +342,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
state->payload_miR = 0;
|
||||
state->payload_keyidR = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -420,22 +421,17 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
if (fid == 0x10)
|
||||
{
|
||||
/* Check the "Service Option" bits */
|
||||
if(so & 0x30)
|
||||
if(so & 0x20)
|
||||
{
|
||||
/* Experimentally determined with DSD+,
|
||||
* is equal to 0x2, this is a TXI call */
|
||||
if((so & 0x30) == 0x20)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " TXI");
|
||||
fprintf(stderr, "TXI ");
|
||||
}
|
||||
else
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " RES");
|
||||
fprintf(stderr, "RS%d ", (so & 0x30) >> 4);
|
||||
}
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " TXI");
|
||||
fprintf(stderr, "TXI ");
|
||||
}
|
||||
if (so & 0x10)
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " RPT");
|
||||
fprintf(stderr, "RPT "); //Short way of saying the next SF's VC6 will be pre-empted/repeat frames for the TXI backwards channel
|
||||
}
|
||||
if(so & 0x08)
|
||||
{
|
||||
@@ -493,7 +489,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
if (restchannel != -1)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "Cap+ R-Ch %d", restchannel);
|
||||
fprintf (stderr, "Rest LSN: %d", restchannel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,26 +507,65 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
}
|
||||
}
|
||||
|
||||
if (state->K != 0 && fid == 0x10 && so & 0x40)
|
||||
//BUGFIX: Include slot and algid so we don't accidentally print more than one loaded key
|
||||
//this can happen on Missing PI header and LE when the keyloader has loaded a TG/Hash key and an RC4 key simultandeously
|
||||
//subsequennt EMB would print two key values until call cleared out
|
||||
|
||||
if (state->K != 0 && fid == 0x10 && so & 0x40 && slot == 0 && state->payload_algid == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %lld ", state->K);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (state->K != 0 && fid == 0x10 && so & 0x40 && slot == 1 && state->payload_algidR == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %lld ", state->K);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (state->K1 != 0 && fid == 0x68 && so & 0x40)
|
||||
if (state->K1 != 0 && fid == 0x68 && so & 0x40 && slot == 0 && state->payload_algid == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
if (state->K2 != 0) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Key %010llX ", state->K1);
|
||||
fprintf (stderr, "Key %010llX ", state->K1);
|
||||
if (state->K2 != 0) fprintf (stderr, "%016llX ", state->K2);
|
||||
if (state->K4 != 0) fprintf (stderr, "%016llX %016llX", state->K3, state->K4);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->K1 != 0 && fid == 0x68 && so & 0x40 && slot == 1 && state->payload_algidR == 0)
|
||||
{
|
||||
if (state->K2 != 0) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %010llX ", state->K1);
|
||||
if (state->K2 != 0) fprintf (stderr, "%016llX ", state->K2);
|
||||
if (state->K4 != 0) fprintf (stderr, "%016llX %016llX", state->K3, state->K4);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (slot == 0 && state->payload_algid == 0x21 && state->R != 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %010llX ", state->R);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (slot == 1 && state->payload_algidR == 0x21 && state->RR != 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %010llX ", state->RR);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
END_FLCO:
|
||||
|
||||
//blank the call string here if its a TLC
|
||||
if (type == 2) sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
if (unk == 1 || pf == 1)
|
||||
{
|
||||
fprintf(stderr, " FLCO=0x%02X FID=0x%02X ", flco, fid);
|
||||
|
||||
325
src/dmr_le.c
325
src/dmr_le.c
@@ -13,6 +13,23 @@ void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc,
|
||||
{
|
||||
|
||||
uint8_t slot = state->currentslot;
|
||||
|
||||
//enforce RC4 due to missing PI header, but with valid SVC Opts
|
||||
//ideally, this would be handled by VC-F single burst, but its not fully reliable compared to this
|
||||
//due to multiple signalling occurring inside of it, depending on system type
|
||||
if (state->M == 0x21)
|
||||
{
|
||||
if (slot == 0 && state->dmr_so & 0x40)
|
||||
{
|
||||
state->payload_algid = 0x21;
|
||||
state->payload_keyid = 0xFF;
|
||||
}
|
||||
if (slot == 1 && state->dmr_soR & 0x40)
|
||||
{
|
||||
state->payload_algidR = 0x21;
|
||||
state->payload_keyidR = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
//collect our fragments and place them into storage
|
||||
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
|
||||
@@ -34,6 +51,12 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
||||
uint64_t go_test = 0;
|
||||
uint64_t mi_corrected = 0;
|
||||
uint64_t go_corrected = 0;
|
||||
|
||||
uint8_t mi_bits[36];
|
||||
memset (mi_bits, 0, sizeof(mi_bits));
|
||||
uint8_t mi_crc_cmp = 0;
|
||||
uint8_t mi_crc_ext = 1;
|
||||
uint8_t mi_crc_ok = 0;
|
||||
|
||||
mi_test = (state->late_entry_mi_fragment[slot][1][0] << 32L) | (state->late_entry_mi_fragment[slot][2][0] << 28) | (state->late_entry_mi_fragment[slot][3][0] << 24) |
|
||||
(state->late_entry_mi_fragment[slot][1][1] << 20) | (state->late_entry_mi_fragment[slot][2][1] << 16) | (state->late_entry_mi_fragment[slot][3][1] << 12) |
|
||||
@@ -60,12 +83,22 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
||||
mi_corrected |= mi_go_bits[i];
|
||||
go_corrected = go_corrected << 1;
|
||||
go_corrected |= mi_go_bits[i+12];
|
||||
//manipulate for crc check
|
||||
mi_bits[i+(j*12)] = mi_go_bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
int mi_final = 0;
|
||||
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF;
|
||||
|
||||
mi_crc_ext = (uint8_t)ConvertBitIntoBytes(&mi_bits[32], 4);
|
||||
mi_crc_cmp = crc4(mi_bits, 32);
|
||||
if (mi_crc_ext == mi_crc_cmp)
|
||||
mi_crc_ok = 1;
|
||||
|
||||
//debug -- working now
|
||||
// fprintf (stderr, " LE MI: %09llX; CRC EXT: %X; CRC CMP: %X; \n", mi_corrected, mi_crc_ext, mi_crc_cmp);
|
||||
|
||||
if (g[0] && g[1] && g[2])
|
||||
{
|
||||
if (slot == 0 && state->payload_algid != 0)
|
||||
@@ -73,8 +106,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
||||
if (state->payload_mi != mi_final)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_mi, mi_final);
|
||||
state->payload_mi = mi_final;
|
||||
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_mi, mi_final);
|
||||
state->payload_mi = mi_final;
|
||||
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
||||
else fprintf (stderr, "(CRC ERR)");
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//run afterwards, or le verification won't match up properly
|
||||
@@ -89,8 +125,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
||||
if (state->payload_miR != mi_final)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_miR, mi_final);
|
||||
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_miR, mi_final);
|
||||
state->payload_miR = mi_final;
|
||||
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
||||
else fprintf (stderr, "(CRC ERR)");
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//run afterwards, or le verification won't match up properly
|
||||
@@ -161,13 +200,24 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t sbrc_interleaved[32];
|
||||
uint8_t sbrc_return[32];
|
||||
uint8_t sbrc_retcrc[32]; //crc significant bits of the return for SB
|
||||
memset (sbrc_interleaved, 0, sizeof(sbrc_interleaved));
|
||||
memset (sbrc_return, 0, sizeof(sbrc_return));
|
||||
memset (sbrc_retcrc, 0, sizeof(sbrc_retcrc));
|
||||
uint32_t irr_err = 0;
|
||||
uint32_t sbrc_hex = 0;
|
||||
uint16_t crc_extracted = 7777;
|
||||
uint16_t crc_computed = 9999;
|
||||
uint8_t crc_okay = 0;
|
||||
uint8_t crc7_okay = 0; //RC
|
||||
uint8_t crc3_okay = 0; //TXI
|
||||
uint8_t txi = 0; //SEE: https://patents.google.com/patent/US8271009B2
|
||||
|
||||
//NOTE: Any previous mentions to Cap+ in this area may have been in error,
|
||||
//The signalling observed here was actually TXI information, not Cap+ Specifically
|
||||
|
||||
//check to see if this a TXI system
|
||||
if (slot == 0 && state->dmr_so & 0x20) txi = 1;
|
||||
if (slot == 1 && state->dmr_soR & 0x20) txi = 1;
|
||||
|
||||
// 9.3.2 Pre-emption and power control Indicator (PI)
|
||||
// 0 - The embedded signalling carries information associated to the same logical channel or the Null embedded message
|
||||
@@ -181,9 +231,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
//bad emb burst, never set a valid power indicator value (probably 9)
|
||||
if (power > 1) goto SBRC_END;
|
||||
|
||||
//arrange the return for proper order for the crc3 check
|
||||
for (i = 0; i < 8; i++) sbrc_retcrc[i] = sbrc_return[i+3];
|
||||
|
||||
//RC Channel CRC 7 Mask = 0x7A; CRC bits are used as privacy indicators on
|
||||
//Single Voice Burst F (see below), other moto values seem to exist there as well
|
||||
//unknown what the other values are (see Cap+ 0x313 and 0x643)
|
||||
//Single Voice Burst F (see below), other moto values seem to exist there as well -- See TXI patent
|
||||
if (power == 1) //RC
|
||||
{
|
||||
crc_extracted = 0;
|
||||
@@ -193,106 +245,152 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
crc_extracted = crc_extracted | sbrc_return[i+4];
|
||||
}
|
||||
crc_extracted = crc_extracted ^ 0x7A;
|
||||
crc_computed = crc7((uint8_t *) sbrc_return, 11);
|
||||
if (crc_extracted == crc_computed) crc_okay = 1;
|
||||
crc_computed = crc7((uint8_t *) sbrc_return, 7);
|
||||
if (crc_extracted == crc_computed) crc7_okay = 1;
|
||||
}
|
||||
else crc_okay = 1; //SB
|
||||
|
||||
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people right now
|
||||
else //if (txi == 1) //if TXI -- but TXI systems also carry the non-crc protected ENC identifiers
|
||||
{
|
||||
fprintf (stderr, "\n %s", KCYN);
|
||||
crc_extracted = 0;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
crc_extracted = crc_extracted << 1;
|
||||
crc_extracted = crc_extracted | sbrc_return[i]; //first 3 most significant bits
|
||||
}
|
||||
crc_computed = crc3((uint8_t *) sbrc_retcrc, 8); //working now seems consistent as well
|
||||
if (crc_extracted == crc_computed) crc3_okay = 1;
|
||||
// fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
|
||||
}
|
||||
// else //crc_okay = 0; //CRC invalid / not available when is ENC Identifiers (I really hate that)
|
||||
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
sbrc_hex = sbrc_hex << 1;
|
||||
sbrc_hex |= sbrc_return[i] & 1;
|
||||
}
|
||||
|
||||
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
if (power == 0) fprintf (stderr, " SB: ");
|
||||
if (power == 1) fprintf (stderr, " RC: ");
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
sbrc_hex = sbrc_hex << 1;
|
||||
sbrc_hex |= sbrc_return[i] & 1; //sbrc_return
|
||||
fprintf (stderr, "%d", sbrc_return[i]);
|
||||
}
|
||||
fprintf (stderr, " - %03X", sbrc_hex);
|
||||
fprintf (stderr, " - %03X; ", sbrc_hex);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// if (crc_okay == 0) //forego this since the crc can vary or not be used at all
|
||||
// {
|
||||
// fprintf (stderr, "%s", KRED);
|
||||
// fprintf (stderr, " (CRC ERR)");
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
|
||||
// }
|
||||
|
||||
if (crc_okay == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
if (opts->payload == 1) fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
//Disabling the lower portion until this can be completely ironed out
|
||||
|
||||
//sbrc_hex value of 0x313 seems to be some Cap+ Thing,
|
||||
//also observed 0x643 on another cap+ system (site id, status? something?)
|
||||
// uint8_t sbrc_opcode = sbrc_hex;
|
||||
// uint8_t alg = sbrc_hex & 0x7;
|
||||
// uint8_t key = (sbrc_hex >> 3) & 0xFF;
|
||||
uint8_t sbrc_opcode = sbrc_hex & 0x7; //opcode and alg the same bits, but the alg is present when CRC is bad (I know they are limited on bits, but I hate that idea)
|
||||
uint8_t alg = sbrc_hex & 0x7; //SEE: https://patents.google.com/patent/EP2347540B1/en
|
||||
uint8_t key = (sbrc_hex >> 3) & 0xFF;
|
||||
uint8_t txi_delay = (sbrc_hex >> 3) & 0x1F; //middle five are the 'delay' value on a TXI system
|
||||
|
||||
//this pattern seems to fit the multiple cap+ systems I've observed
|
||||
//test on site '7' to make sure (works on 1 and 4)
|
||||
// uint8_t cap_site = (sbrc_hex >> 4) & 0x7;
|
||||
//Note: AES-256 Key 1 will pass a CRC3 due to its bit arrangement vs the CRC poly 1101
|
||||
// if (irr_err == 0 && sbrc_hex = 0xD) crc3_okay = 0; //SB: 00000001101
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// if (irr_err != 0) fprintf (stderr, "%s (FEC ERR) %d %s", KRED, irr_err, KNRM);
|
||||
// if (irr_err == 0)
|
||||
// {
|
||||
// if (sbrc_hex == 0) ; //NULL
|
||||
// else if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0)
|
||||
// {
|
||||
// //Cap+ Site ID seems to fit here on samples I've seen with the alternate SB signalling, but no idea what signals that info and not the emb alg/key info
|
||||
// fprintf (stderr, "%s ", KYEL);
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, " Capacity Plus Site %d", cap_site);
|
||||
// fprintf (stderr, "%s ", KNRM);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
//NOTE: on above, I belive that we need to check by opcode as well, as a CRC3 can have multiple collisions
|
||||
//so we need to exclude op/alg 0 and 3 from the check (does algID 0x03/0x23 even exist?)
|
||||
|
||||
// if (slot == 0)
|
||||
// {
|
||||
// //key and alg only present SOME times, not all,
|
||||
// //also, intermixed with other signalling
|
||||
// //needs more study first!
|
||||
// if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
|
||||
// {
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s ", KYEL);
|
||||
// fprintf (stderr, "\n Slot 1");
|
||||
// fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
// fprintf (stderr, "%s ", KNRM);
|
||||
// }
|
||||
|
||||
// //needs more study before assignment
|
||||
// // state->payload_keyid = key;
|
||||
// // state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
// }
|
||||
// }
|
||||
if (opts->dmr_le == 1) //this will now require a user to switch it on or off until more testing/figuring can be done
|
||||
{
|
||||
if (irr_err != 0) fprintf (stderr, "\n%s SLOT %d SB/RC (FEC ERR) %d %s \n", KRED, slot, irr_err, KNRM);
|
||||
if (irr_err == 0)
|
||||
{
|
||||
if (sbrc_hex == 0) ; //NULL, do nothing
|
||||
|
||||
// if (slot == 1)
|
||||
// {
|
||||
// if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
|
||||
// {
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s ", KYEL);
|
||||
// fprintf (stderr, "\n Slot 2");
|
||||
// fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
// fprintf (stderr, "%s ", KNRM);
|
||||
// }
|
||||
|
||||
// //needs more study before assignment
|
||||
// // state->payload_keyidR = key;
|
||||
// // state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
// }
|
||||
// }
|
||||
//else if (placeholder for future conditions)
|
||||
// {
|
||||
// placeholder for future conditions
|
||||
// }
|
||||
|
||||
// }
|
||||
else if (crc7_okay == 1)
|
||||
{
|
||||
//do something with the reverse channel information
|
||||
}
|
||||
|
||||
// }
|
||||
// }
|
||||
//if the call is interruptable (TXI) and the crc3 is okay and TXI Opcode
|
||||
else if (crc3_okay == 1 && (sbrc_opcode == 0 || sbrc_opcode == 3) )
|
||||
{
|
||||
//opcodes -- 0 (NULL), BR Delay (3)
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " TXI Op: %X -", sbrc_opcode);
|
||||
if (sbrc_opcode == 0) fprintf (stderr, " Null; ");
|
||||
else if (sbrc_opcode == 3)
|
||||
{
|
||||
if (txi_delay != 0)
|
||||
fprintf (stderr, " BR Delay: %d - %d ms;", txi_delay, txi_delay * 30); //could also indicate number of superframes until next VC6 pre-emption
|
||||
else fprintf (stderr, "BR Delay: Irrelevant / Send at any time;");
|
||||
|
||||
//alignment of inbound backwards channel and outbound burst
|
||||
if (txi_delay == 2) fprintf (stderr, " SF3, Burst E;"); //E is inbound
|
||||
if (txi_delay == 4) fprintf (stderr, " SF3, Burst D;"); //D is inbound
|
||||
if (txi_delay == 6) fprintf (stderr, " SF3, Burst C;"); //C is inbound
|
||||
if (txi_delay == 8) fprintf (stderr, " SF3, Burst B;"); //B is inbound
|
||||
}
|
||||
else fprintf (stderr, " Unk; ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //only during payload
|
||||
|
||||
}
|
||||
|
||||
else if (sbrc_opcode != 0 && sbrc_opcode != 3) //all that should be left in this field is the potential ENC identifiers
|
||||
{
|
||||
|
||||
if (slot == 0) //may not need the state->errs anymore //&& state->errs < 3
|
||||
{
|
||||
if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
|
||||
{
|
||||
//if we aren't forcing a particular alg or privacy key set
|
||||
if (state->M == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Slot 1");
|
||||
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||
state->payload_keyid = key;
|
||||
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == 1) //may not need the state->errs anymore //&& state->errsR < 3
|
||||
{
|
||||
if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
|
||||
{
|
||||
//if we aren't forcing a particular alg or privacy key set
|
||||
if (state->M == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Slot 2");
|
||||
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||
state->payload_keyidR = key;
|
||||
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
SBRC_END:
|
||||
|
||||
@@ -314,3 +412,50 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
|
||||
}
|
||||
|
||||
uint8_t crc3(uint8_t bits[], unsigned int len)
|
||||
{
|
||||
uint8_t crc=0;
|
||||
unsigned int K = 3;
|
||||
//x^3+x+1
|
||||
uint8_t poly[4] = {1,1,0,1};
|
||||
uint8_t buf[256];
|
||||
if (len+K > sizeof(buf)) {
|
||||
return 0;
|
||||
}
|
||||
memset (buf, 0, sizeof(buf));
|
||||
for (unsigned int i=0; i<len; i++){
|
||||
buf[i] = bits[i];
|
||||
}
|
||||
for (unsigned int i=0; i<len; i++)
|
||||
if (buf[i])
|
||||
for (unsigned int j=0; j<K+1; j++)
|
||||
buf[i+j] ^= poly[j];
|
||||
for (unsigned int i=0; i<K; i++){
|
||||
crc = (crc << 1) + buf[len + i];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint8_t crc4(uint8_t bits[], unsigned int len)
|
||||
{
|
||||
uint8_t crc=0;
|
||||
unsigned int K = 4;
|
||||
//x^4+x+1
|
||||
uint8_t poly[5] = {1,0,0,1,1};
|
||||
uint8_t buf[256];
|
||||
if (len+K > sizeof(buf)) {
|
||||
return 0;
|
||||
}
|
||||
memset (buf, 0, sizeof(buf));
|
||||
for (unsigned int i=0; i<len; i++){
|
||||
buf[i] = bits[i];
|
||||
}
|
||||
for (unsigned int i=0; i<len; i++)
|
||||
if (buf[i])
|
||||
for (unsigned int j=0; j<K+1; j++)
|
||||
buf[i+j] ^= poly[j];
|
||||
for (unsigned int i=0; i<K; i++){
|
||||
crc = (crc << 1) + buf[len + i];
|
||||
}
|
||||
return crc ^ 0xF; //invert
|
||||
}
|
||||
|
||||
12
src/dmr_ms.c
12
src/dmr_ms.c
@@ -87,7 +87,11 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
//so getDibit doesn't know to invert it before it gets here
|
||||
|
||||
for (j = 0; j < 6; j++) {
|
||||
state->dmrburstL = 16;
|
||||
state->dmrburstL = 16;
|
||||
|
||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -370,7 +374,11 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
char ambe_fr4[4][24]; //shim for crappy tdma direct, need more samples to see if this is really a necessary shim or not
|
||||
char ambe_fr4[4][24];
|
||||
|
||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||
|
||||
//memcpy of ambe_fr for late entry
|
||||
char m1[4][24];
|
||||
|
||||
16
src/dmr_pi.c
16
src/dmr_pi.c
@@ -26,6 +26,14 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 1");
|
||||
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||||
|
||||
//Anytone RC4 Shim
|
||||
if (state->payload_algid == 0x01)
|
||||
{
|
||||
fprintf (stderr, " Anytone (0x01)");
|
||||
state->payload_algid = 0x21;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
if (state->payload_algid != 0x21)
|
||||
{
|
||||
@@ -53,6 +61,14 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 2");
|
||||
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
||||
|
||||
//Anytone RC4 Shim
|
||||
if (state->payload_algidR == 0x01)
|
||||
{
|
||||
fprintf (stderr, " Anytone (0x01)");
|
||||
state->payload_algidR = 0x21;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
if (state->payload_algidR != 0x21)
|
||||
{
|
||||
|
||||
@@ -26,9 +26,11 @@ void closePulseOutput (dsd_opts * opts)
|
||||
{
|
||||
pa_simple_free (opts->pulse_digi_dev_out);
|
||||
if (opts->dmr_stereo == 1)
|
||||
{
|
||||
pa_simple_free (opts->pulse_digi_dev_outR);
|
||||
}
|
||||
|
||||
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) //EDACS analog calls and/or monitoring source analog audio
|
||||
pa_simple_free (opts->pulse_raw_dev_out);
|
||||
|
||||
}
|
||||
|
||||
void closePulseInput (dsd_opts * opts)
|
||||
@@ -47,10 +49,9 @@ void openPulseOutput(dsd_opts * opts)
|
||||
tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
|
||||
tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
|
||||
|
||||
if (opts->monitor_input_audio == 1)
|
||||
{
|
||||
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL);
|
||||
}
|
||||
//reconfigured to open when using edacs or raw analog monitor so we can have a analog audio out that runs at 48k1 and not 8k1 float/short
|
||||
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
|
||||
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Analog", &ss, 0, NULL, NULL);
|
||||
|
||||
//tt
|
||||
pa_channel_map* left = 0; //NULL and 0 are same in this context
|
||||
@@ -600,7 +601,15 @@ openAudioInDevice (dsd_opts * opts)
|
||||
}
|
||||
else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
opts->audio_in_type = 3;
|
||||
#elif AERO_BUILD
|
||||
opts->audio_in_type = 5;
|
||||
sprintf (opts->audio_in_dev, "/dev/dsp");
|
||||
#else
|
||||
opts->audio_in_type = 0;
|
||||
sprintf (opts->audio_in_dev, "pulse");
|
||||
#endif
|
||||
}
|
||||
else if(strncmp(opts->audio_in_dev, "pulse", 5) == 0)
|
||||
{
|
||||
@@ -629,6 +638,47 @@ openAudioInDevice (dsd_opts * opts)
|
||||
}
|
||||
}
|
||||
|
||||
//test .rrc files with hardset wav file settings
|
||||
else if (strncmp(extension, ".rrc", 3) == 0)
|
||||
{
|
||||
//debug
|
||||
fprintf (stderr, "Opening M17 .rrc headless wav file\n");
|
||||
|
||||
opts->audio_in_type = 2;
|
||||
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
||||
opts->audio_in_file_info->samplerate = 48000;
|
||||
opts->audio_in_file_info->channels = 1;
|
||||
opts->audio_in_file_info->seekable = 0;
|
||||
opts->audio_in_file_info->format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
|
||||
|
||||
if(opts->audio_in_file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error, couldn't open %s with libsndfile: %s\n", opts->audio_in_dev, sf_strerror(NULL));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: test .sym files as symbol capture .bin files
|
||||
else if (strncmp(extension, ".sym", 3) == 0)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||||
{
|
||||
fprintf (stderr,"Error, couldn't open bin file %s\n", opts->audio_in_dev);
|
||||
exit(1);
|
||||
}
|
||||
if (S_ISREG(stat_buf.st_mode))
|
||||
{
|
||||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||||
opts->audio_in_type = 4; //symbol capture bin files
|
||||
}
|
||||
else
|
||||
{
|
||||
opts->audio_in_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if (strncmp(extension, ".bin", 3) == 0)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
|
||||
@@ -265,30 +265,33 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||
|
||||
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) ||
|
||||
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) ||
|
||||
(state->synctype == 17) || (state->synctype == 29) || (state->synctype == 36) )
|
||||
(state->synctype == 17) || (state->synctype == 29) || (state->synctype == 31) ||
|
||||
(state->synctype == 36) || (state->synctype == 99) )
|
||||
|
||||
{
|
||||
// 1 -P25p1
|
||||
// 3 -X2-TDMA (inverted signal voice frame)
|
||||
// 5 -X2-TDMA (inverted signal data frame)
|
||||
// 9 -NXDN (inverted voice frame)
|
||||
// 9 -M17 LSR
|
||||
// 11 -DMR (inverted signal voice frame)
|
||||
// 13 -DMR (inverted signal data frame)
|
||||
// 17 -NXDN (inverted data frame)
|
||||
// 17 -M17 STR
|
||||
// 29 -NXDN (inverted FSW)
|
||||
// 31 -YSF
|
||||
// 36 -P25p2
|
||||
// 99 -M17 Preamble
|
||||
|
||||
int valid;
|
||||
int dibit;
|
||||
|
||||
valid = 0;
|
||||
|
||||
//disabling again, causing issues with trunking P25
|
||||
if (state->synctype == 1 && opts->p25_trunk == 1)
|
||||
{
|
||||
// Use the P25 heuristics if available
|
||||
// valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
||||
if (state->synctype == 1 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
||||
{
|
||||
// Use the P25p1 heuristics if available
|
||||
valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
|
||||
if (valid == 0)
|
||||
{
|
||||
@@ -335,24 +338,26 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||
// 0 +P25p1
|
||||
// 2 +X2-TDMA (non inverted signal data frame)
|
||||
// 4 +X2-TDMA (non inverted signal voice frame)
|
||||
// 8 +NXDN (non inverted voice frame)
|
||||
// 8 +M17 LSF
|
||||
// 10 +DMR (non inverted signal data frame)
|
||||
// 12 +DMR (non inverted signal voice frame)
|
||||
// 16 +NXDN (non inverted data frame)
|
||||
// 16 +M17 STR
|
||||
// 28 +NXND (FSW)
|
||||
// 30 +YSF
|
||||
// 35 +p25p2
|
||||
// 98 +M17 Preamble
|
||||
|
||||
int valid;
|
||||
int dibit;
|
||||
|
||||
valid = 0;
|
||||
|
||||
//disabling again, causing issues with trunking P25
|
||||
if (state->synctype == 0 && opts->p25_trunk == 1)
|
||||
{
|
||||
// Use the P25 heuristics if available
|
||||
// valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
||||
if (state->synctype == 0 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
||||
{
|
||||
// Use the P25p1 heuristics if available
|
||||
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
|
||||
if (valid == 0)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,11 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
|
||||
}
|
||||
|
||||
char * getDateF(void) {
|
||||
char datename[80]; //32-bit needs this to be 80
|
||||
#ifdef AERO_BUILD
|
||||
char datename[80];
|
||||
#else
|
||||
char datename[99];
|
||||
#endif
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
|
||||
@@ -1,8 +1,36 @@
|
||||
//M17 Filter -- RRC Alpha = 0.5 S/s 48000 with 81 taps
|
||||
#define M17ZEROS 80 //ONLY SEE 79 THOUGH
|
||||
float m17gain = 10.0f;
|
||||
static float m17xv[M17ZEROS+1];
|
||||
float m17coeffs[81] =
|
||||
{
|
||||
-0.009265784007800534, -0.006136551625729697, -0.001125978562075172, 0.004891777252042491,
|
||||
0.01071805138282269, 0.01505751553351295, 0.01679337935001369, 0.015256245142156299,
|
||||
0.01042830577908502, 0.003031522725559901, -0.0055333532968188165, -0.013403099825723372,
|
||||
-0.018598682349642525, -0.01944761739590459, -0.015005271935951746, -0.0053887880354343935,
|
||||
0.008056525910253532, 0.022816244158307273, 0.035513467692208076, 0.04244131815783876,
|
||||
0.04025481153629372, 0.02671818654865632, 0.0013810216516704976, -0.03394615682795165,
|
||||
-0.07502635967975885, -0.11540977897637611, -0.14703962203941534, -0.16119995609538576,
|
||||
-0.14969512896336504, -0.10610329539459686, -0.026921412469634916, 0.08757875030779196,
|
||||
0.23293327870303457, 0.4006012210123992, 0.5786324696325503, 0.7528286479934068,
|
||||
0.908262741447522, 1.0309661131633199, 1.1095611856548013, 1.1366197723675815,
|
||||
1.1095611856548013, 1.0309661131633199, 0.908262741447522, 0.7528286479934068,
|
||||
0.5786324696325503, 0.4006012210123992, 0.23293327870303457, 0.08757875030779196,
|
||||
-0.026921412469634916, -0.10610329539459686, -0.14969512896336504, -0.16119995609538576,
|
||||
-0.14703962203941534, -0.11540977897637611, -0.07502635967975885, -0.03394615682795165,
|
||||
0.0013810216516704976, 0.02671818654865632, 0.04025481153629372, 0.04244131815783876,
|
||||
0.035513467692208076, 0.022816244158307273, 0.008056525910253532, -0.0053887880354343935,
|
||||
-0.015005271935951746, -0.01944761739590459, -0.018598682349642525, -0.013403099825723372,
|
||||
-0.0055333532968188165, 0.003031522725559901, 0.01042830577908502, 0.015256245142156299,
|
||||
0.01679337935001369, 0.01505751553351295, 0.01071805138282269, 0.004891777252042491,
|
||||
-0.001125978562075172, -0.006136551625729697, -0.009265784007800534
|
||||
};
|
||||
|
||||
// Original DMR filter
|
||||
#define NZEROS 60
|
||||
float ngain = 7.423339364f;
|
||||
static float xv[NZEROS+1];
|
||||
float xcoeffs[] =
|
||||
float xcoeffs[61] =
|
||||
{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f,
|
||||
-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f,
|
||||
+0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f,
|
||||
@@ -27,7 +55,7 @@ float xcoeffs[] =
|
||||
float nxgain = 15.95930463f;
|
||||
static float nxv[NXZEROS+1];
|
||||
|
||||
float nxcoeffs[] =
|
||||
float nxcoeffs[135] =
|
||||
{ +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f,
|
||||
+0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f,
|
||||
-0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f,
|
||||
@@ -74,7 +102,7 @@ const float dmrgain = 6.82973073748f;
|
||||
static float dxv[DMRNZEROS+1];
|
||||
|
||||
// DMR filter F4EXB - root raised cosine alpha=0.7 Ts = 6650 S/s Fc = 48kHz
|
||||
const float dmrcoeffs[] =
|
||||
const float dmrcoeffs[61] =
|
||||
{0.0301506278, 0.0269200615, 0.0159662432, -0.0013114705, -0.0216605133,
|
||||
-0.0404938748, -0.0528141756, -0.0543747957, -0.0428325003, -0.0186176083,
|
||||
0.0147202645, 0.0508418571, 0.0816392577, 0.0988113688, 0.0957187780,
|
||||
@@ -98,7 +126,7 @@ static float dpmrxv[NXZEROS+1];
|
||||
const float dpmrgain = 14.6083498224f;
|
||||
|
||||
// dPMR filter - root raised cosine alpha=0.2 Ts = 3325 S/s Fc = 48 kHz - zero at boundaries appears to be slightly better
|
||||
const float dpmrcoeffs[] =
|
||||
const float dpmrcoeffs[135] =
|
||||
{-0.0000983004, 0.0058388841, 0.0119748846, 0.0179185547, 0.0232592816,
|
||||
0.0275919612, 0.0305433586, 0.0317982965, 0.0311240307,
|
||||
0.0283911865, 0.0235897433, 0.0168387650, 0.0083888763,
|
||||
@@ -156,6 +184,11 @@ dpmr_filter(short sample)
|
||||
return dsd_input_filter(sample, 4);
|
||||
}
|
||||
|
||||
short m17_filter (short sample)
|
||||
{
|
||||
return dsd_input_filter(sample, 5);
|
||||
}
|
||||
|
||||
|
||||
short
|
||||
dsd_input_filter(short sample, int mode)
|
||||
@@ -189,6 +222,14 @@ dsd_input_filter(short sample, int mode)
|
||||
coeffs = (float *)dpmrcoeffs;
|
||||
zeros = DPMRNZEROS;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
gain = m17gain;
|
||||
v = m17xv;
|
||||
coeffs = (float *)m17coeffs;
|
||||
zeros = M17ZEROS;
|
||||
break;
|
||||
|
||||
default:
|
||||
return sample;
|
||||
}
|
||||
|
||||
@@ -177,19 +177,19 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
|
||||
if (opts->dmr_stereo == 0 && state->synctype < 32)
|
||||
{
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
dmrMSBootstrap (opts, state);
|
||||
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_mono == 1 && state->synctype == 32)
|
||||
{
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
dmrMSBootstrap (opts, state);
|
||||
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
||||
{
|
||||
@@ -198,7 +198,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
|
||||
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
|
||||
}
|
||||
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
|
||||
}
|
||||
@@ -207,7 +207,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
dmrMSData (opts, state);
|
||||
if (opts->p25_trunk == 0) dmrMSData (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -219,7 +219,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
state->payload_miP = 0; //zero out when switching back to data sync
|
||||
dmr_data_sync (opts, state);
|
||||
}
|
||||
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
|
||||
@@ -231,7 +230,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_stereo = 0; //set the state to zero for handling pure data frames
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
state->payload_miP = 0; //zero out when switching back to data sync
|
||||
dmr_data_sync (opts, state);
|
||||
}
|
||||
}
|
||||
@@ -290,16 +288,21 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
//ysf
|
||||
else if ((state->synctype == 30) || (state->synctype == 31))
|
||||
{
|
||||
//Do stuff
|
||||
//fprintf(stderr, "YSF Sync! \n");
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
//openMbeOutFile (opts, state);
|
||||
}
|
||||
//sprintf(state->fsubtype, " VOICE ");
|
||||
//relocate MBEout to inside frame handling -- Not Working Currently for YSF
|
||||
processYSF(opts, state);
|
||||
return;
|
||||
}
|
||||
//M17
|
||||
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) || (state->synctype == 99) || (state->synctype == 98))
|
||||
{
|
||||
if (state->synctype == 98 || state->synctype == 99) //preamble only
|
||||
skipDibit(opts, state, 8); //skip dibits to prime the demodulator
|
||||
else if (state->synctype == 16 || state->synctype == 17)
|
||||
processM17STR(opts, state);
|
||||
else
|
||||
processM17LSF(opts, state);
|
||||
return;
|
||||
}
|
||||
//P25 P2
|
||||
else if ((state->synctype == 35) || (state->synctype == 36))
|
||||
{
|
||||
|
||||
@@ -18,39 +18,6 @@
|
||||
#include "dsd.h"
|
||||
#include <locale.h>
|
||||
|
||||
//borrowed from LEH/DSDcc for 'improved NXDN sync detection'
|
||||
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr)
|
||||
{
|
||||
|
||||
int Compare = -1;
|
||||
size_t i = 0;
|
||||
int err = 0;
|
||||
int BreakBeforeEnd = 0;
|
||||
|
||||
if(s1 && s2)
|
||||
{
|
||||
for(i = 0; i < size; i++)
|
||||
{
|
||||
if(((s1[i] & 0xFF) != '\0') && ((s2[i] & 0xFF) != '\0'))
|
||||
{
|
||||
if((s1[i] & 0xFF) != (s2[i] & 0xFF)) err++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BreakBeforeEnd = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if((err <= MaxErr) && (BreakBeforeEnd == 0))
|
||||
{
|
||||
Compare = 0;
|
||||
}
|
||||
} /* End if(s1 && s2) */
|
||||
|
||||
return Compare;
|
||||
} /* End strncmperr() */
|
||||
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
@@ -67,7 +34,11 @@ char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
}
|
||||
|
||||
char * getDate(void) {
|
||||
char datename[32];
|
||||
#ifdef AERO_BUILD
|
||||
char datename[80];
|
||||
#else
|
||||
char datename[99];
|
||||
#endif
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
@@ -114,16 +85,16 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
* 5 = -X2-TDMA (inverted signal data frame)
|
||||
* 6 = +D-STAR
|
||||
* 7 = -D-STAR
|
||||
* 8 = +NXDN (non inverted voice frame)
|
||||
* 9 = -NXDN (inverted voice frame)
|
||||
* 8 = +M17 STR (non inverted stream frame)
|
||||
* 9 = -M17 STR (inverted stream frame)
|
||||
* 10 = +DMR (non inverted signal data frame)
|
||||
* 11 = -DMR (inverted signal voice frame)
|
||||
* 12 = +DMR (non inverted signal voice frame)
|
||||
* 13 = -DMR (inverted signal data frame)
|
||||
* 14 = +ProVoice
|
||||
* 15 = -ProVoice
|
||||
* 16 = +NXDN (non inverted data frame)
|
||||
* 17 = -NXDN (inverted data frame)
|
||||
* 16 = +M17 LSF (non inverted link frame)
|
||||
* 17 = -M17 LSF (inverted link frame)
|
||||
* 18 = +D-STAR_HD
|
||||
* 19 = -D-STAR_HD
|
||||
* 20 = +dPMR Frame Sync 1
|
||||
@@ -189,10 +160,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
}
|
||||
//rtludp
|
||||
//rtl
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
#endif
|
||||
}
|
||||
|
||||
fprintf (stderr, "Tuning to Frequency: %.06lf MHz\n",
|
||||
@@ -207,12 +180,13 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
char synctest[25];
|
||||
char synctest12[13]; //dPMR
|
||||
char synctest10[11]; //NXDN FSW only
|
||||
char synctest19[20]; //NXDN Preamble + FSW
|
||||
char synctest18[19];
|
||||
char synctest32[33];
|
||||
char synctest20[21]; //YSF
|
||||
char synctest21[22]; //P25 S-OEMI (SACCH)
|
||||
char synctest48[49]; //EDACS
|
||||
char synctest8[9]; //M17
|
||||
char synctest16[17]; //M17 Preamble
|
||||
char modulation[8];
|
||||
char *synctest_p;
|
||||
int symboltest_pos; //symbol test position, match to synctest_pos
|
||||
@@ -226,19 +200,27 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
t_max = 10;
|
||||
}
|
||||
//else if dPMR
|
||||
//dPMR
|
||||
else if (opts->frame_dpmr == 1)
|
||||
{
|
||||
t_max = 12; //based on Frame_Sync_2 pattern
|
||||
}
|
||||
//if Phase 2 (or YSF in future), then only 19
|
||||
else if (state->lastsynctype == 35 || state->lastsynctype == 36) //P2
|
||||
else if (opts->frame_m17 == 1)
|
||||
{
|
||||
t_max = 8;
|
||||
}
|
||||
else if (state->lastsynctype == 30 || state->lastsynctype == 31 )
|
||||
{
|
||||
t_max = 20; //20 on YSF
|
||||
}
|
||||
//if Phase 2, then only 19
|
||||
else if (state->lastsynctype == 35 || state->lastsynctype == 36 )
|
||||
{
|
||||
t_max = 19; //Phase 2 S-ISCH is only 19
|
||||
}
|
||||
else t_max = 24; //24 for everything else
|
||||
|
||||
int lbuf[t_max], lbuf2[t_max];
|
||||
int lbuf[48], lbuf2[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max
|
||||
int lsum;
|
||||
char spectrum[64];
|
||||
//init the lbuf
|
||||
@@ -446,6 +428,16 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->minref = state->min;
|
||||
}
|
||||
|
||||
|
||||
//if using an rtl input method, do not look for sync patterns if the rms value is lower than our 'soft squelch' level
|
||||
if (opts->audio_in_type == 3 && opts->rtl_rms < opts->rtl_squelch_level)
|
||||
{
|
||||
if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1 || opts->frame_dpmr == 1 || opts->frame_m17 == 1)
|
||||
{
|
||||
goto SYNC_TEST_END;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy (synctest, (synctest_p - 23), 24);
|
||||
if (opts->frame_p25p1 == 1)
|
||||
{
|
||||
@@ -556,51 +548,138 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
//YSF sync
|
||||
strncpy(synctest20, (synctest_p - 19), 20); //double check make sure this is right
|
||||
if(opts->frame_ysf == 1) //(opts->frame_ysf == 1
|
||||
strncpy(synctest20, (synctest_p - 19), 20);
|
||||
if(opts->frame_ysf == 1)
|
||||
{
|
||||
if (0 == 0) //opts->inverted_ysf == 0
|
||||
if (strcmp(synctest20, FUSION_SYNC) == 0)
|
||||
{
|
||||
if (strcmp(synctest20, FUSION_SYNC) == 0)
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
fprintf (stderr, "\nYSF FUSION SYNC \n");
|
||||
opts->inverted_ysf = 0; //should we set this here?
|
||||
state->lastsynctype = 30;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (30);
|
||||
}
|
||||
printFrameSync (opts, state, "+YSF ", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
opts->inverted_ysf = 0;
|
||||
state->lastsynctype = 30;
|
||||
return (30);
|
||||
}
|
||||
}
|
||||
if(opts->frame_ysf == 1) //(opts->frame_ysf == 1
|
||||
{
|
||||
if (0 == 0) //opts->inverted_ysf == 1
|
||||
else if (strcmp(synctest20, INV_FUSION_SYNC) == 0)
|
||||
{
|
||||
if (strcmp(synctest20, INV_FUSION_SYNC) == 0)
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
fprintf (stderr, "\nINVERTED YSF FUSION SYNC \n");
|
||||
opts->inverted_ysf = 1; //should we set this here?
|
||||
state->lastsynctype = 31;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (31);
|
||||
}
|
||||
printFrameSync (opts, state, "-YSF ", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
opts->inverted_ysf = 1;
|
||||
state->lastsynctype = 31;
|
||||
return (31);
|
||||
}
|
||||
}
|
||||
//end YSF sync
|
||||
|
||||
//M17 Sync -- Just STR and LSF for now
|
||||
strncpy(synctest16, (synctest_p - 15), 16);
|
||||
strncpy(synctest8, (synctest_p - 7), 8);
|
||||
if(opts->frame_m17 == 1)
|
||||
{
|
||||
//preambles will skip dibits in an attempt to prime the
|
||||
//demodulator but not attempt any decoding
|
||||
if (strcmp(synctest8, M17_PRE) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 PREAMBLE", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 98;
|
||||
fprintf (stderr, "\n");
|
||||
return (98);
|
||||
}
|
||||
}
|
||||
else if (strcmp(synctest8, M17_PIV) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "-M17 PREAMBLE", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 99;
|
||||
fprintf (stderr, "\n");
|
||||
return (99);
|
||||
}
|
||||
}
|
||||
else if (strcmp(synctest8, M17_STR) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 16 || state->lastsynctype == 8)
|
||||
{
|
||||
state->lastsynctype = 16;
|
||||
return (16);
|
||||
}
|
||||
state->lastsynctype = 16;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printFrameSync (opts, state, "-M17 LSF", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 99)
|
||||
{
|
||||
state->lastsynctype = 9;
|
||||
return (9);
|
||||
}
|
||||
state->lastsynctype = 9;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(synctest8, M17_LSF) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "-M17 STR", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 17 || state->lastsynctype == 9)
|
||||
{
|
||||
state->lastsynctype = 17;
|
||||
return (17);
|
||||
}
|
||||
state->lastsynctype = 17;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 LSF", synctest_pos + 1, modulation);
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->lastsynctype == 98)
|
||||
{
|
||||
state->lastsynctype = 8;
|
||||
return (8);
|
||||
}
|
||||
state->lastsynctype = 8;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
//end M17
|
||||
|
||||
//P25 P2 sync S-ISCH VCH
|
||||
strncpy(synctest20, (synctest_p - 19), 20);
|
||||
if(opts->frame_p25p2 == 1)
|
||||
@@ -631,10 +710,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, " P2 Missing Parameters ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (35); //35
|
||||
}
|
||||
@@ -670,10 +745,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
state->lastsynctype = 36; //36
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (36); //36
|
||||
}
|
||||
@@ -705,10 +776,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "+dPMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 21;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (21);
|
||||
}
|
||||
if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
|
||||
@@ -741,10 +808,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
state->lastsynctype = 25;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (25);
|
||||
}
|
||||
if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
|
||||
@@ -783,20 +846,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 33; //33
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (33); //33
|
||||
}
|
||||
else //inverted MS voice frame
|
||||
{
|
||||
sprintf(state->ftype, "DMR MS");
|
||||
state->lastsynctype = 32;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (32);
|
||||
}
|
||||
}
|
||||
@@ -823,10 +878,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 34;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (34);
|
||||
}
|
||||
}
|
||||
@@ -852,20 +903,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 32;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (32);
|
||||
}
|
||||
else //inverted MS data frame
|
||||
{
|
||||
sprintf(state->ftype, "DMR MS");
|
||||
state->lastsynctype = 33;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (33);
|
||||
}
|
||||
|
||||
@@ -888,10 +931,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 10;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (10);
|
||||
}
|
||||
@@ -908,10 +947,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 11;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (11); //11
|
||||
}
|
||||
@@ -933,10 +968,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 33;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (33);
|
||||
}
|
||||
@@ -953,10 +984,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 32;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (32);
|
||||
}
|
||||
@@ -978,10 +1005,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 33;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (33);
|
||||
}
|
||||
@@ -998,10 +1021,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 32;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (32);
|
||||
}
|
||||
@@ -1027,10 +1046,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 12;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (12);
|
||||
}
|
||||
@@ -1044,10 +1059,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 13;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (13);
|
||||
}
|
||||
@@ -1073,10 +1084,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 32;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (32); //treat Direct Mode same as MS mode for now
|
||||
}
|
||||
@@ -1113,10 +1120,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 32;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (32);
|
||||
}
|
||||
@@ -1129,10 +1132,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 33;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (33);
|
||||
}
|
||||
@@ -1210,11 +1209,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "+D-STAR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 6;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (6);
|
||||
}
|
||||
if (strcmp (synctest, INV_DSTAR_SYNC) == 0)
|
||||
@@ -1229,11 +1223,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "-D-STAR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 7;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (7);
|
||||
}
|
||||
if (strcmp (synctest, DSTAR_HD) == 0)
|
||||
@@ -1248,11 +1237,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "+D-STAR_HD ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 18;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (18);
|
||||
}
|
||||
if (strcmp (synctest, INV_DSTAR_HD) == 0)
|
||||
@@ -1267,203 +1251,59 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
printFrameSync (opts, state, "-D-STAR_HD ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 19;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (19);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef NXDNTESTSYNC //use experimental sync detection based on multiple factors
|
||||
|
||||
//NXDN FSW sync and handling - testing with more exact syncs patterns
|
||||
//NXDN
|
||||
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
||||
{
|
||||
strncpy (synctest10, (synctest_p - 9), 10); //FSW only
|
||||
strncpy (synctest19, (synctest_p - 18), 19); //Preamble + FSW
|
||||
|
||||
//Using Hard Coded Sync Strings with variations for the areas where the symbol
|
||||
//error will occur due to the demodulation issues internally
|
||||
|
||||
//Preamble plus FSW, proceed right away
|
||||
if (
|
||||
|
||||
(strcmp (synctest19, "3131133313131331131") == 0 )
|
||||
|| (strcmp (synctest19, "3131133313331331131") == 0 )
|
||||
|| (strcmp (synctest19, "3131133313131331111") == 0 )
|
||||
|| (strcmp (synctest19, "3131133313331331111") == 0 )
|
||||
|
||||
if (
|
||||
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|
||||
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|
||||
|| (strcmp (synctest10, "3131331111") == 0 )
|
||||
|| (strcmp (synctest10, "3331331111") == 0 )
|
||||
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->lastsynctype = 28;
|
||||
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n +PANDF ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest19);
|
||||
return (28);
|
||||
}
|
||||
else if (
|
||||
|
||||
(strcmp (synctest19, "1313311133131331131") == 0 )
|
||||
|| (strcmp (synctest19, "1313311133331331131") == 0 )
|
||||
|| (strcmp (synctest19, "1313311133131331111") == 0 )
|
||||
|| (strcmp (synctest19, "1313311133331331111") == 0 )
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->lastsynctype = 29;
|
||||
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n -PANDF ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest19);
|
||||
return (29);
|
||||
}
|
||||
|
||||
else if (
|
||||
(strcmp (synctest10, "3131331131") == 0 )
|
||||
|| (strcmp (synctest10, "3331331131") == 0 )
|
||||
|| (strcmp (synctest10, "3131331111") == 0 )
|
||||
|| (strcmp (synctest10, "3331331111") == 0 )
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
if (state->lastsynctype == 28)
|
||||
{
|
||||
state->lastsynctype = 28;
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n +FSW ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest10);
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (28);
|
||||
}
|
||||
|
||||
state->lastsynctype = 28;
|
||||
|
||||
|
||||
}
|
||||
|
||||
else if (
|
||||
|
||||
(strcmp (synctest10, "1313113313") == 0 )
|
||||
|| (strcmp (synctest10, "1113113313") == 0 )
|
||||
|| (strcmp (synctest10, "1313113333") == 0 )
|
||||
|| (strcmp (synctest10, "1113113333") == 0 )
|
||||
(strcmp (synctest10, "1313113313") == 0 )
|
||||
|| (strcmp (synctest10, "1113113313") == 0 )
|
||||
|| (strcmp (synctest10, "1313113333") == 0 )
|
||||
|| (strcmp (synctest10, "1113113333") == 0 )
|
||||
|| (strcmp (synctest10, "1313133313") == 0 )
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
if (state->lastsynctype == 29)
|
||||
{
|
||||
state->lastsynctype = 29;
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n -FSW ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest10);
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
return (29);
|
||||
}
|
||||
state->lastsynctype = 29;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else //use current 'more stable' NXDN Sync pattern detection
|
||||
|
||||
//NXDN FSW sync and handling - moved to very bottom of sync stack for falsing sanity
|
||||
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
||||
{
|
||||
strncpy (synctest10, (synctest_p - 9), 10); //FSW only
|
||||
strncpy (synctest19, (synctest_p - 18), 19); //Preamble + FSW
|
||||
|
||||
//Preamble plus FSW, proceed right away
|
||||
if ( (strncmperr (synctest19, NXDN_PANDFSW, 19, 1) == 0) )
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 28;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
// if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
||||
// fprintf (stderr, " %s ", synctest19);
|
||||
return (28);
|
||||
}
|
||||
|
||||
else if ( (strncmperr (synctest19, INV_NXDN_PANDFSW, 19, 1) == 0) )
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 29;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
// if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
||||
// fprintf (stderr, " %s ", synctest19);
|
||||
return (29);
|
||||
}
|
||||
|
||||
else if ( (strncmperr (synctest10, NXDN_FSW, 10, 1) == 0) )
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
if (state->lastsynctype == 28)
|
||||
{
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
// if (opts->payload == 1) fprintf (stderr, "FSW ");
|
||||
// fprintf (stderr, " %s ", synctest10);
|
||||
return (28);
|
||||
}
|
||||
state->lastsynctype = 28; //need two consecutive patterns to continue
|
||||
|
||||
}
|
||||
|
||||
else if ( (strncmperr (synctest10, INV_NXDN_FSW, 10, 1) == 0) )
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
if (state->lastsynctype == 29)
|
||||
{
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
// if (opts->payload == 1) fprintf (stderr, "FSW ");
|
||||
// fprintf (stderr, " %s ", synctest10);
|
||||
return (29);
|
||||
}
|
||||
state->lastsynctype = 29; //need two consecutive patterns to continue
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //NXDN Sync Type Selection
|
||||
|
||||
//Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible
|
||||
#ifdef PVCONVENTIONAL
|
||||
if (opts->frame_provoice == 1)
|
||||
@@ -1551,6 +1391,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
#endif //End Provoice Conventional
|
||||
|
||||
SYNC_TEST_END: ; //do nothing
|
||||
|
||||
} // t >= 10
|
||||
|
||||
if (exitflag == 1)
|
||||
@@ -1581,7 +1423,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
if ((opts->errorbars == 1) && (opts->verbose > 1) && (state->carrier == 1))
|
||||
{
|
||||
fprintf (stderr,"Sync: no sync\n");
|
||||
fprintf (stderr,"Press CTRL + C to close.\n");
|
||||
// fprintf (stderr,"Press CTRL + C to close.\n");
|
||||
|
||||
}
|
||||
noCarrier (opts, state);
|
||||
|
||||
@@ -146,7 +146,8 @@ int csvChanImport(dsd_opts * opts, dsd_state * state) //channel map import
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support
|
||||
//Decimal Variant of Key Import
|
||||
int csvKeyImportDec(dsd_opts * opts, dsd_state * state) //multi-key support
|
||||
{
|
||||
char filename[1024] = "filename.csv";
|
||||
sprintf (filename, "%s", opts->key_in_file);
|
||||
@@ -210,3 +211,48 @@ int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Hex Variant of Key Import
|
||||
int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for rc4 keys
|
||||
{
|
||||
char filename[1024] = "filename.csv";
|
||||
sprintf (filename, "%s", opts->key_in_file);
|
||||
char buffer[BSIZE];
|
||||
FILE * fp;
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
printf("Unable to open file '%s'\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
int row_count = 0;
|
||||
int field_count = 0;
|
||||
unsigned long long int keynumber;
|
||||
|
||||
while (fgets(buffer, BSIZE, fp)) {
|
||||
field_count = 0;
|
||||
row_count++;
|
||||
if (row_count == 1)
|
||||
continue; //don't want labels
|
||||
char * field = strtok(buffer, ","); //seperate by comma
|
||||
while (field) {
|
||||
|
||||
if (field_count == 0)
|
||||
{
|
||||
sscanf (field, "%llX", &keynumber);
|
||||
}
|
||||
|
||||
if (field_count == 1)
|
||||
{
|
||||
sscanf (field, "%llX", &state->rkey_array[keynumber]);
|
||||
}
|
||||
|
||||
field = strtok(NULL, ",");
|
||||
field_count++;
|
||||
}
|
||||
fprintf (stderr, "Key [%04llX] [%016llX]", keynumber, state->rkey_array[keynumber]);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
546
src/dsd_main.c
546
src/dsd_main.c
File diff suppressed because it is too large
Load Diff
1251
src/dsd_mbe.c
1251
src/dsd_mbe.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
164
src/dsd_reset.c
164
src/dsd_reset.c
@@ -2,26 +2,59 @@
|
||||
#include "dsd.h"
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
void
|
||||
resetState (dsd_state * state)
|
||||
//fixed the memory leak, but now random segfaults occur -- double free or corruption (out) or (!prev)
|
||||
void resetState (dsd_state * state)
|
||||
{
|
||||
|
||||
int i, j;
|
||||
|
||||
//Dibit Buffer -- Free Allocated Memory
|
||||
// free (state->dibit_buf);
|
||||
|
||||
//Dibit Buffer -- Memset/Init/Allocate Memory
|
||||
// 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->dibit_buf_p = state->dibit_buf + 200;
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
state->repeat = 0; //repeat frame?
|
||||
|
||||
//Audio Buffer -- Free Allocated Memory
|
||||
free (state->audio_out_buf);
|
||||
free (state->audio_out_float_buf);
|
||||
free (state->audio_out_bufR);
|
||||
free (state->audio_out_float_bufR);
|
||||
|
||||
//Audio Buffer -- Memset/Init/Allocate Memory per slot
|
||||
|
||||
//slot 1
|
||||
state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
//slot 2
|
||||
state->audio_out_bufR = malloc (sizeof (short) * 1000000);
|
||||
state->audio_out_float_bufR = malloc (sizeof (float) * 1000000);
|
||||
|
||||
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||||
|
||||
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||
|
||||
state->audio_out_idxR = 0;
|
||||
state->audio_out_idx2R = 0;
|
||||
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
|
||||
|
||||
//Sync
|
||||
state->center = 0;
|
||||
state->jitter = -1;
|
||||
state->synctype = -1;
|
||||
@@ -31,76 +64,73 @@ resetState (dsd_state * state)
|
||||
state->umid = 0;
|
||||
state->minref = -12000;
|
||||
state->maxref = 12000;
|
||||
|
||||
state->lastsample = 0;
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
state->sbuf[i] = 0;
|
||||
}
|
||||
{
|
||||
state->sbuf[i] = 0;
|
||||
}
|
||||
state->sidx = 0;
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
state->maxbuf[i] = 15000;
|
||||
}
|
||||
{
|
||||
state->maxbuf[i] = 15000;
|
||||
}
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
state->minbuf[i] = -15000;
|
||||
}
|
||||
{
|
||||
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;
|
||||
|
||||
//Reset Voice Errors in C0 and C1 (or remaining Codewords in IMBE)
|
||||
state->errs = 0;
|
||||
state->errs2 = 0;
|
||||
state->mbe_file_type = -1;
|
||||
state->errsR = 0;
|
||||
state->errs2R = 0;
|
||||
|
||||
//Misc -- may not be needed
|
||||
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;
|
||||
//unsure if these are still used or ever were used,
|
||||
// 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->nxdn_last_ran = 0;
|
||||
// state->payload_algid = 0;
|
||||
// state->payload_algidR = 0;
|
||||
state->dmr_encL = 0;
|
||||
state->dmr_encR = 0;
|
||||
// //MBE Specific
|
||||
// //free the memory before allocating it again -- may not use this
|
||||
// free (state->cur_mp);
|
||||
// free (state->prev_mp);
|
||||
// free (state->prev_mp_enhanced);
|
||||
|
||||
//each time you run this, it increses memory use by 4MB, massive memory leak
|
||||
//need to revisit this sometime and look into only resetting only the necesary items to let P25 switch between signals (C4FM or Wide) without needing a restart
|
||||
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
|
||||
// //memory allocation and init on mbe -- may not use this
|
||||
// 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);
|
||||
|
||||
//rest the heurestics, we want to do this on each tune, each RF frequency can deviate quite a bit in strength
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||||
}
|
||||
|
||||
//simple function to reset the dibit buffer
|
||||
void reset_dibit_buffer(dsd_state * state)
|
||||
{
|
||||
//Dibit Buffer -- Free Allocated Memory
|
||||
// free (state->dibit_buf);
|
||||
|
||||
//Dibit Buffer -- Memset/Init/Allocate Memory
|
||||
// state->dibit_buf = malloc (sizeof (int) * 1000000);
|
||||
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
}
|
||||
|
||||
@@ -250,6 +250,7 @@ int UDPBind (char *hostname, int portno)
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
//going to leave this function available, even if completely switched over to rtl_dev_tune now, may be useful in the future
|
||||
void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
||||
{
|
||||
int handle;
|
||||
@@ -274,8 +275,5 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
||||
address.sin_port = htons(udp_port);
|
||||
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
||||
|
||||
//BUGFIX: This was causing an indefinite number of UDP sockets to stay open on each tune request
|
||||
//we open a new socket with each request, so we need to close the socket after writing to it
|
||||
//this would cause the tuning to stop after x number of tune attempts (few hours? on a busy system)
|
||||
close (handle); //close socket after sending.
|
||||
}
|
||||
119
src/dsd_symbol.c
119
src/dsd_symbol.c
@@ -17,6 +17,29 @@
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as len
|
||||
{
|
||||
|
||||
int i;
|
||||
long int rms;
|
||||
long p, t, s;
|
||||
double dc, err;
|
||||
|
||||
p = t = 0L;
|
||||
for (i=0; i<len; i+=step) {
|
||||
s = (long)samples[i];
|
||||
t += s;
|
||||
p += s * s;
|
||||
}
|
||||
/* correct for dc offset in squares */
|
||||
dc = (double)(t*step) / (double)len;
|
||||
err = t * 2 * dc - dc * dc * len;
|
||||
|
||||
rms = (long int)sqrt((p-err) / len);
|
||||
if (rms < 0) rms = 150;
|
||||
return rms;
|
||||
}
|
||||
|
||||
int
|
||||
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
@@ -111,7 +134,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
|
||||
sf_close(opts->audio_in_file);
|
||||
fprintf (stderr, "\n\nEnd of .wav file.\n");
|
||||
fprintf (stderr, "\nEnd of %s\n", opts->audio_in_dev);
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
@@ -129,14 +152,9 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
// TODO: need to read demodulated stream here
|
||||
// get_rtlsdr_sample(&sample);
|
||||
// Read demodulated stream here
|
||||
get_rtlsdr_sample(&sample, opts, state);
|
||||
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767)
|
||||
{
|
||||
state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here?
|
||||
pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL);
|
||||
}
|
||||
opts->rtl_rms = rtl_return_rms();
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -246,43 +264,70 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
|
||||
}
|
||||
|
||||
//tcp socket input from SDR++ -- old method to open pulse or quit right away
|
||||
// else if (opts->audio_in_type == 8)
|
||||
// {
|
||||
// result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
// if(result == 0) {
|
||||
//Source Audio Monitoring
|
||||
if (have_sync == 0 && opts->monitor_input_audio == 1)
|
||||
{
|
||||
//sanity check to prevent an overflow
|
||||
if (state->analog_sample_counter > 959)
|
||||
state->analog_sample_counter = 959;
|
||||
|
||||
// fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
// //open pulse input if we are pulse output AND using ncurses terminal
|
||||
// if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
// {
|
||||
// opts->audio_in_type = 0; //set input type
|
||||
// openPulseInput(opts); //open pulse input
|
||||
// }
|
||||
// //else cleanup and exit
|
||||
// else cleanupAndExit(opts, state);
|
||||
|
||||
// }
|
||||
// }
|
||||
state->analog_out[state->analog_sample_counter++] = sample;
|
||||
|
||||
//UDP Socket input...not working correct. Reads samples, but no sync
|
||||
// else if (opts->audio_in_type == 6)
|
||||
// {
|
||||
//I think this doesn't get the entire dgram when we run sf_read_short on the udp dgram
|
||||
// result = sf_read_short(opts->udp_file_in, &sample, 1);
|
||||
// if (sample != 0)
|
||||
// fprintf (stderr, "Result = %d Sample = %d \n", result, sample);
|
||||
// }
|
||||
if (state->analog_sample_counter == 960)
|
||||
{
|
||||
//get an rms value if not using the rtl built in version
|
||||
if (opts->audio_in_type != 3)
|
||||
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
||||
|
||||
//debug
|
||||
// opts->rtl_rms = 101;
|
||||
|
||||
//make it a little quieter
|
||||
for (int x = 0; x < 960; x++)
|
||||
state->analog_out[x] /= 4;
|
||||
|
||||
//seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise
|
||||
if ( opts->rtl_rms > opts->rtl_squelch_level )
|
||||
{
|
||||
if (opts->audio_out_type == 0)
|
||||
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
|
||||
|
||||
//NOTE: Worked okay earlier in Cygwin, so should be fine
|
||||
if (opts->audio_out_type == 5)
|
||||
write (opts->audio_out_fd, state->analog_out, 960*2);
|
||||
|
||||
//test hold on scan/trunking
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
|
||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||
state->analog_sample_counter = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (have_sync == 1 && opts->monitor_input_audio == 1)
|
||||
{
|
||||
//zero out and reset counter
|
||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||
state->analog_sample_counter = 0;
|
||||
}
|
||||
|
||||
if (opts->use_cosine_filter)
|
||||
{
|
||||
if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34)
|
||||
if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33
|
||||
|| state->lastsynctype == 34 || state->lastsynctype == 30 || state->lastsynctype == 31)
|
||||
{
|
||||
sample = dmr_filter(sample);
|
||||
}
|
||||
|
||||
else if (state->lastsynctype == 8 || state->lastsynctype == 9 ||
|
||||
state->lastsynctype == 16 || state->lastsynctype == 17 ||
|
||||
else if (state->lastsynctype == 8 || state->lastsynctype == 9 ||state->lastsynctype == 16 || state->lastsynctype == 17)
|
||||
{
|
||||
sample = m17_filter(sample);
|
||||
}
|
||||
|
||||
else if (
|
||||
state->lastsynctype == 20 || state->lastsynctype == 21 ||
|
||||
state->lastsynctype == 22 || state->lastsynctype == 23 ||
|
||||
state->lastsynctype == 24 || state->lastsynctype == 25 ||
|
||||
@@ -521,7 +566,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
// opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
||||
fclose(opts->symbolfile);
|
||||
fprintf (stderr, "\n\nEnd of .bin file\n");
|
||||
fprintf (stderr, "\nEnd of %s\n", opts->audio_in_dev);
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
|
||||
315
src/edacs-fme.c
315
src/edacs-fme.c
@@ -14,12 +14,16 @@
|
||||
* 1994-7
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-10 Version EDACS-FM Florida Man Edition
|
||||
* 2023-08 Version EDACS-FM Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
#include "dsd.h"
|
||||
|
||||
char * getDateE(void) {
|
||||
char datename[99]; //might honestly just need a much smaller size, and not a larger one
|
||||
#ifdef AERO_BUILD
|
||||
char datename[80];
|
||||
#else
|
||||
char datename[99];
|
||||
#endif
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
@@ -45,6 +49,191 @@ char * getTimeE(void) //get pretty hh:mm:ss timestamp
|
||||
return curr;
|
||||
}
|
||||
|
||||
void openWavOutFile48k (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
SF_INFO info;
|
||||
info.samplerate = 48000; //48k for analog output (has to match input)
|
||||
info.channels = 1;
|
||||
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info);
|
||||
|
||||
if (opts->wav_out_f == NULL)
|
||||
{
|
||||
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//generic rms type function
|
||||
long int gen_rms(short *samples, int len, int step)
|
||||
{
|
||||
|
||||
int i;
|
||||
long int rms;
|
||||
long p, t, s;
|
||||
double dc, err;
|
||||
|
||||
p = t = 0L;
|
||||
for (i=0; i<len; i+=step) {
|
||||
s = (long)samples[i];
|
||||
t += s;
|
||||
p += s * s;
|
||||
}
|
||||
/* correct for dc offset in squares */
|
||||
dc = (double)(t*step) / (double)len;
|
||||
err = t * 2 * dc - dc * dc * len;
|
||||
|
||||
rms = (long int)sqrt((p-err) / len);
|
||||
//make sure it doesnt' randomly feed us a large negative value (overflow?)
|
||||
if (rms < 0) rms = 150; //could also consider returning 0 and making it return the last known good value instead
|
||||
return rms;
|
||||
}
|
||||
|
||||
//listening to and playing back analog audio
|
||||
void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn)
|
||||
{
|
||||
|
||||
int i;
|
||||
short analog1[960];
|
||||
short analog2[960];
|
||||
short analog3[960];
|
||||
short sample = 0;
|
||||
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
|
||||
memset (analog1, 0, sizeof(analog1));
|
||||
memset (analog2, 0, sizeof(analog2));
|
||||
memset (analog3, 0, sizeof(analog3));
|
||||
|
||||
long int rms = opts->rtl_squelch_level + 1; //one more for the initial loop phase
|
||||
long int sql = opts->rtl_squelch_level;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
while (rms > sql) //!exitflag && -- no exitflag on this version
|
||||
{
|
||||
//this will only work on 48k/1 short output
|
||||
if (opts->audio_in_type == 0)
|
||||
{
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
analog1[i] = sample;
|
||||
}
|
||||
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
analog2[i] = sample;
|
||||
}
|
||||
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
analog3[i] = sample;
|
||||
}
|
||||
//this rms will only work properly (for now) with squelch enabled in SDR++ or other
|
||||
rms = gen_rms(analog3, 960, 1);
|
||||
}
|
||||
|
||||
//TCP Input -- TODO: Error Handling if connection drops
|
||||
if (opts->audio_in_type == 8)
|
||||
{
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
analog1[i] = sample;
|
||||
}
|
||||
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
analog2[i] = sample;
|
||||
}
|
||||
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
analog3[i] = sample;
|
||||
}
|
||||
//this rms will only work properly (for now) with squelch enabled in SDR++
|
||||
rms = gen_rms(analog3, 960, 1);
|
||||
}
|
||||
|
||||
//RTL Input
|
||||
#ifdef USE_RTLSDR
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
get_rtlsdr_sample(&sample, opts, state);
|
||||
analog1[i] = sample;
|
||||
}
|
||||
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
get_rtlsdr_sample(&sample, opts, state);
|
||||
analog2[i] = sample;
|
||||
}
|
||||
|
||||
for (i = 0; i < 960; i++)
|
||||
{
|
||||
get_rtlsdr_sample(&sample, opts, state);
|
||||
analog3[i] = sample;
|
||||
}
|
||||
//the rtl rms value works properly without needing a 'hard' squelch value
|
||||
rms = rtl_return_rms();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opts->audio_out_type == 0)
|
||||
{
|
||||
pa_simple_write(opts->pulse_raw_dev_out, analog1, 960*2, NULL);
|
||||
pa_simple_write(opts->pulse_raw_dev_out, analog2, 960*2, NULL);
|
||||
pa_simple_write(opts->pulse_raw_dev_out, analog3, 960*2, NULL);
|
||||
}
|
||||
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
write (opts->audio_out_fd, analog1, 960*2);
|
||||
write (opts->audio_out_fd, analog2, 960*2);
|
||||
write (opts->audio_out_fd, analog3, 960*2);
|
||||
}
|
||||
|
||||
opts->rtl_rms = rms;
|
||||
|
||||
|
||||
printFrameSync (opts, state, " EDACS", 0, "A");
|
||||
|
||||
if (rms < sql) fprintf (stderr, "%s", KRED);
|
||||
else fprintf (stderr, "%s", KGRN);
|
||||
|
||||
fprintf (stderr, " Analog RMS: %04ld SQL: %ld", rms, sql);
|
||||
if (afs != 0)
|
||||
fprintf (stderr, " AFS [0x%03X] [%02d-%03d] LCN [%02d]", afs, afs >> 7, afs & 0x7F, lcn);
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
if (rms > sql) fprintf (stderr, "\n");
|
||||
|
||||
//Update Ncurses Terminal
|
||||
if (opts->use_ncurses_terminal == 1)
|
||||
ncursesPrinter(opts, state);
|
||||
|
||||
//WIP: Write Analog Samples to wav file, easy enough,
|
||||
//but needs wav to be opened as 48k, or downsampled
|
||||
//working on 48k version of openWavOutFile
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
sf_write_short(opts->wav_out_f, analog1, 960);
|
||||
sf_write_short(opts->wav_out_f, analog2, 960);
|
||||
sf_write_short(opts->wav_out_f, analog3, 960);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void edacs(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
//changed to ulli here for 32-bit cygwin (not sure if was an issue, but playing it safe)
|
||||
@@ -64,7 +253,6 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
unsigned char command = 0xFF;
|
||||
unsigned char mt1 = 0x1F;
|
||||
unsigned char mt2 = 0xF;
|
||||
unsigned char mta = 0;
|
||||
unsigned char lcn = 0;
|
||||
|
||||
//commands; may not use these anymore
|
||||
@@ -75,7 +263,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
state->edacs_vc_lcn = -1; //init on negative for ncurses and tuning
|
||||
|
||||
int i, j;
|
||||
int i;
|
||||
int edacs_bit[241] = {0}; //zero out bit array and collect bits into it.
|
||||
|
||||
for (i = 0; i < 240; i++) //288 bits every transmission minus 48 bit (24 dibit) sync pattern
|
||||
@@ -124,32 +312,32 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
//ESK on/off detection, I honestly don't remember the logic for this anymore, but it works fine
|
||||
if ( (((fr_1t & 0xF000000000) >> 36) != 0xB) && (((fr_1t & 0xF000000000) >> 36) != 0x1) && (((fr_1t & 0xFF00000000) >> 32) != 0xF3) )
|
||||
{
|
||||
if ( (((fr_1t & 0xF000000000) >> 36) != 0xB) && (((fr_1t & 0xF000000000) >> 36) != 0x1) && (((fr_1t & 0xFF00000000) >> 32) != 0xF3) )
|
||||
{
|
||||
//experimenting with values here, not too high, and not too low
|
||||
if ( (((fr_1t & 0xF000000000) >> 36) <= 0x8 ))
|
||||
if ( (((fr_1t & 0xF000000000) >> 36) <= 0x8 ))
|
||||
{
|
||||
state->esk_mask = 0xA0;
|
||||
state->esk_mask = 0xA0;
|
||||
}
|
||||
//ideal value would be 5, but some other values exist that don't allow it
|
||||
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
|
||||
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
|
||||
{
|
||||
state->esk_mask = 0x0;
|
||||
state->esk_mask = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Standard/Networked Auto Detection
|
||||
//if (command == netcmd) //netcmd is F3 Standard/Networked (I think)
|
||||
//if (command == netcmd) //netcmd is F3 Standard/Networked (I think)
|
||||
if ( (fr_1t >> 32 == netcmd) || (fr_1t >> 32 == (netcmd ^ 0xA0)) )
|
||||
{
|
||||
state->ea_mode = 0; //disable extended addressing mode
|
||||
}
|
||||
state->ea_mode = 0; //disable extended addressing mode
|
||||
}
|
||||
|
||||
//EA Auto detection //peercmd is 0xF88 peer site relay 0xFF80000000 >> 28
|
||||
if (fr_1t >> 28 == peercmd || fr_1t >> 28 == (peercmd ^ 0xA00) )
|
||||
if (fr_1t >> 28 == peercmd || fr_1t >> 28 == (peercmd ^ 0xA00) )
|
||||
{
|
||||
state->ea_mode = 1; //enable extended addressing mode
|
||||
}
|
||||
state->ea_mode = 1; //enable extended addressing mode
|
||||
}
|
||||
|
||||
//Start Extended Addressing Mode
|
||||
if (state->ea_mode == 1)
|
||||
@@ -284,6 +472,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld TG %d SRC %d.wav", getDateE(), getTimeE(), state->edacs_site_id, group, source);
|
||||
openWavOutFile (opts, state);
|
||||
// openWavOutFile48k (opts, state); //debug for testing analog wav only
|
||||
}
|
||||
|
||||
//do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
|
||||
@@ -292,15 +481,20 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
|
||||
opts->p25_is_tuned = 1;
|
||||
//debug testing (since I don't have EDACS standard w/ Analog nearby)
|
||||
// edacs_analog(opts, state, group, lcn);
|
||||
}
|
||||
|
||||
if (opts->audio_in_type == 3) //rtl dongle
|
||||
{
|
||||
rtl_udp_tune(opts, state, state->trunk_lcn_freq[lcn-1]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
opts->p25_is_tuned = 1;
|
||||
//debug testing (since I don't have EDACS standard w/ Analog nearby)
|
||||
// edacs_analog(opts, state, group, lcn);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -398,44 +592,57 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||
//signal level drops (RMS, or a dotting sequence is detected)
|
||||
|
||||
//analog working now with edacs_analog
|
||||
if (command == 0xEE)
|
||||
{
|
||||
//no handling for raw audio yet...that works properly atleast
|
||||
fprintf (stderr, " Analog");
|
||||
}
|
||||
else //Digital Call (ProVoice, hopefully not Aegis in 2022)
|
||||
{
|
||||
|
||||
//Digital Call (ProVoice, hopefully, and not Aegis in 2022)
|
||||
else
|
||||
fprintf (stderr, " Digital");
|
||||
//this is working now with the new import setup
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
|
||||
//skip analog calls on RTL Input on ARM devices due to High CPU usage from RTL RMS function
|
||||
#ifdef __arm__
|
||||
if (command == 0xEE && opts->audio_in_type == 3)
|
||||
goto ENDPV;
|
||||
#endif
|
||||
|
||||
//this is working now with the new import setup
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||
{
|
||||
if (lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
{
|
||||
if (lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||
//openwav file and do per call right here
|
||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||
{
|
||||
//openwav file and do per call right here
|
||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||
{
|
||||
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld AFS %X.wav", getDateE(), getTimeE(), state->edacs_site_id, afs);
|
||||
openWavOutFile (opts, state);
|
||||
}
|
||||
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
|
||||
if (opts->audio_in_type == 3) //rtl dongle
|
||||
{
|
||||
rtl_udp_tune(opts, state, state->trunk_lcn_freq[lcn-1]);
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
|
||||
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld AFS %02d-%03d - %X.wav", getDateE(), getTimeE(), state->edacs_site_id, a, fs, afs);
|
||||
if (command == 0xEF) openWavOutFile (opts, state); //digital
|
||||
if (command == 0xEE) openWavOutFile48k (opts, state); //analog at 48k
|
||||
}
|
||||
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
|
||||
}
|
||||
|
||||
if (opts->audio_in_type == 3) //rtl dongle
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
@@ -456,7 +663,9 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
} //end Standard or Networked
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ENDPV:
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
|
||||
296
src/ez.cpp
296
src/ez.cpp
@@ -178,146 +178,166 @@ int ez_rs28_sacch (int payload[180], int parity[132])
|
||||
return (ec);
|
||||
}
|
||||
|
||||
//I-ISCH Lookup section, borrowed from OP25
|
||||
std::map <std::string, int> isch_map;
|
||||
std::map <std::uint64_t, int> isch_map;
|
||||
void map_isch()
|
||||
{
|
||||
isch_map["184229d461"] = 0;
|
||||
isch_map["18761451f6"] = 1;
|
||||
isch_map["181ae27e2f"] = 2;
|
||||
isch_map["182edffbb8"] = 3;
|
||||
isch_map["18df8a7510"] = 4;
|
||||
isch_map["18ebb7f087"] = 5;
|
||||
isch_map["188741df5e"] = 6;
|
||||
isch_map["18b37c5ac9"] = 7;
|
||||
isch_map["1146a44f13"] = 8;
|
||||
isch_map["117299ca84"] = 9;
|
||||
isch_map["111e6fe55d"] = 10;
|
||||
isch_map["112a5260ca"] = 11;
|
||||
isch_map["11db07ee62"] = 12;
|
||||
isch_map["11ef3a6bf5"] = 13;
|
||||
isch_map["1183cc442c"] = 14;
|
||||
isch_map["11b7f1c1bb"] = 15;
|
||||
isch_map["1a4a2e239e"] = 16;
|
||||
isch_map["1a7e13a609"] = 17;
|
||||
isch_map["1a12e589d0"] = 18;
|
||||
isch_map["1a26d80c47"] = 19;
|
||||
isch_map["1ad78d82ef"] = 20;
|
||||
isch_map["1ae3b00778"] = 21;
|
||||
isch_map["1a8f4628a1"] = 22;
|
||||
isch_map["1abb7bad36"] = 23;
|
||||
isch_map["134ea3b8ec"] = 24;
|
||||
isch_map["137a9e3d7b"] = 25;
|
||||
isch_map["13166812a2"] = 26;
|
||||
isch_map["1322559735"] = 27;
|
||||
isch_map["13d300199d"] = 28;
|
||||
isch_map["13e73d9c0a"] = 29;
|
||||
isch_map["138bcbb3d3"] = 30;
|
||||
isch_map["13bff63644"] = 31;
|
||||
isch_map["1442f705ef"] = 32;
|
||||
isch_map["1476ca8078"] = 33;
|
||||
isch_map["141a3cafa1"] = 34;
|
||||
isch_map["142e012a36"] = 35;
|
||||
isch_map["14df54a49e"] = 36;
|
||||
isch_map["14eb692109"] = 37;
|
||||
isch_map["14879f0ed0"] = 38;
|
||||
isch_map["14b3a28b47"] = 39;
|
||||
isch_map["1d467a9e9d"] = 40;
|
||||
isch_map["1d72471b0a"] = 41;
|
||||
isch_map["1d1eb134d3"] = 42;
|
||||
isch_map["1d2a8cb144"] = 43;
|
||||
isch_map["1ddbd93fec"] = 44;
|
||||
isch_map["1defe4ba7b"] = 45;
|
||||
isch_map["1d831295a2"] = 46;
|
||||
isch_map["1db72f1035"] = 47;
|
||||
isch_map["164af0f210"] = 48;
|
||||
isch_map["167ecd7787"] = 49;
|
||||
isch_map["16123b585e"] = 50;
|
||||
isch_map["162606ddc9"] = 51;
|
||||
isch_map["16d7535361"] = 52;
|
||||
isch_map["16e36ed6f6"] = 53;
|
||||
isch_map["168f98f92f"] = 54;
|
||||
isch_map["16bba57cb8"] = 55;
|
||||
isch_map["1f4e7d6962"] = 56;
|
||||
isch_map["1f7a40ecf5"] = 57;
|
||||
isch_map["1f16b6c32c"] = 58;
|
||||
isch_map["1f228b46bb"] = 59;
|
||||
isch_map["1fd3dec813"] = 60;
|
||||
isch_map["1fe7e34d84"] = 61;
|
||||
isch_map["1f8b15625d"] = 62;
|
||||
isch_map["1fbf28e7ca"] = 63;
|
||||
isch_map["84d62c339"] = 64;
|
||||
isch_map["8795f46ae"] = 65;
|
||||
isch_map["815a96977"] = 66;
|
||||
isch_map["82194ece0"] = 67;
|
||||
isch_map["8d0c16248"] = 68;
|
||||
isch_map["8e4fce7df"] = 69;
|
||||
isch_map["8880ac806"] = 70;
|
||||
isch_map["8bc374d91"] = 71;
|
||||
isch_map["149ef584b"] = 72;
|
||||
isch_map["17dd2dddc"] = 73;
|
||||
isch_map["11124f205"] = 74;
|
||||
isch_map["125197792"] = 75;
|
||||
isch_map["1d44cf93a"] = 76;
|
||||
isch_map["1e0717cad"] = 77;
|
||||
isch_map["18c875374"] = 78;
|
||||
isch_map["1b8bad6e3"] = 79;
|
||||
isch_map["a456534c6"] = 80;
|
||||
isch_map["a7158b151"] = 81;
|
||||
isch_map["a1dae9e88"] = 82;
|
||||
isch_map["a29931b1f"] = 83;
|
||||
isch_map["ad8c695b7"] = 84;
|
||||
isch_map["aecfb1020"] = 85;
|
||||
isch_map["a800d3ff9"] = 86;
|
||||
isch_map["ab430ba6e"] = 87;
|
||||
isch_map["341e8afb4"] = 88;
|
||||
isch_map["375d52a23"] = 89;
|
||||
isch_map["3192305fa"] = 90;
|
||||
isch_map["32d1e806d"] = 91;
|
||||
isch_map["3dc4b0ec5"] = 92;
|
||||
isch_map["3e8768b52"] = 93;
|
||||
isch_map["38480a48b"] = 94;
|
||||
isch_map["3b0bd211c"] = 95;
|
||||
isch_map["44dbc12b7"] = 96;
|
||||
isch_map["479819720"] = 97;
|
||||
isch_map["41577b8f9"] = 98;
|
||||
isch_map["4214a3d6e"] = 99;
|
||||
isch_map["4d01fb3c6"] = 100;
|
||||
isch_map["4e4223651"] = 101;
|
||||
isch_map["488d41988"] = 102;
|
||||
isch_map["4bce99c1f"] = 103;
|
||||
isch_map["d493189c5"] = 104;
|
||||
isch_map["d7d0c0c52"] = 105;
|
||||
isch_map["d11fa238b"] = 106;
|
||||
isch_map["d25c7a61c"] = 107;
|
||||
isch_map["dd49228b4"] = 108;
|
||||
isch_map["de0afad23"] = 109;
|
||||
isch_map["d8c5982fa"] = 110;
|
||||
isch_map["db864076d"] = 111;
|
||||
isch_map["645bbe548"] = 112;
|
||||
isch_map["6718660df"] = 113;
|
||||
isch_map["61d704f06"] = 114;
|
||||
isch_map["6294dca91"] = 115;
|
||||
isch_map["6d8184439"] = 116;
|
||||
isch_map["6ec25c1ae"] = 117;
|
||||
isch_map["680d3ee77"] = 118;
|
||||
isch_map["6b4ee6be0"] = 119;
|
||||
isch_map["f41367e3a"] = 120;
|
||||
isch_map["f750bfbad"] = 121;
|
||||
isch_map["f19fdd474"] = 122;
|
||||
isch_map["f2dc051e3"] = 123;
|
||||
isch_map["fdc95df4b"] = 124;
|
||||
isch_map["fe8a85adc"] = 125;
|
||||
isch_map["f845e7505"] = 126;
|
||||
isch_map["fb063f092"] = 127;
|
||||
isch_map[0x184229d461ULL] = 0;
|
||||
isch_map[0x18761451f6ULL] = 1;
|
||||
isch_map[0x181ae27e2fULL] = 2;
|
||||
isch_map[0x182edffbb8ULL] = 3;
|
||||
isch_map[0x18df8a7510ULL] = 4;
|
||||
isch_map[0x18ebb7f087ULL] = 5;
|
||||
isch_map[0x188741df5eULL] = 6;
|
||||
isch_map[0x18b37c5ac9ULL] = 7;
|
||||
isch_map[0x1146a44f13ULL] = 8;
|
||||
isch_map[0x117299ca84ULL] = 9;
|
||||
isch_map[0x111e6fe55dULL] = 10;
|
||||
isch_map[0x112a5260caULL] = 11;
|
||||
isch_map[0x11db07ee62ULL] = 12;
|
||||
isch_map[0x11ef3a6bf5ULL] = 13;
|
||||
isch_map[0x1183cc442cULL] = 14;
|
||||
isch_map[0x11b7f1c1bbULL] = 15;
|
||||
isch_map[0x1a4a2e239eULL] = 16;
|
||||
isch_map[0x1a7e13a609ULL] = 17;
|
||||
isch_map[0x1a12e589d0ULL] = 18;
|
||||
isch_map[0x1a26d80c47ULL] = 19;
|
||||
isch_map[0x1ad78d82efULL] = 20;
|
||||
isch_map[0x1ae3b00778ULL] = 21;
|
||||
isch_map[0x1a8f4628a1ULL] = 22;
|
||||
isch_map[0x1abb7bad36ULL] = 23;
|
||||
isch_map[0x134ea3b8ecULL] = 24;
|
||||
isch_map[0x137a9e3d7bULL] = 25;
|
||||
isch_map[0x13166812a2ULL] = 26;
|
||||
isch_map[0x1322559735ULL] = 27;
|
||||
isch_map[0x13d300199dULL] = 28;
|
||||
isch_map[0x13e73d9c0aULL] = 29;
|
||||
isch_map[0x138bcbb3d3ULL] = 30;
|
||||
isch_map[0x13bff63644ULL] = 31;
|
||||
isch_map[0x1442f705efULL] = 32;
|
||||
isch_map[0x1476ca8078ULL] = 33;
|
||||
isch_map[0x141a3cafa1ULL] = 34;
|
||||
isch_map[0x142e012a36ULL] = 35;
|
||||
isch_map[0x14df54a49eULL] = 36;
|
||||
isch_map[0x14eb692109ULL] = 37;
|
||||
isch_map[0x14879f0ed0ULL] = 38;
|
||||
isch_map[0x14b3a28b47ULL] = 39;
|
||||
isch_map[0x1d467a9e9dULL] = 40;
|
||||
isch_map[0x1d72471b0aULL] = 41;
|
||||
isch_map[0x1d1eb134d3ULL] = 42;
|
||||
isch_map[0x1d2a8cb144ULL] = 43;
|
||||
isch_map[0x1ddbd93fecULL] = 44;
|
||||
isch_map[0x1defe4ba7bULL] = 45;
|
||||
isch_map[0x1d831295a2ULL] = 46;
|
||||
isch_map[0x1db72f1035ULL] = 47;
|
||||
isch_map[0x164af0f210ULL] = 48;
|
||||
isch_map[0x167ecd7787ULL] = 49;
|
||||
isch_map[0x16123b585eULL] = 50;
|
||||
isch_map[0x162606ddc9ULL] = 51;
|
||||
isch_map[0x16d7535361ULL] = 52;
|
||||
isch_map[0x16e36ed6f6ULL] = 53;
|
||||
isch_map[0x168f98f92fULL] = 54;
|
||||
isch_map[0x16bba57cb8ULL] = 55;
|
||||
isch_map[0x1f4e7d6962ULL] = 56;
|
||||
isch_map[0x1f7a40ecf5ULL] = 57;
|
||||
isch_map[0x1f16b6c32cULL] = 58;
|
||||
isch_map[0x1f228b46bbULL] = 59;
|
||||
isch_map[0x1fd3dec813ULL] = 60;
|
||||
isch_map[0x1fe7e34d84ULL] = 61;
|
||||
isch_map[0x1f8b15625dULL] = 62;
|
||||
isch_map[0x1fbf28e7caULL] = 63;
|
||||
isch_map[0x084d62c339ULL] = 64;
|
||||
isch_map[0x08795f46aeULL] = 65;
|
||||
isch_map[0x0815a96977ULL] = 66;
|
||||
isch_map[0x082194ece0ULL] = 67;
|
||||
isch_map[0x08d0c16248ULL] = 68;
|
||||
isch_map[0x08e4fce7dfULL] = 69;
|
||||
isch_map[0x08880ac806ULL] = 70;
|
||||
isch_map[0x08bc374d91ULL] = 71;
|
||||
isch_map[0x0149ef584bULL] = 72;
|
||||
isch_map[0x017dd2dddcULL] = 73;
|
||||
isch_map[0x011124f205ULL] = 74;
|
||||
isch_map[0x0125197792ULL] = 75;
|
||||
isch_map[0x01d44cf93aULL] = 76;
|
||||
isch_map[0x01e0717cadULL] = 77;
|
||||
isch_map[0x018c875374ULL] = 78;
|
||||
isch_map[0x01b8bad6e3ULL] = 79;
|
||||
isch_map[0x0a456534c6ULL] = 80;
|
||||
isch_map[0x0a7158b151ULL] = 81;
|
||||
isch_map[0x0a1dae9e88ULL] = 82;
|
||||
isch_map[0x0a29931b1fULL] = 83;
|
||||
isch_map[0x0ad8c695b7ULL] = 84;
|
||||
isch_map[0x0aecfb1020ULL] = 85;
|
||||
isch_map[0x0a800d3ff9ULL] = 86;
|
||||
isch_map[0x0ab430ba6eULL] = 87;
|
||||
isch_map[0x0341e8afb4ULL] = 88;
|
||||
isch_map[0x0375d52a23ULL] = 89;
|
||||
isch_map[0x03192305faULL] = 90;
|
||||
isch_map[0x032d1e806dULL] = 91;
|
||||
isch_map[0x03dc4b0ec5ULL] = 92;
|
||||
isch_map[0x03e8768b52ULL] = 93;
|
||||
isch_map[0x038480a48bULL] = 94;
|
||||
isch_map[0x03b0bd211cULL] = 95;
|
||||
isch_map[0x044dbc12b7ULL] = 96;
|
||||
isch_map[0x0479819720ULL] = 97;
|
||||
isch_map[0x041577b8f9ULL] = 98;
|
||||
isch_map[0x04214a3d6eULL] = 99;
|
||||
isch_map[0x04d01fb3c6ULL] = 100;
|
||||
isch_map[0x04e4223651ULL] = 101;
|
||||
isch_map[0x0488d41988ULL] = 102;
|
||||
isch_map[0x04bce99c1fULL] = 103;
|
||||
isch_map[0x0d493189c5ULL] = 104;
|
||||
isch_map[0x0d7d0c0c52ULL] = 105;
|
||||
isch_map[0x0d11fa238bULL] = 106;
|
||||
isch_map[0x0d25c7a61cULL] = 107;
|
||||
isch_map[0x0dd49228b4ULL] = 108;
|
||||
isch_map[0x0de0afad23ULL] = 109;
|
||||
isch_map[0x0d8c5982faULL] = 110;
|
||||
isch_map[0x0db864076dULL] = 111;
|
||||
isch_map[0x0645bbe548ULL] = 112;
|
||||
isch_map[0x06718660dfULL] = 113;
|
||||
isch_map[0x061d704f06ULL] = 114;
|
||||
isch_map[0x06294dca91ULL] = 115;
|
||||
isch_map[0x06d8184439ULL] = 116;
|
||||
isch_map[0x06ec25c1aeULL] = 117;
|
||||
isch_map[0x0680d3ee77ULL] = 118;
|
||||
isch_map[0x06b4ee6be0ULL] = 119;
|
||||
isch_map[0x0f41367e3aULL] = 120;
|
||||
isch_map[0x0f750bfbadULL] = 121;
|
||||
isch_map[0x0f19fdd474ULL] = 122;
|
||||
isch_map[0x0f2dc051e3ULL] = 123;
|
||||
isch_map[0x0fdc95df4bULL] = 124;
|
||||
isch_map[0x0fe8a85adcULL] = 125;
|
||||
isch_map[0x0f845e7505ULL] = 126;
|
||||
isch_map[0x0fb063f092ULL] = 127;
|
||||
isch_map[0x575d57f7ffULL] = -2; // S-ISCH
|
||||
}
|
||||
|
||||
int isch_lookup (unsigned long long int isch)
|
||||
//I-ISCH Lookup, borrowed from OP25 (now w/ error correction)
|
||||
int isch_lookup (uint64_t isch)
|
||||
{
|
||||
map_isch(); //initialize the lookup map
|
||||
char s[64];
|
||||
int decoded = -2; //initialize lookup to an invalid number
|
||||
sprintf(s, "%llx", isch);
|
||||
decoded = isch_map[s];
|
||||
return(decoded);
|
||||
}
|
||||
map_isch(); //initialize the lookup map
|
||||
int decoded = -2;
|
||||
|
||||
// Must contain bit errors if no exact match, so
|
||||
// look for codeword with smallest hamming distance
|
||||
if (isch_map.find(isch) == isch_map.end())
|
||||
{
|
||||
int popct, popmin = 40;
|
||||
for (auto it = isch_map.begin(); it != isch_map.end(); ++it)
|
||||
{
|
||||
popct = __builtin_popcountll(isch ^ it->first);
|
||||
// Encoding is (40, 9, 16) which can correct at most 7 bit-errors
|
||||
if ((popct <= 7) && (popct < popmin))
|
||||
{
|
||||
decoded = it->second;
|
||||
popmin = popct;
|
||||
}
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
else // No errors, so simply return the matching value
|
||||
decoded = isch_map[isch];
|
||||
|
||||
return decoded;
|
||||
|
||||
}
|
||||
809
src/m17.c
Normal file
809
src/m17.c
Normal file
@@ -0,0 +1,809 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* m17.c
|
||||
* M17 Decoder (WIP)
|
||||
*
|
||||
* m17_scramble Bit Array from SDR++
|
||||
* CRC16 from M17-Implementations (thanks again, sp5wwp)
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2023-07 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
#include "dsd.h"
|
||||
|
||||
//try to find a fancy lfsr or calculation for this and not an array if possible
|
||||
uint8_t m17_scramble[369] = {
|
||||
1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1,
|
||||
1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
|
||||
1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1,
|
||||
1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0,
|
||||
1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
|
||||
0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1
|
||||
};
|
||||
|
||||
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
|
||||
|
||||
uint8_t p1[62] = {
|
||||
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
|
||||
};
|
||||
|
||||
//produce 6 short samples (48k) for every 1 short sample (8k)
|
||||
void upsampleM17 (short invalue, short prev, short outbuf[6])
|
||||
{
|
||||
|
||||
float c, d;
|
||||
|
||||
c = prev;
|
||||
d = invalue;
|
||||
|
||||
// basic triangle interpolation
|
||||
outbuf[0] = c = ((invalue * (float) 0.166) + (c * (float) 0.834));
|
||||
outbuf[1] = c = ((invalue * (float) 0.332) + (c * (float) 0.668));
|
||||
outbuf[2] = c = ((invalue * (float) 0.500) + (c * (float) 0.5));
|
||||
outbuf[3] = c = ((invalue * (float) 0.668) + (c * (float) 0.332));
|
||||
outbuf[4] = c = ((invalue * (float) 0.834) + (c * (float) 0.166));
|
||||
outbuf[5] = c = d;
|
||||
prev = d; //shift prev to the last d value for the next repitition
|
||||
|
||||
}
|
||||
|
||||
//from M17_Implementations -- sp5wwp -- should have just looked here to begin with
|
||||
//this setup looks very similar to the OP25 variant of crc16, but with a few differences (uses packed bytes)
|
||||
uint16_t crc16m17(const uint8_t *in, const uint16_t len)
|
||||
{
|
||||
uint32_t crc = 0xFFFF; //init val
|
||||
uint16_t poly = 0x5935;
|
||||
for(uint16_t i=0; i<len; i++)
|
||||
{
|
||||
crc^=in[i]<<8;
|
||||
for(uint8_t j=0; j<8; j++)
|
||||
{
|
||||
crc<<=1;
|
||||
if(crc&0x10000)
|
||||
crc=(crc^poly)&0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
return crc&(0xFFFF);
|
||||
}
|
||||
|
||||
void M17decodeCSD(dsd_state * state, unsigned long long int dst, unsigned long long int src)
|
||||
{
|
||||
//evaluate dst and src, and determine if they need to be converted to calsign
|
||||
int i, j;
|
||||
char c;
|
||||
unsigned long long int value;
|
||||
|
||||
if (dst == 0xFFFFFFFFFFFF)
|
||||
fprintf (stderr, " DST: BROADCAST");
|
||||
else if (dst == 0)
|
||||
fprintf (stderr, " DST: RESERVED %012llx", dst);
|
||||
else if (dst >= 0xEE6B28000000)
|
||||
fprintf (stderr, " DST: RESERVED %012llx", dst);
|
||||
else
|
||||
{
|
||||
fprintf (stderr, " DST: ");
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
c = b40[dst % 40];
|
||||
state->m17_dst_csd[i] = c;
|
||||
fprintf (stderr, "%c", c);
|
||||
dst = dst / 40;
|
||||
}
|
||||
//assign completed CSD to a more useful string instead
|
||||
sprintf (state->m17_dst_str, "%c%c%c%c%c%c%c%c%c",
|
||||
state->m17_dst_csd[0], state->m17_dst_csd[1], state->m17_dst_csd[2], state->m17_dst_csd[3],
|
||||
state->m17_dst_csd[4], state->m17_dst_csd[5], state->m17_dst_csd[6], state->m17_dst_csd[7], state->m17_dst_csd[8]);
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "DT: %s", state->m17_dst_str);
|
||||
}
|
||||
|
||||
if (src == 0xFFFFFFFFFFFF)
|
||||
fprintf (stderr, " SRC: UNKNOWN FFFFFFFFFFFF");
|
||||
else if (src == 0)
|
||||
fprintf (stderr, " SRC: RESERVED %012llx", src);
|
||||
else if (src >= 0xEE6B28000000)
|
||||
fprintf (stderr, " SRC: RESERVED %012llx", src);
|
||||
else
|
||||
{
|
||||
fprintf (stderr, " SRC: ");
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
c = b40[src % 40];
|
||||
state->m17_src_csd[i] = c;
|
||||
fprintf (stderr, "%c", c);
|
||||
src = src / 40;
|
||||
}
|
||||
//assign completed CSD to a more useful string instead
|
||||
sprintf (state->m17_src_str, "%c%c%c%c%c%c%c%c%c",
|
||||
state->m17_src_csd[0], state->m17_src_csd[1], state->m17_src_csd[2], state->m17_src_csd[3],
|
||||
state->m17_src_csd[4], state->m17_src_csd[5], state->m17_src_csd[6], state->m17_src_csd[7], state->m17_src_csd[8]);
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "ST: %s", state->m17_src_str);
|
||||
}
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " DST: %012llX SRC: %012llX", state->m17_dst, state->m17_src);
|
||||
|
||||
}
|
||||
|
||||
void M17decodeLSF(dsd_state * state)
|
||||
{
|
||||
int i;
|
||||
|
||||
unsigned long long int lsf_dst = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[0], 48);
|
||||
unsigned long long int lsf_src = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[48], 48);
|
||||
uint16_t lsf_type = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[96], 16);
|
||||
|
||||
//this is the way the manual/code expects you to read these bits
|
||||
// uint8_t lsf_ps = (lsf_type >> 0) & 0x1;
|
||||
uint8_t lsf_dt = (lsf_type >> 1) & 0x3;
|
||||
uint8_t lsf_et = (lsf_type >> 3) & 0x3;
|
||||
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
|
||||
uint8_t lsf_cn = (lsf_type >> 7) & 0xF;
|
||||
uint8_t lsf_rs = (lsf_type >> 11) & 0x1F;
|
||||
|
||||
//store this so we can reference it for playing voice and/or decoding data, dst/src etc
|
||||
state->m17_str_dt = lsf_dt;
|
||||
state->m17_dst = lsf_dst;
|
||||
state->m17_src = lsf_src;
|
||||
state->m17_can = lsf_cn;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
//packet or stream
|
||||
// if (lsf_ps == 0) fprintf (stderr, " P-");
|
||||
// if (lsf_ps == 1) fprintf (stderr, " S-");
|
||||
|
||||
fprintf (stderr, " CAN: %d", lsf_cn);
|
||||
M17decodeCSD(state, lsf_dst, lsf_src);
|
||||
|
||||
if (lsf_dt == 0) fprintf (stderr, " Reserved");
|
||||
if (lsf_dt == 1) fprintf (stderr, " Data");
|
||||
if (lsf_dt == 2) fprintf (stderr, " Voice (3200bps)");
|
||||
if (lsf_dt == 3) fprintf (stderr, " Voice + Data");
|
||||
|
||||
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
|
||||
|
||||
if (lsf_et != 0) fprintf (stderr, " ENC:");
|
||||
if (lsf_et == 2) fprintf (stderr, " AES-CTR");
|
||||
if (lsf_et == 1) fprintf (stderr, " Scrambler - %d", lsf_es);
|
||||
|
||||
state->m17_enc = lsf_et;
|
||||
state->m17_enc_st = lsf_es;
|
||||
|
||||
//pack meta bits into 14 bytes
|
||||
for (i = 0; i < 14; i++)
|
||||
state->m17_meta[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8);
|
||||
|
||||
//Examine the Meta data
|
||||
if (lsf_et == 0 && state->m17_meta[0] != 0) //not sure if this applies universally, or just to text data byte 0 for null data
|
||||
{
|
||||
fprintf (stderr, " Meta:");
|
||||
if (lsf_es == 0) fprintf (stderr, " Text Data");
|
||||
if (lsf_es == 1) fprintf (stderr, " GNSS Pos");
|
||||
if (lsf_es == 2) fprintf (stderr, " Extended CSD");
|
||||
if (lsf_es == 3) fprintf (stderr, " Reserved");
|
||||
}
|
||||
|
||||
if (lsf_et == 2)
|
||||
{
|
||||
fprintf (stderr, " IV: ");
|
||||
for (i = 0; i < 16; i++)
|
||||
fprintf (stderr, "%02X", state->m17_meta[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits)
|
||||
{
|
||||
int i, j, err;
|
||||
err = 0;
|
||||
|
||||
uint8_t lich[4][24];
|
||||
uint8_t lich_decoded[48];
|
||||
uint8_t temp[96];
|
||||
bool g[4];
|
||||
|
||||
//for testing bit arrangement vs the crc code
|
||||
uint8_t bs[240];
|
||||
memset(bs, 1, sizeof(bs));
|
||||
|
||||
uint16_t crc_cmp = 0;
|
||||
uint16_t crc_ext = 0;
|
||||
uint8_t crc_err = 0;
|
||||
|
||||
memset(lich, 0, sizeof(lich));
|
||||
memset(lich_decoded, 0, sizeof(lich_decoded));
|
||||
memset(temp, 0, sizeof(temp));
|
||||
|
||||
//execute golay 24,12 or 4 24-bit chunks and reorder into 4 12-bit chunks
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
g[i] = TRUE;
|
||||
|
||||
for (j = 0; j < 24; j++)
|
||||
lich[i][j] = lich_bits[(i*24)+j];
|
||||
|
||||
g[i] = Golay_24_12_decode(lich[i]);
|
||||
if(g[i] == FALSE) err = -1;
|
||||
|
||||
for (j = 0; j < 12; j++)
|
||||
lich_decoded[i*12+j] = lich[i][j];
|
||||
|
||||
}
|
||||
|
||||
uint8_t lich_counter = (uint8_t)ConvertBitIntoBytes(&lich_decoded[40], 3); //lich_cunt
|
||||
uint8_t lich_reserve = (uint8_t)ConvertBitIntoBytes(&lich_decoded[43], 5); //lich_reserved
|
||||
|
||||
if (err == 0)
|
||||
fprintf (stderr, "LC: %d/6 ", lich_counter+1);
|
||||
else fprintf (stderr, "LICH G24 ERR");
|
||||
|
||||
if (err = 0 && lich_reserve != 0) fprintf(stderr, " LRS: %d", lich_reserve);
|
||||
|
||||
//transfer to storage
|
||||
for (i = 0; i < 40; i++)
|
||||
state->m17_lsf[lich_counter*40+i] = lich_decoded[i];
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, " LICH: ");
|
||||
for (i = 0; i < 6; i++)
|
||||
fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&lich_decoded[i*8], 8));
|
||||
}
|
||||
|
||||
uint8_t lsf_packed[30];
|
||||
memset (lsf_packed, 0, sizeof(lsf_packed));
|
||||
|
||||
if (lich_counter == 5)
|
||||
{
|
||||
|
||||
//need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future)
|
||||
for (i = 0; i < 30; i++)
|
||||
lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8);
|
||||
|
||||
crc_cmp = crc16m17(lsf_packed, 28);
|
||||
crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16);
|
||||
|
||||
if (crc_cmp != crc_ext) crc_err = 1;
|
||||
|
||||
if (crc_err == 0)
|
||||
M17decodeLSF(state);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n LSF: ");
|
||||
for (i = 0; i < 30; i++)
|
||||
{
|
||||
if (i == 15) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", lsf_packed[i]);
|
||||
}
|
||||
}
|
||||
|
||||
memset (state->m17_lsf, 1, sizeof(state->m17_lsf));
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " E-%04X; C-%04X (CRC CHK)", crc_ext, crc_cmp);
|
||||
|
||||
if (crc_err == 1) fprintf (stderr, " EMB LSF CRC ERR");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload)
|
||||
{
|
||||
int i;
|
||||
unsigned char voice1[8];
|
||||
unsigned char voice2[8];
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
voice1[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+0], 8);
|
||||
voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8);
|
||||
}
|
||||
|
||||
//TODO: Add some decryption methods
|
||||
if (state->m17_enc != 0)
|
||||
{
|
||||
//process scrambler or AES-CTR decryption
|
||||
//(no AES-CTR right now, Scrambler should be easy enough)
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n CODEC2: ");
|
||||
for (i = 0; i < 8; i++)
|
||||
fprintf (stderr, "%02X", voice1[i]);
|
||||
fprintf (stderr, " (1600)");
|
||||
|
||||
fprintf (stderr, "\n LSDATA: "); //low speed data
|
||||
for (i = 0; i < 8; i++)
|
||||
fprintf (stderr, "%02X", voice2[i]);
|
||||
}
|
||||
|
||||
#ifdef USE_CODEC2
|
||||
size_t nsam;
|
||||
nsam = 160;
|
||||
|
||||
//converted to using allocated memory pointers to prevent the overflow issues
|
||||
short * samp1 = malloc (sizeof(short) * nsam);
|
||||
short * upsamp = malloc (sizeof(short) * nsam * 6);
|
||||
short * out = malloc (sizeof(short) * 6);
|
||||
short prev;
|
||||
int j;
|
||||
|
||||
codec2_decode(state->codec2_1600, samp1, voice1);
|
||||
|
||||
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
||||
|
||||
}
|
||||
|
||||
#ifdef AERO_BUILD
|
||||
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS w/ required upsample to 48k
|
||||
{
|
||||
//upsample to 48k and then play
|
||||
prev = samp1[0];
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
upsampleM17 (samp1[i], prev, out);
|
||||
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
|
||||
}
|
||||
write (opts->audio_out_fd, upsamp, nsam*2*6);
|
||||
}
|
||||
#else
|
||||
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS via PADSP at 8k
|
||||
{
|
||||
write (opts->audio_out_fd, samp1, nsam*2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
||||
if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV
|
||||
{
|
||||
sf_write_short(opts->wav_out_f, samp1, nsam);
|
||||
}
|
||||
|
||||
//TODO: Codec2 Raw file saving
|
||||
// if(mbe_out_dir)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
free (samp1);
|
||||
free (upsamp);
|
||||
free (out);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload)
|
||||
{
|
||||
int i;
|
||||
unsigned char voice1[8];
|
||||
unsigned char voice2[8];
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
voice1[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+0], 8);
|
||||
voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8);
|
||||
}
|
||||
|
||||
//TODO: Add some decryption methods
|
||||
if (state->m17_enc != 0)
|
||||
{
|
||||
//process scrambler or AES-CTR decryption
|
||||
//(no AES-CTR right now, Scrambler should be easy enough)
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n CODEC2: ");
|
||||
for (i = 0; i < 8; i++)
|
||||
fprintf (stderr, "%02X", voice1[i]);
|
||||
fprintf (stderr, " (3200)");
|
||||
|
||||
fprintf (stderr, "\n CODEC2: ");
|
||||
for (i = 0; i < 8; i++)
|
||||
fprintf (stderr, "%02X", voice2[i]);
|
||||
fprintf (stderr, " (3200)");
|
||||
}
|
||||
|
||||
#ifdef USE_CODEC2
|
||||
size_t nsam;
|
||||
nsam = 160;
|
||||
|
||||
//converted to using allocated memory pointers to prevent the overflow issues
|
||||
short * samp1 = malloc (sizeof(short) * nsam);
|
||||
short * samp2 = malloc (sizeof(short) * nsam);
|
||||
short * upsamp = malloc (sizeof(short) * nsam * 6);
|
||||
short * out = malloc (sizeof(short) * 6);
|
||||
short prev;
|
||||
int j;
|
||||
|
||||
codec2_decode(state->codec2_3200, samp1, voice1);
|
||||
codec2_decode(state->codec2_3200, samp2, voice2);
|
||||
|
||||
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
||||
pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
||||
}
|
||||
|
||||
#ifdef AERO_BUILD
|
||||
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS w/ required upsample to 48k
|
||||
{
|
||||
//upsample to 48k and then play
|
||||
// prev = samp1[0];
|
||||
prev = 0;
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
upsampleM17 (samp1[i], prev, out);
|
||||
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
|
||||
}
|
||||
write (opts->audio_out_fd, upsamp, nsam*2*6);
|
||||
prev = samp2[0];
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
upsampleM17 (samp2[i], prev, out);
|
||||
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
|
||||
}
|
||||
write (opts->audio_out_fd, upsamp, nsam*2*6);
|
||||
}
|
||||
#else
|
||||
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS via PADSP at 8k
|
||||
{
|
||||
write (opts->audio_out_fd, samp1, nsam*2);
|
||||
write (opts->audio_out_fd, samp2, nsam*2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT
|
||||
{
|
||||
write (opts->audio_out_fd, samp1, nsam*2);
|
||||
write (opts->audio_out_fd, samp2, nsam*2);
|
||||
}
|
||||
|
||||
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
||||
if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV
|
||||
{
|
||||
sf_write_short(opts->wav_out_f, samp1, nsam);
|
||||
sf_write_short(opts->wav_out_f, samp2, nsam);
|
||||
}
|
||||
|
||||
//TODO: Codec2 Raw file saving
|
||||
// if(mbe_out_dir)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
free (samp1);
|
||||
free (samp2);
|
||||
free (upsamp);
|
||||
free (out);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t * m17_bits)
|
||||
{
|
||||
|
||||
int i, k, x;
|
||||
uint8_t m17_punc[275]; //25 * 11 = 275
|
||||
memset (m17_punc, 0, sizeof(m17_punc));
|
||||
for (i = 0; i < 272; i++)
|
||||
m17_punc[i] = m17_bits[i+96];
|
||||
|
||||
//depuncture the bits
|
||||
uint8_t m17_depunc[300]; //25 * 12 = 300
|
||||
memset (m17_depunc, 0, sizeof(m17_depunc));
|
||||
k = 0; x = 0;
|
||||
for (i = 0; i < 25; i++)
|
||||
{
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = m17_punc[x++];
|
||||
m17_depunc[k++] = 0;
|
||||
}
|
||||
|
||||
//setup the convolutional decoder
|
||||
uint8_t temp[300];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[28];
|
||||
uint8_t trellis_buf[144];
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
|
||||
for (i = 0; i < 296; i++)
|
||||
temp[i] = m17_depunc[i] << 1;
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (i = 0; i < 148; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 144);
|
||||
|
||||
//144/8 = 18, last 4 (144-148) are trailing zeroes
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
|
||||
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
|
||||
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
|
||||
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
|
||||
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
|
||||
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
|
||||
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
|
||||
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
//load m_data into bits for either data packets or voice packets
|
||||
uint8_t payload[128];
|
||||
uint8_t end = 9;
|
||||
uint16_t fn = 0;
|
||||
memset (payload, 0, sizeof(payload));
|
||||
|
||||
end = trellis_buf[0];
|
||||
fn = (uint16_t)ConvertBitIntoBytes(&trellis_buf[1], 15);
|
||||
|
||||
//insert fn bits into meta 14 and meta 15 for Initialization Vector
|
||||
state->m17_meta[14] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[1], 7);
|
||||
state->m17_meta[15] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[8], 8);
|
||||
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, " FSN: %05d", fn);
|
||||
|
||||
if (end == 1)
|
||||
fprintf (stderr, " END;");
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
payload[i] = trellis_buf[i+16];
|
||||
|
||||
if (state->m17_str_dt == 2)
|
||||
M17processCodec2_3200(opts, state, payload);
|
||||
else if (state->m17_str_dt == 3)
|
||||
M17processCodec2_1600(opts, state, payload);
|
||||
else if (state->m17_str_dt == 1) fprintf (stderr, " DATA;");
|
||||
else if (state->m17_str_dt == 0) fprintf (stderr, " RES;");
|
||||
// else fprintf (stderr, " UNK;");
|
||||
|
||||
if (opts->payload == 1 && state->m17_str_dt < 2)
|
||||
{
|
||||
fprintf (stderr, "\n STREAM: ");
|
||||
for (i = 0; i < 18; i++)
|
||||
fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void processM17STR(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int i, x;
|
||||
//overflow/memory issue returns in Cygwin for...reasons...
|
||||
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
||||
uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized)
|
||||
uint8_t m17_int_bits[368]; //368 bits that are still interleaved
|
||||
uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble
|
||||
uint8_t lich_bits[96];
|
||||
int lich_err = -1;
|
||||
|
||||
memset (dbuf, 0, sizeof(dbuf));
|
||||
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
|
||||
memset (m17_int_bits, 0, sizeof(m17_int_bits));
|
||||
memset (m17_bits, 0, sizeof(m17_bits));
|
||||
memset (lich_bits, 0, sizeof(lich_bits));
|
||||
|
||||
//load dibits into dibit buffer
|
||||
for (i = 0; i < 184; i++)
|
||||
dbuf[i] = (uint8_t) getDibit(opts, state);
|
||||
|
||||
//convert dbuf into a bit array
|
||||
for (i = 0; i < 184; i++)
|
||||
{
|
||||
m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1;
|
||||
m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
//descramble the frame
|
||||
for (i = 0; i < 368; i++)
|
||||
m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1;
|
||||
|
||||
//deinterleave the bit array using Quadratic Permutation Polynomial
|
||||
//function π(x) = (45x + 92x^2 ) mod 368
|
||||
for (i = 0; i < 368; i++)
|
||||
{
|
||||
x = ((45*i)+(92*i*i)) % 368;
|
||||
m17_bits[i] = m17_int_bits[x];
|
||||
}
|
||||
|
||||
for (i = 0; i < 96; i++)
|
||||
lich_bits[i] = m17_bits[i];
|
||||
|
||||
//check lich first, and handle LSF chunk and completed LSF
|
||||
lich_err = M17processLICH(state, opts, lich_bits);
|
||||
|
||||
if (lich_err == 0)
|
||||
M17prepareStream(opts, state, m17_bits);
|
||||
|
||||
// if (lich_err != 0) state->lastsynctype = -1; //disable
|
||||
|
||||
//ending linebreak
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
} //end processM17STR
|
||||
|
||||
void processM17LSF(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
//NOTE: Have not been able to get this to work successfully, but considering
|
||||
//there is only one LSF frame at the beginning of TX, its probably just as easy to
|
||||
//use and rely on the STR frame and embedded LSF chunk, which does work properly
|
||||
int i, j, k, x;
|
||||
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
||||
uint8_t m17_rnd_bits[500]; //368 bits that are still scrambled (randomized)
|
||||
uint8_t m17_int_bits[500]; //368 bits that are still interleaved
|
||||
uint8_t m17_bits[500]; //368 bits that have been de-interleaved and de-scramble
|
||||
uint8_t m17_depunc[500]; //488 bits after depuncturing
|
||||
|
||||
memset (dbuf, 0, sizeof(dbuf));
|
||||
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
|
||||
memset (m17_int_bits, 0, sizeof(m17_int_bits));
|
||||
memset (m17_bits, 0, sizeof(m17_bits));
|
||||
memset (m17_depunc, 0, sizeof(m17_depunc));
|
||||
|
||||
//load dibits into dibit buffer
|
||||
for (i = 0; i < 184; i++)
|
||||
dbuf[i] = (uint8_t) getDibit(opts, state);
|
||||
|
||||
//convert dbuf into a bit array
|
||||
for (i = 0; i < 184; i++)
|
||||
{
|
||||
m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1;
|
||||
m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
//descramble the frame
|
||||
for (i = 0; i < 368; i++)
|
||||
m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1;
|
||||
|
||||
//deinterleave the bit array using Quadratic Permutation Polynomial
|
||||
//function π(x) = (45x + 92x^2 ) mod 368
|
||||
for (i = 0; i < 368; i++)
|
||||
{
|
||||
x = ((45*i)+(92*i*i)) % 368;
|
||||
m17_bits[i] = m17_int_bits[x];
|
||||
}
|
||||
|
||||
j = 0; k = 0; x = 0;
|
||||
|
||||
// P1 Depuncture
|
||||
for (i = 0; i < 488; i++)
|
||||
{
|
||||
if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++];
|
||||
else m17_depunc[x++] = 1;
|
||||
|
||||
if (k == 61) k = 0; //61 -- should reset 8 times againt the array
|
||||
|
||||
}
|
||||
|
||||
//debug -- values seem okay at end of run
|
||||
// fprintf (stderr, "K = %d; J = %d; X = %d", k, j, x);
|
||||
|
||||
//setup the convolutional decoder
|
||||
uint8_t temp[500];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[30];
|
||||
uint8_t trellis_buf[240]; //30*8 = 240
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
|
||||
for (i = 0; i < 488; i++)
|
||||
temp[i] = m17_depunc[i] << 1;
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (i = 0; i < 244; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 240);
|
||||
|
||||
//244/8 = 30, last 4 (244-248) are trailing zeroes
|
||||
for(i = 0; i < 30; i++)
|
||||
{
|
||||
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
|
||||
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
|
||||
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
|
||||
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
|
||||
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
|
||||
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
|
||||
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
|
||||
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
memset (state->m17_lsf, 0, sizeof(state->m17_lsf));
|
||||
memcpy (state->m17_lsf, trellis_buf, 240);
|
||||
|
||||
uint8_t lsf_packed[30];
|
||||
memset (lsf_packed, 0, sizeof(lsf_packed));
|
||||
|
||||
//need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future)
|
||||
for (i = 0; i < 30; i++)
|
||||
lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8);
|
||||
|
||||
uint16_t crc_cmp = crc16m17(lsf_packed, 28);
|
||||
uint16_t crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16);
|
||||
int crc_err = 0;
|
||||
|
||||
if (crc_cmp != crc_ext) crc_err = 1;
|
||||
|
||||
if (crc_err == 0)
|
||||
M17decodeLSF(state);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n LSF: ");
|
||||
for (i = 0; i < 30; i++)
|
||||
{
|
||||
if (i == 15) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", lsf_packed[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " E-%04X; C-%04X (CRC CHK)", crc_ext, crc_cmp);
|
||||
|
||||
if (crc_err == 1) fprintf (stderr, " CRC ERR");
|
||||
|
||||
//ending linebreak
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
} //end processM17LSF
|
||||
@@ -36,13 +36,13 @@
|
||||
|
||||
|
||||
/* Global variables ---------------------------------------------------------*/
|
||||
static const uint8_t CNXDNConvolution_BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||
static const uint8_t CNXDNConvolution_BIT_MASK_TABLE[8] = {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 uint8_t CNXDNConvolution_BRANCH_TABLE1[8] = {0U, 0U, 0U, 0U, 2U, 2U, 2U, 2U};
|
||||
static const uint8_t CNXDNConvolution_BRANCH_TABLE2[8] = {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;
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
#include "dsd.h"
|
||||
#include "nxdn_const.h"
|
||||
|
||||
static const uint8_t scramble_t[] = { //values are the position values we need to invert in the descramble
|
||||
//NOTE: Descrambling was having an issue without a value inside the brackets, but only when
|
||||
//the PARITY table was disabled, was this due to a memory issue or overflow?
|
||||
static const uint8_t scramble_t[182] = { //values are the position values we need to invert in the descramble
|
||||
2, 5, 6, 7, 10, 12, 14, 16, 17, 22, 23, 25, 26, 27, 28, 30, 33, 34, 36, 37, 38, 41, 45, 47,
|
||||
52, 54, 56, 57, 59, 62, 63, 64, 65, 66, 67, 69, 70, 73, 76, 79, 81, 82, 84, 85, 86, 87, 88,
|
||||
89, 92, 95, 96, 98, 100, 103, 104, 107, 108, 116, 117, 121, 122, 125, 127, 131, 132, 134,
|
||||
@@ -33,11 +35,6 @@ static const uint8_t scramble_t[] = { //values are the position values we need t
|
||||
168, 170, 171, 174, 175, 176, 177, 181
|
||||
};
|
||||
|
||||
static const int PARITY[] = {
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0,
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||
};
|
||||
|
||||
//decoding functions here
|
||||
void nxdn_descramble(uint8_t dibits[], int len)
|
||||
@@ -52,9 +49,9 @@ void nxdn_descramble(uint8_t dibits[], int len)
|
||||
|
||||
void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
{
|
||||
uint8_t deperm[200]; //144
|
||||
uint8_t depunc[200]; //192
|
||||
uint8_t trellis_buf[400]; //96
|
||||
uint8_t deperm[144]; //144
|
||||
uint8_t depunc[192]; //192
|
||||
uint8_t trellis_buf[96]; //96
|
||||
uint16_t crc = 0; //crc calculated by function
|
||||
uint16_t check = 0; //crc from payload for comparison
|
||||
int out;
|
||||
@@ -73,7 +70,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[210];
|
||||
uint8_t temp[200];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[20]; //13
|
||||
@@ -82,17 +79,10 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
|
||||
for (int i = 0; i < 192; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
temp[i+192] = 0;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 100U; i++)
|
||||
for (int i = 0; i < 96; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
@@ -100,7 +90,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 96U);
|
||||
CNXDNConvolution_chainback(m_data, 92);
|
||||
|
||||
for(int i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -121,26 +111,23 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
check = check | trellis_buf[84+i]; //80
|
||||
}
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, " FACCH");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " FACCH Payload ");
|
||||
fprintf (stderr, " FACCH1 Payload ");
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
// fprintf (stderr, " - %03X %03X", check, crc);
|
||||
if (crc != check && opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -149,9 +136,9 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
{
|
||||
//see about initializing these variables
|
||||
uint8_t deperm[200]; //60
|
||||
uint8_t depunc[200]; //72
|
||||
uint8_t trellis_buf[400]; //32
|
||||
uint8_t deperm[60]; //60
|
||||
uint8_t depunc[72]; //72
|
||||
uint8_t trellis_buf[32]; //32
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
@@ -182,27 +169,20 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[90];
|
||||
uint8_t temp[80];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[10]; //5
|
||||
uint8_t m_data[5]; //5
|
||||
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
|
||||
for (int i = 0; i < 72; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
temp[i+72] = 0;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 36U; i++) //40
|
||||
for (int i = 0; i < 36; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
@@ -211,7 +191,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
}
|
||||
|
||||
//stored as 5 bytes, will need to convert to trellis_buf after running
|
||||
CNXDNConvolution_chainback(m_data, 32U); //36
|
||||
CNXDNConvolution_chainback(m_data, 32);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
@@ -238,7 +218,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
uint8_t nsf_sacch[400];
|
||||
uint8_t nsf_sacch[26];
|
||||
memset (nsf_sacch, 0, sizeof(nsf_sacch));
|
||||
for (int i = 0; i < 26; i++)
|
||||
{
|
||||
@@ -251,16 +231,14 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
state->nxdn_last_ran = ran;
|
||||
}
|
||||
|
||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
|
||||
fprintf (stderr, "PF 1/1");
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, " SACCH NSF");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
|
||||
|
||||
//I'm placing this here, my observation is that SACCH NSF
|
||||
//is almost always, if not always, just IDLE
|
||||
else fprintf (stderr, " IDLE");
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -269,7 +247,15 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
// if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", check, crc);
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//reset the sacch field -- Github Issue #118
|
||||
@@ -296,9 +282,10 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
else fprintf (stderr, " ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
fprintf (stderr, "PF %d/4", part_of_frame+1);
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, " SACCH SF%d", sf);
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
@@ -332,25 +319,26 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
NXDN_SACCH_Full_decode (opts, state);
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
// if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
|
||||
}
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
|
||||
// for (int i = 0; i < 4; i++)
|
||||
// {
|
||||
// fprintf (stderr, "[%02X]", m_data[i]);
|
||||
// }
|
||||
// // if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type)
|
||||
{
|
||||
uint8_t deperm[500]; //348
|
||||
uint8_t depunc[500]; //406
|
||||
uint8_t trellis_buf[400]; //199
|
||||
uint8_t deperm[348]; //348
|
||||
uint8_t depunc[406]; //406
|
||||
uint8_t trellis_buf[208]; //199
|
||||
int id = 0;
|
||||
uint16_t crc = 0;
|
||||
uint16_t check = 0;
|
||||
@@ -379,26 +367,19 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[500]; //220, this one was way too small
|
||||
uint8_t temp[406];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[52]; //26
|
||||
uint8_t m_data[26]; //26
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
|
||||
for (int i = 0; i < 406; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
temp[i+203] = 0;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 207U; i++)
|
||||
for (int i = 0; i < 203; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
@@ -407,7 +388,7 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
}
|
||||
|
||||
//numerals seem okay now
|
||||
CNXDNConvolution_chainback(m_data, 203U);
|
||||
CNXDNConvolution_chainback(m_data, 199);
|
||||
|
||||
for(int i = 0; i < 26; i++)
|
||||
{
|
||||
@@ -428,22 +409,17 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
check = check | trellis_buf[i+184];
|
||||
}
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (type == 0) fprintf (stderr, " UDCH");
|
||||
if (type == 1) fprintf (stderr, " FACCH2");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (type == 0) fprintf (stderr, " UDCH");
|
||||
if (type == 1) fprintf (stderr, " FACCH2");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
uint8_t f2u_message_buffer[400]; //199
|
||||
memset (f2u_message_buffer, 0, sizeof(f2u_message_buffer));
|
||||
|
||||
//just going to leave this all here in case its needed, like in cac,
|
||||
//don't have any samples with f2 or udch data in it
|
||||
for (int i = 0; i < 199-8; i++)
|
||||
for (int i = 0; i < 199-8-15; i++)
|
||||
{
|
||||
f2u_message_buffer[i] = trellis_buf[i+8];
|
||||
}
|
||||
@@ -453,11 +429,11 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
else if (opts->aggressive_framesync == 0)
|
||||
{
|
||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
// else if (opts->aggressive_framesync == 0)
|
||||
// {
|
||||
// if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
|
||||
// if (type == 0) {} //need handling for user data (text messages and AVL)
|
||||
// }
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -470,6 +446,14 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
if (i == 13) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
// if (crc != check) fprintf (stderr, " CRC ERR ");
|
||||
|
||||
if (type == 0)
|
||||
@@ -490,9 +474,9 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
|
||||
void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
{
|
||||
uint8_t deperm[500]; //300
|
||||
uint8_t depunc[500]; //350
|
||||
uint8_t trellis_buf[400]; //171
|
||||
uint8_t deperm[300]; //300
|
||||
uint8_t depunc[350]; //350
|
||||
uint8_t trellis_buf[176]; //176
|
||||
int id = 0;
|
||||
int ran = 0;
|
||||
uint16_t crc = 0;
|
||||
@@ -521,21 +505,19 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[360];
|
||||
uint8_t temp[179];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[52]; //26
|
||||
uint8_t m_data[22]; //26
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
|
||||
for (int i = 0; i < 350; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 179U; i++)
|
||||
for (int i = 0; i < 175; i++) //179
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
@@ -543,7 +525,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 175U);
|
||||
CNXDNConvolution_chainback(m_data, 171); //175
|
||||
|
||||
for(int i = 0; i < 22; i++)
|
||||
{
|
||||
@@ -559,11 +541,11 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
|
||||
crc = crc16cac(trellis_buf, 171);
|
||||
|
||||
uint8_t cac_message_buffer[400]; //171
|
||||
uint8_t cac_message_buffer[147]; //171
|
||||
memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
|
||||
|
||||
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field
|
||||
for (int i = 0; i < 160; i++)
|
||||
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field and ending crc
|
||||
for (int i = 0; i < 147; i++)
|
||||
{
|
||||
cac_message_buffer[i] = trellis_buf[i+8];
|
||||
}
|
||||
@@ -589,7 +571,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
}
|
||||
|
||||
if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, cac_message_buffer);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, cac_message_buffer);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -613,9 +595,9 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
fprintf (stderr, " SCCH");
|
||||
|
||||
//see about initializing these variables
|
||||
uint8_t deperm[200]; //60
|
||||
uint8_t depunc[200]; //72
|
||||
uint8_t trellis_buf[400]; //32
|
||||
uint8_t deperm[60]; //60
|
||||
uint8_t depunc[72]; //72
|
||||
uint8_t trellis_buf[32]; //32
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
@@ -645,27 +627,20 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[90];
|
||||
uint8_t temp[72];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[10]; //5
|
||||
uint8_t m_data[5]; //5
|
||||
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
|
||||
for (int i = 0; i < 72; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
temp[i+72] = 0;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 36U; i++)
|
||||
for (int i = 0; i < 36; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
@@ -673,7 +648,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 32U);
|
||||
CNXDNConvolution_chainback(m_data, 32);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
@@ -724,15 +699,9 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
|
||||
//NOTE: scch has its own message format, and thus, doesn't go to content element decoding
|
||||
//like everything else does
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (crc == check) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
@@ -743,7 +712,13 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
// if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", check, crc);
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
@@ -752,9 +727,9 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
|
||||
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type)
|
||||
{
|
||||
uint8_t deperm[300]; //144
|
||||
uint8_t depunc[300]; //192
|
||||
uint8_t trellis_buf[600]; //96
|
||||
uint8_t deperm[144]; //144
|
||||
uint8_t depunc[192]; //192
|
||||
uint8_t trellis_buf[96]; //96
|
||||
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached
|
||||
uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
|
||||
uint16_t crc[2]; //crc calculated by function
|
||||
@@ -762,10 +737,10 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
||||
int out;
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[500];
|
||||
uint8_t temp[192];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[40]; //13
|
||||
uint8_t m_data[12]; //13
|
||||
memset (temp, 0, sizeof(temp));
|
||||
memset (m_data, 0, sizeof(m_data));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
@@ -789,17 +764,10 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
||||
}
|
||||
|
||||
for (int i = 0; i < 192; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
temp[i+192] = 0;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 100U; i++)
|
||||
for (int i = 0; i < 96; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
@@ -807,7 +775,7 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 96U);
|
||||
CNXDNConvolution_chainback(m_data, 92);
|
||||
|
||||
for(int i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -833,25 +801,22 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
||||
for (int i = 0; i < 12; i++) f3_udch2_bytes[i+(j*12)] = m_data[i];
|
||||
}
|
||||
|
||||
if (crc[0] != check[0] || crc[1] != check[1])
|
||||
{
|
||||
if (type == 0) fprintf (stderr, " UDCH2");
|
||||
if (type == 1) fprintf (stderr, " FACCH3");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (type == 0) fprintf (stderr, " UDCH2");
|
||||
if (type == 1) fprintf (stderr, " FACCH3");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
|
||||
if (crc[0] == check[0] && crc[1] == check[1])
|
||||
{
|
||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
else if (opts->aggressive_framesync == 0)
|
||||
{
|
||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
// else if (opts->aggressive_framesync == 0)
|
||||
// {
|
||||
// if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
// if (type == 0) {} //need handling for user data (text messages and AVL)
|
||||
// }
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -864,8 +829,17 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
||||
if (i == 12) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", f3_udch2_bytes[i]);
|
||||
}
|
||||
// fprintf (stderr, " - %03X %03X", check[0], crc[0]);
|
||||
// fprintf (stderr, " - %03X %03X", check[1], crc[1]);
|
||||
|
||||
if ( (crc[0] != check[0] || crc[1] != check[1]) && opts->payload == 1)
|
||||
{
|
||||
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// fprintf (stderr, " - %03X %03X", check[0], crc[0]);
|
||||
// fprintf (stderr, " - %03X %03X", check[1], crc[1]);
|
||||
}
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
|
||||
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
uint8_t SACCH[400]; //72
|
||||
uint8_t SACCH[72]; //72
|
||||
uint8_t sacch_bytes[9];
|
||||
|
||||
uint32_t i;
|
||||
uint8_t CrcCorrect = 1;
|
||||
|
||||
memset (SACCH, 0, sizeof (SACCH));
|
||||
memset (sacch_bytes, 0, sizeof (sacch_bytes));
|
||||
|
||||
/* Consider all SACCH CRC parts as correct */
|
||||
CrcCorrect = 1;
|
||||
@@ -35,12 +38,23 @@ void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
|
||||
/* Decodes the element content */
|
||||
// currently only going to run this if all four CRCs are good
|
||||
if (CrcCorrect == 1) NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, SACCH);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, SACCH);
|
||||
|
||||
//reset the sacch field -- Github Issue #118
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Full SACCH Payload ");
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
sacch_bytes[i] = (uint8_t)ConvertBitIntoBytes(&SACCH[i*8], 8);
|
||||
fprintf (stderr, "[%02X]", sacch_bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* End NXDN_SACCH_Full_decode() */
|
||||
|
||||
@@ -60,6 +74,8 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
MessageType |= (ElementsContent[6] & 1) << 1;
|
||||
MessageType |= (ElementsContent[7] & 1) << 0;
|
||||
|
||||
nxdn_message_type (opts, state, MessageType);
|
||||
|
||||
/* Save the "F1" and "F2" flags */
|
||||
state->NxdnElementsContent.F1 = ElementsContent[0];
|
||||
state->NxdnElementsContent.F2 = ElementsContent[1];
|
||||
@@ -128,6 +144,10 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
NXDN_decode_VCALL(opts, state, ElementsContent);
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
|
||||
#ifdef LIMAZULUTWEAKS
|
||||
; //do nothing -- testing errors on CAC messages when returning quickly from RTCH
|
||||
#else
|
||||
|
||||
//tune back to CC here - save about 1-2 seconds
|
||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
||||
{
|
||||
@@ -143,18 +163,23 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
//extra safeguards due to sync issues with NXDN
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
memset(state->active_channel, 0, sizeof(state->active_channel));
|
||||
opts->p25_is_tuned = 0;
|
||||
rtl_udp_tune (opts, state, state->p25_cc_freq);
|
||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||
#endif
|
||||
}
|
||||
|
||||
state->last_cc_sync_time = time(NULL); //allow tuners a second to catch up, particularly rtl input
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
break;
|
||||
|
||||
//Idle
|
||||
@@ -173,8 +198,6 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
}
|
||||
} /* End switch(MessageType) */
|
||||
|
||||
nxdn_message_type (opts, state, MessageType);
|
||||
|
||||
} /* End NXDN_Elements_Content_decode() */
|
||||
|
||||
//externalize multiple sub-element handlers
|
||||
@@ -570,9 +593,10 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
}
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
//extra safeguards due to sync issues with NXDN
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
@@ -581,7 +605,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
//
|
||||
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
|
||||
@@ -599,6 +623,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
fprintf (stderr, " Key Loaded: %lld", state->rkey_array[DestinationID]);
|
||||
}
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -791,7 +816,7 @@ void NXDN_decode_srv_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
|
||||
//poll for current frequency, will always be the control channel
|
||||
//this PDU is constantly pumped out on the CC CAC Message
|
||||
if (opts->p25_trunk == 1)
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) //changed this so the rtl tuning lag doesn't set RTCH frequency after tuning but before landing
|
||||
{
|
||||
long int ccfreq = 0;
|
||||
//if using rigctl, we can poll for the current frequency
|
||||
@@ -801,7 +826,7 @@ void NXDN_decode_srv_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||
}
|
||||
//if using rtl input, we can ask for the current frequency tuned
|
||||
else if (opts->audio_in_type == 3)
|
||||
else if (opts->audio_in_type == 3) //after changing to rtl_dev_tune, this may lag a bit due to delay in sample delivery?
|
||||
{
|
||||
ccfreq = (long int)opts->rtlsdr_center_freq;
|
||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||
@@ -1125,56 +1150,9 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
|
||||
else if (state->rkey_array[DestinationID] != 0) state->R = state->rkey_array[DestinationID];
|
||||
|
||||
// #ifdef LIMAZULUTWEAKS
|
||||
|
||||
// //LimaZulu specific tweak, load keys from frequency value, if avalable -- untested
|
||||
|
||||
// long int freq = 0;
|
||||
// uint8_t hash_bits[24];
|
||||
// memset (hash_bits, 0, sizeof(hash_bits));
|
||||
// uint16_t limazulu = 0;
|
||||
|
||||
// //if not available, then poll rigctl if its available
|
||||
// if (opts->use_rigctl == 1)
|
||||
// freq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
|
||||
// //if using rtl input, we can ask for the current frequency tuned
|
||||
// else if (opts->audio_in_type == 3)
|
||||
// freq = (long int)opts->rtlsdr_center_freq;
|
||||
|
||||
// //freq = 167831250; //hardset for testing
|
||||
|
||||
// //since a frequency value will be larger than the 16-bit max, we need to hash it first
|
||||
// //the hash has to be run the same way as the import, so at a 24-bit depth, which hopefully
|
||||
// //will not lead to any duplicate key loads due to multiple CRC16 collisions on a larger value?
|
||||
// for (int i = 0; i < 24; i++)
|
||||
// hash_bits[i] = ((freq << i) & 0x800000) >> 23; //load into array for CRC16
|
||||
|
||||
// if (freq) limazulu = ComputeCrcCCITT16d (hash_bits, 24);
|
||||
// limazulu = limazulu & 0xFFFF; //make sure no larger than 16-bits
|
||||
|
||||
// fprintf (stderr, "%s", KCYN);
|
||||
// if (freq) fprintf (stderr, "\n Freq: %ld - Freq Hash: %d", freq, limazulu);
|
||||
// if (state->rkey_array[limazulu] != 0) fprintf (stderr, " - Key Loaded: %lld", state->rkey_array[limazulu]);
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// if (state->rkey_array[limazulu] != 0)
|
||||
// state->R = state->rkey_array[limazulu];
|
||||
|
||||
// #endif //end LIMAZULUTWEAKS
|
||||
|
||||
//Don't zero key if no keyloader
|
||||
if (CipherType != 0x1 && state->keyloader == 1) state->R = 0;
|
||||
|
||||
//NOTE: Broadcast Call appears to have values that aren't typical for VCALL,
|
||||
//so not applying any settings below if CallType == 0 (BC Call)
|
||||
|
||||
//NOTE: Above note may be in error; its possible that the issues I was having
|
||||
//was from not resetting the entire SACCH superframe after reading it, and
|
||||
//the samples in question having interwoven ALIAS and VCALL, and bad settings
|
||||
//coming from a missed SF Part of Frame, if not reset, we could skip a SF POF
|
||||
//and still believe we have a good decode -- will need further testing #118
|
||||
|
||||
/* Print the "Cipher Type" */
|
||||
if(CipherType != 0 && MessageType == 0x1)
|
||||
{
|
||||
@@ -1384,8 +1362,8 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
//add current active to display string -- may need tweaking on if to use rep1 (active ch), or rep2 (home prefix)
|
||||
if (rep1 != 0 && rep1 != 31)
|
||||
{
|
||||
if (gu == 0) sprintf (state->active_channel[rep1], "Active Ch: %d TG: %d-%d; ", rep1, rep2, id); //Group TG
|
||||
else sprintf (state->active_channel[rep1], "Active Ch: %d TGT: %d-%d; ", rep1, rep2, id); //Private TGT
|
||||
if (gu == 0) sprintf (state->active_channel[rep1], "Active Group Ch: %d TG: %d-%d; ", rep1, rep2, id); //Group TG
|
||||
else sprintf (state->active_channel[rep1], "Active Private Ch: %d TGT: %d-%d; ", rep1, rep2, id); //Private TGT
|
||||
state->last_active_time = time(NULL);
|
||||
}
|
||||
|
||||
@@ -1431,7 +1409,8 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
//check to see if the source/target candidate is blocked first
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0)) //DE is digital encrypted, B is block
|
||||
{
|
||||
if (state->p25_cc_freq != 0 && state->last_vc_sync_time > 1 && freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
//will need to monitor, 1 second may be too long on idas, may need to try 0 or manipulate another way
|
||||
if (state->p25_cc_freq != 0 && ((time(NULL) - state->last_vc_sync_time) > 1) && freq != 0)
|
||||
{
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
@@ -1452,9 +1431,10 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
if (state->rkey_array[id] != 0) state->R = state->rkey_array[id];
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
//extra safeguards due to sync issues with NXDN
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
@@ -1462,13 +1442,14 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
state->last_vc_sync_time = time(NULL); //should we use this here, or not?
|
||||
//
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
//check the rkey array for a scrambler key value
|
||||
//TGT ID and Key ID could clash though if csv or system has both with different keys
|
||||
if (state->rkey_array[id] != 0) state->R = state->rkey_array[id];
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t facch_bits_b[144];
|
||||
uint8_t cac_bits[300];
|
||||
uint8_t facch2_bits[348]; //facch2 or udch, same amount of bits
|
||||
uint8_t facch3_bits[288]; //facch3 or udch2, same amoount of bits
|
||||
uint8_t facch3_bits[288]; //facch3 or udch2, same amount of bits
|
||||
|
||||
//nxdn bit buffer, for easy assignment handling
|
||||
int nxdn_bit_buffer[364];
|
||||
@@ -252,7 +252,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "L%02X - ", lich);
|
||||
}
|
||||
else if (voice || facch || sacch || facch2 || cac)
|
||||
else if (voice || facch || sacch || facch2 || udch || cac)
|
||||
{
|
||||
if (opts->frame_nxdn48 == 1)
|
||||
{
|
||||
@@ -396,6 +396,9 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
#endif //end LIMAZULUTWEAKS
|
||||
|
||||
if (opts->scanner_mode == 1)
|
||||
state->last_cc_sync_time = time(NULL) + 2; //add a little extra hangtime between resuming scan
|
||||
|
||||
//Option/Steal Flags echoed in Voice, V+F, or Data
|
||||
if (voice && !facch) //voice only, no facch steal
|
||||
{
|
||||
@@ -461,9 +464,18 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 1);
|
||||
|
||||
//SHOULD be okay to run facch1's again on steal frames, will need testing
|
||||
// if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
// if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
|
||||
//only run facch in second slot if its not equal to the first one
|
||||
//ideally, this would work better AFTER decoding/FEC
|
||||
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
|
||||
if (facch & 2)
|
||||
{
|
||||
if (memcmp (facch_bits_a, facch_bits_b, 144) != 0)
|
||||
nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
}
|
||||
|
||||
if (voice)
|
||||
{
|
||||
//restore MBE file open here
|
||||
@@ -488,6 +500,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
//may need to reconsider this, due to double FACCH1 steals on some Type-C (ASSGN_DUP, etc) and Conventional Systems (random IDLE FACCH1 steal for no reason)
|
||||
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice frames mixing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,9 +295,20 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
//tune back to CC here - save about 1-2 seconds
|
||||
else if (lc_format == 0x4F) //# Call Termination/Cancellation
|
||||
{
|
||||
fprintf (stderr, " Call Termination/Cancellation");
|
||||
fprintf (stderr, " Call Termination");
|
||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
||||
{
|
||||
|
||||
//Will we need to check for a symbolrate change here, can a P25p2 TDMA-CC system
|
||||
//revert back to a phase 1 traffic channel or carry a phase 1 traffic channel?
|
||||
|
||||
//clear heuristics from current traffic channel
|
||||
if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1)
|
||||
{
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -316,9 +327,10 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->payload_algid = 0;
|
||||
@@ -331,7 +343,8 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
sprintf (state->active_channel[1], "%s", "");
|
||||
opts->p25_is_tuned = 0;
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||
rtl_udp_tune (opts, state, state->p25_cc_freq);
|
||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,6 +459,9 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
|
||||
//reset dropbytes - skip first 11 for LCW
|
||||
state->dropL = 267;
|
||||
|
||||
//set vc counter to 0
|
||||
state->p25vc = 0;
|
||||
|
||||
@@ -466,14 +469,24 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
||||
{
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX", algidhex, kidhex, mihex1, mihex2);
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
if (state->R != 0 && state->payload_algid == 0xAA)
|
||||
{
|
||||
fprintf (stderr, " Key: %010llX", state->R);
|
||||
opts->unmute_encrypted_p25 = 1;
|
||||
}
|
||||
else if (state->payload_algid != 0 && state->payload_algid != 0x80)
|
||||
{
|
||||
//may want to mute this again, or may not want to
|
||||
opts->unmute_encrypted_p25 = 0;
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC");
|
||||
|
||||
@@ -171,6 +171,8 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
|
||||
// TODO: error correction of the LSD bytes...
|
||||
// TODO: do something useful with the LSD bytes...
|
||||
|
||||
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
||||
}
|
||||
|
||||
// IMBE 9
|
||||
|
||||
@@ -172,6 +172,8 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
// TODO: error correction of the LSD bytes...
|
||||
// TODO: do something useful with the LSD bytes...
|
||||
|
||||
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
||||
}
|
||||
|
||||
// IMBE 9
|
||||
@@ -183,6 +185,9 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
//set vc counter to 0
|
||||
state->p25vc = 0;
|
||||
|
||||
//reset dropbytes -- skip first 11 for next LCW
|
||||
state->dropL = 267;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
@@ -366,15 +371,24 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
if (irrecoverable_errors == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX", algidhex, kidhex, mihex1, mihex2);
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
if (state->R != 0 && state->payload_algid == 0xAA)
|
||||
{
|
||||
fprintf (stderr, " Key: %010llX", state->R);
|
||||
opts->unmute_encrypted_p25 = 1;
|
||||
}
|
||||
else if (state->payload_algid != 0 && state->payload_algid != 0x80)
|
||||
{
|
||||
//may want to mute this again, or may not want to
|
||||
opts->unmute_encrypted_p25 = 0;
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC");
|
||||
@@ -390,4 +404,45 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//run LFSR on the MI if we have irrecoverable errors here
|
||||
if (irrecoverable_errors && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
|
||||
{
|
||||
LFSRP(state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
void LFSRP(dsd_state * state)
|
||||
{
|
||||
//rework for P2 TDMA support
|
||||
unsigned long long int lfsr = 0;
|
||||
if (state->currentslot == 0)
|
||||
lfsr = state->payload_miP;
|
||||
|
||||
if (state->currentslot == 1)
|
||||
lfsr = state->payload_miN;
|
||||
|
||||
int cnt = 0;
|
||||
for(cnt=0;cnt<64;cnt++)
|
||||
{
|
||||
// Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
|
||||
unsigned long long int bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1;
|
||||
lfsr = (lfsr << 1) | (bit);
|
||||
}
|
||||
|
||||
if (state->currentslot == 0)
|
||||
state->payload_miP = lfsr;
|
||||
|
||||
if (state->currentslot == 1)
|
||||
state->payload_miN = lfsr;
|
||||
|
||||
//print current ENC identifiers already known and new calculated MI
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (state->currentslot == 0)
|
||||
fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algid, state->payload_keyid, state->payload_miP);
|
||||
if (state->currentslot == 1)
|
||||
fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algidR, state->payload_keyidR, state->payload_miN);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
@@ -337,14 +337,24 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channelt >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
@@ -355,13 +365,15 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -421,15 +433,26 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channelt >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
@@ -440,13 +463,15 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,4 +37,9 @@ processTDU (dsd_opts* opts, dsd_state* state)
|
||||
//reset some strings -- since its a tdu, blank out any call strings, only want during actual call
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
|
||||
//zero out on termination
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
state->payload_miP = 0;
|
||||
}
|
||||
|
||||
@@ -446,4 +446,9 @@ processTDULC (dsd_opts* opts, dsd_state* state)
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
|
||||
//zero out on termination
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
state->payload_miP = 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ int dibit = 0;
|
||||
int vc_counter = 0;
|
||||
int framing_counter = 0;
|
||||
|
||||
unsigned long long int isch = 0;
|
||||
uint64_t isch = 0;
|
||||
int isch_decoded = -1;
|
||||
int p2_duid[8] = {0};
|
||||
int16_t duid_decoded = 0;
|
||||
@@ -479,9 +479,9 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
||||
//Cygwin OSS Slot Preference Pre-emption shim
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
//set to 16 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 16;
|
||||
else state->dmrburstR = 16;
|
||||
//set to 21 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -552,6 +552,7 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, " ALG ID 0x%02X", state->payload_algid);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
|
||||
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
|
||||
fprintf (stderr, " ESSB");
|
||||
}
|
||||
|
||||
@@ -567,6 +568,7 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, " ALG ID 0x%02X", state->payload_algidR);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
|
||||
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
|
||||
fprintf (stderr, " ESSB");
|
||||
}
|
||||
|
||||
@@ -574,7 +576,11 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (ec == -1 || ec >= 15)
|
||||
{
|
||||
//ESS R-S Failure
|
||||
//ESS R-S Failure -- run LFSR on current MI if applicable
|
||||
if (state->currentslot == 0 && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
|
||||
LFSRP(state);
|
||||
if (state->currentslot == 1 && state->payload_algidR != 0x80 && state->payload_keyidR != 0 && state->payload_miN != 0)
|
||||
LFSRP(state);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
@@ -640,9 +646,9 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
||||
//Cygwin OSS Slot Preference Pre-emption shim
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
//set to 16 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 16;
|
||||
else state->dmrburstR = 16;
|
||||
//set to 21 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -651,6 +657,13 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
process_ESS(opts, state);
|
||||
|
||||
//reset drop bytes after a 2V
|
||||
if (state->currentslot == 0 && state->payload_algid == 0xAA)
|
||||
state->dropL = 256;
|
||||
|
||||
if (state->currentslot == 1 && state->payload_algidR == 0xAA)
|
||||
state->dropR = 256;
|
||||
|
||||
}
|
||||
|
||||
//P2 Data Unit ID
|
||||
@@ -872,16 +885,5 @@ void processP2 (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_stereo = 0;
|
||||
state->p2_is_lcch = 0;
|
||||
|
||||
//bugfix for OSS slot preferred pre-emption on dual voices
|
||||
//in case or marginal signal or bad decoding and both get stuck on 16, indefinitely muting the non-preferred slot
|
||||
//BUG: This causes an annoying blink blink in ncurses, just FYI -- find a better workaround
|
||||
#ifdef AERO_BUILD
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
//set both to blank value
|
||||
state->dmrburstL = 17;
|
||||
state->dmrburstR = 17;
|
||||
}
|
||||
#endif
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
190
src/p25p2_vpdu.c
190
src/p25p2_vpdu.c
@@ -118,19 +118,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
// //testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -148,13 +137,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,19 +194,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -232,13 +212,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,19 +302,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -353,14 +324,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
j = 8; //break loop
|
||||
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,19 +404,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -461,13 +423,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -524,19 +488,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -554,13 +507,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
if (state->synctype == 0 || state->synctype == 1) state->p25_vc_freq[0] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -680,19 +635,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -710,14 +654,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -857,19 +803,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -889,15 +824,17 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
//probably best to only set these when really tuning
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -979,19 +916,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -1011,15 +937,17 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
//probably best to only set these when really tuning
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1092,19 +1020,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channelt >> 12] == 1)
|
||||
{
|
||||
@@ -1122,13 +1040,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1623,7 +1543,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
int lcolorcode = ((MAC[12+len_a] & 0xF) << 8) | MAC[13+len_a];
|
||||
fprintf (stderr, "\n Network Status Broadcast - Extended \n");
|
||||
fprintf (stderr, " LRA [%02X] WACN [%05X] SYSID [%03X] NAC [%03X] CHAN-T [%04X] CHAN-R [%04X]", lra, lwacn, lsysid, lcolorcode, channelt, channelr);
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
state->p25_cc_freq = process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
state->p25_cc_is_tdma = 1; //flag on for CC tuning purposes when system is qpsk
|
||||
if (state->p2_hardset == 0 ) //state->p2_is_lcch == 1 shim until CRC is working, prevent bogus data
|
||||
|
||||
@@ -120,6 +120,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
|
||||
state->dmrburstL = 20;
|
||||
fprintf (stderr, "\n VCH 0 - ");
|
||||
@@ -142,6 +143,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
|
||||
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -153,6 +155,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->payload_algidR = 0; //zero this out as well
|
||||
|
||||
state->dmrburstR = 20;
|
||||
@@ -176,6 +179,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
|
||||
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -194,6 +198,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
state->dmrburstL = 23;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
@@ -217,6 +222,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->dmrburstR = 23;
|
||||
state->payload_algidR = 0;
|
||||
state->payload_keyidR = 0;
|
||||
@@ -270,13 +276,13 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
state->dmrburstL = 21;
|
||||
state->dmrburstL = 22;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmrburstR = 21;
|
||||
state->dmrburstR = 22;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
@@ -369,6 +375,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
|
||||
state->dmrburstL = 20;
|
||||
fprintf (stderr, "\n VCH 0 - ");
|
||||
@@ -391,6 +398,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
|
||||
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -402,6 +410,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
|
||||
state->dmrburstR = 20;
|
||||
fprintf (stderr, "\n VCH 1 - ");
|
||||
@@ -424,6 +433,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
|
||||
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -441,6 +451,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
state->dmrburstL = 23;
|
||||
state->payload_algid = 0; //zero this out as well
|
||||
state->payload_keyid = 0;
|
||||
@@ -464,6 +475,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->dmrburstR = 23;
|
||||
state->payload_algidR = 0; //zero this out as well
|
||||
state->payload_keyidR = 0;
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
#include <rtl-sdr.h>
|
||||
#include "dsd.h"
|
||||
|
||||
//#define DEFAULT_SAMPLE_RATE 48000 //moved to opts->rtl_bandwidth
|
||||
#define DEFAULT_SAMPLE_RATE 48000
|
||||
#define DEFAULT_BUF_LENGTH (1 * 16384)
|
||||
#define MAXIMUM_OVERSAMPLE 16 //16
|
||||
#define MAXIMUM_OVERSAMPLE 16
|
||||
#define MAXIMUM_BUF_LENGTH (MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH)
|
||||
#define AUTO_GAIN -100
|
||||
#define BUFFER_DUMP 4096
|
||||
#define BUFFER_DUMP 4096
|
||||
|
||||
#define FREQUENCIES_LIMIT 1000
|
||||
|
||||
@@ -46,7 +46,8 @@ static int ACTUAL_BUF_LENGTH;
|
||||
static int *atan_lut = NULL;
|
||||
static int atan_lut_size = 131072; /* 512 KB */
|
||||
static int atan_lut_coef = 8;
|
||||
//new for UDP
|
||||
|
||||
//UDP -- keep for compatibility reasons
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
static pthread_t socket_freq;
|
||||
@@ -57,7 +58,7 @@ int bandwidth_divisor = 48000; //divide bandwidth by this to get multiplier for
|
||||
|
||||
short int volume_multiplier;
|
||||
short int port;
|
||||
//
|
||||
|
||||
struct dongle_state
|
||||
{
|
||||
int exit_flag;
|
||||
@@ -462,11 +463,14 @@ void dc_block_filter(struct demod_state *fm)
|
||||
}
|
||||
fm->dc_avg = avg;
|
||||
}
|
||||
|
||||
int rms(int16_t *samples, int len, int step)
|
||||
//TODO: Fix This so we don't get random negative values in Cygwin (or 32-bit builds?)
|
||||
//Fixed -- I honestly think the issue is Cygwin can't keep up and if it can't run enough samples in the other thread,
|
||||
//then it reports some jank values, really unsure, I've never seen the issue in Linux side though
|
||||
long int rms(int16_t *samples, int len, int step)
|
||||
/* largely lifted from rtl_power */
|
||||
{
|
||||
int i;
|
||||
long int rms;
|
||||
long p, t, s;
|
||||
double dc, err;
|
||||
|
||||
@@ -480,7 +484,10 @@ int rms(int16_t *samples, int len, int step)
|
||||
dc = (double)(t*step) / (double)len;
|
||||
err = t * 2 * dc - dc * dc * len;
|
||||
|
||||
return (int)sqrt((p-err) / len);
|
||||
rms = (long int)sqrt((p-err) / len);
|
||||
//going with a value that's easy to figure out when its done the thing
|
||||
if (rms < 0){ rms = 999; } //need to text nxdn with this setup to make sure it isn't broken in Windows Cygwin now
|
||||
return rms;
|
||||
}
|
||||
|
||||
void full_demod(struct demod_state *d)
|
||||
@@ -597,7 +604,6 @@ static void *demod_thread_fn(void *arg)
|
||||
|
||||
int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
|
||||
{
|
||||
//target_gain = 36;
|
||||
int i, r, err1, err2, count, nearest;
|
||||
int* gains;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
@@ -628,10 +634,9 @@ int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
|
||||
int r;
|
||||
r = rtlsdr_set_center_freq(dev, frequency);
|
||||
if (r < 0) {
|
||||
fprintf (stderr, "WARNING: Failed to set center freq.\n");
|
||||
fprintf (stderr, " (WARNING: Failed to set Center Frequency). \n");
|
||||
} else {
|
||||
//fprintf (stderr, "Tuned to %u Hz.\n", frequency);
|
||||
fprintf (stderr, "Tuned to center frequency %u Hz.\n", frequency);
|
||||
fprintf (stderr, " (Center Frequency: %u Hz.) \n", frequency);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -679,7 +684,6 @@ int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
||||
|
||||
int verbose_auto_gain(rtlsdr_dev_t *dev)
|
||||
{
|
||||
|
||||
int r;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
if (r != 0) {
|
||||
@@ -692,7 +696,6 @@ int verbose_auto_gain(rtlsdr_dev_t *dev)
|
||||
|
||||
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
||||
{
|
||||
//gain = 36;
|
||||
int r;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
if (r < 0) {
|
||||
@@ -710,7 +713,6 @@ int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
||||
|
||||
int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
|
||||
{
|
||||
//ppm_error = -2; //fix this opt arg to accept negative float values, i.e. float or double??
|
||||
int r;
|
||||
if (ppm_error == 0) {
|
||||
return 0;}
|
||||
@@ -732,25 +734,23 @@ int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
||||
return r;
|
||||
}
|
||||
|
||||
//static void optimal_settings(struct fm_state *fm, int freq, int hopping)
|
||||
static void optimal_settings(int freq, int rate) //
|
||||
static void optimal_settings(int freq, int rate)
|
||||
{
|
||||
// giant ball of hacks
|
||||
// seems unable to do a single pass, 2:1
|
||||
//int r, capture_freq, capture_rate;
|
||||
int capture_freq, capture_rate;
|
||||
struct dongle_state *d = &dongle;
|
||||
struct demod_state *dm = &demod;
|
||||
struct controller_state *cs = &controller;
|
||||
dm->downsample = (1000000 / dm->rate_in) + 1;
|
||||
dm->downsample = (1000000 / dm->rate_in) + 1; //dm->rate_in is the rtl_bandwidth value
|
||||
if (dm->downsample_passes) {
|
||||
dm->downsample_passes = (int)log2(dm->downsample) + 1;
|
||||
dm->downsample = 1 << dm->downsample_passes;
|
||||
}
|
||||
capture_freq = freq;
|
||||
capture_rate = dm->downsample * dm->rate_in;
|
||||
capture_rate = dm->downsample * dm->rate_in; //
|
||||
if (!d->offset_tuning) {
|
||||
capture_freq = freq + capture_rate/4;}
|
||||
capture_freq = freq + capture_rate/4;} //
|
||||
capture_freq += cs->edge * dm->rate_in / 2;
|
||||
dm->output_scale = (1<<15) / (128 * dm->downsample);
|
||||
if (dm->output_scale < 1) {
|
||||
@@ -759,6 +759,7 @@ static void optimal_settings(int freq, int rate) //
|
||||
dm->output_scale = 1;}
|
||||
d->freq = (uint32_t)capture_freq;
|
||||
d->rate = (uint32_t)capture_rate;
|
||||
// fprintf (stderr, "Capture Frequency: %i Rate: %i \n", capture_freq, capture_rate);
|
||||
}
|
||||
|
||||
static void *controller_thread_fn(void *arg)
|
||||
@@ -790,7 +791,6 @@ static void *controller_thread_fn(void *arg)
|
||||
/* Set the sample rate */
|
||||
verbose_set_sample_rate(dongle.dev, dongle.rate);
|
||||
fprintf (stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample);
|
||||
fprintf (stderr, "Press CTRL + C to close.\n");
|
||||
|
||||
while (!exitflag) {
|
||||
safe_cond_wait(&s->hop, &s->hop_m);
|
||||
@@ -807,20 +807,16 @@ static void *controller_thread_fn(void *arg)
|
||||
|
||||
void dongle_init(struct dongle_state *s)
|
||||
{
|
||||
//s->rate = DEFAULT_SAMPLE_RATE;
|
||||
s->rate = rtl_bandwidth;
|
||||
s->gain = AUTO_GAIN; // tenths of a dB
|
||||
s->mute = 0;
|
||||
s->direct_sampling = 0;
|
||||
s->offset_tuning = 0; //
|
||||
s->offset_tuning = 0; //E4000 tuners only
|
||||
s->demod_target = &demod;
|
||||
|
||||
}
|
||||
|
||||
void demod_init(struct demod_state *s)
|
||||
{
|
||||
//s->rate_in = DEFAULT_SAMPLE_RATE;
|
||||
//s->rate_out = DEFAULT_SAMPLE_RATE;
|
||||
s->rate_in = rtl_bandwidth;
|
||||
s->rate_out = rtl_bandwidth;
|
||||
s->squelch_level = 0;
|
||||
@@ -830,16 +826,16 @@ void demod_init(struct demod_state *s)
|
||||
s->downsample_passes = 0;
|
||||
s->comp_fir_size = 0;
|
||||
s->prev_index = 0;
|
||||
s->post_downsample = 1; // once this works, default = 4
|
||||
s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either
|
||||
s->custom_atan = 0;
|
||||
s->deemph = 0;
|
||||
s->rate_out2 = -1; // flag for disabled
|
||||
s->rate_out2 = rtl_bandwidth; // -1 flag for disabled -- this enables low_pass_real, seems to work okay
|
||||
s->mode_demod = &fm_demod;
|
||||
s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
|
||||
s->prev_lpr_index = 0;
|
||||
s->deemph_a = 0;
|
||||
s->now_lpr = 0;
|
||||
s->dc_block = 0;
|
||||
s->dc_block = 1; //enabling by default, but offset tuning is also enabled, so center spike shouldn't be an issue
|
||||
s->dc_avg = 0;
|
||||
pthread_rwlock_init(&s->rw, NULL);
|
||||
pthread_cond_init(&s->ready, NULL);
|
||||
@@ -856,7 +852,6 @@ void demod_cleanup(struct demod_state *s)
|
||||
|
||||
void output_init(struct output_state *s)
|
||||
{
|
||||
//s->rate = DEFAULT_SAMPLE_RATE;
|
||||
s->rate = rtl_bandwidth;
|
||||
pthread_rwlock_init(&s->rw, NULL);
|
||||
pthread_cond_init(&s->ready, NULL);
|
||||
@@ -904,7 +899,8 @@ void sanity_checks(void)
|
||||
}
|
||||
|
||||
}
|
||||
//UDP remote all below HERE
|
||||
|
||||
//UDP remote stuff
|
||||
static unsigned int chars_to_int(unsigned char* buf) {
|
||||
|
||||
int i;
|
||||
@@ -918,9 +914,7 @@ static unsigned int chars_to_int(unsigned char* buf) {
|
||||
}
|
||||
|
||||
static void *socket_thread_fn(void *arg) {
|
||||
//struct fm_state *fm = arg;
|
||||
struct demod_state *d = static_cast<demod_state*>(arg);
|
||||
//int port = 6020;
|
||||
int r, n;
|
||||
int sockfd, newsockfd, portno;
|
||||
socklen_t clilen;
|
||||
@@ -952,114 +946,34 @@ static void *socket_thread_fn(void *arg) {
|
||||
while((n = read(sockfd,buffer,5)) != 0) {
|
||||
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
|
||||
|
||||
dongle.freq = new_freq;
|
||||
optimal_settings(new_freq, demod.rate_in);
|
||||
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
||||
//verbose_set_frequency (dongle.dev, new_freq);
|
||||
//fprintf (stderr, "Tuning to: %d [Hz] (central freq: %d [Hz])\n", new_freq, new_freq + freq_offset);
|
||||
fprintf (stderr, "\nTuning to: %d [Hz] \n", new_freq);
|
||||
}
|
||||
/*
|
||||
if(buffer[0] == 1) {
|
||||
// change demod type
|
||||
int type = chars_to_int(buffer);
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
fprintf (stderr, "Changing demod type to FM\n");
|
||||
fm->mode_demod = &fm_demod;
|
||||
break;
|
||||
case 1:
|
||||
fprintf (stderr, "Changing demod type to AM\n");
|
||||
fm->mode_demod = &am_demod;
|
||||
break;
|
||||
case 2:
|
||||
fprintf (stderr, "Changing demod type to USB\n");
|
||||
fm->mode_demod = &usb_demod;
|
||||
fm->custom_atan = 1;
|
||||
break;
|
||||
case 3:
|
||||
fprintf (stderr, "Changing demod type to LSB\n");
|
||||
fm->mode_demod = &lsb_demod;
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "Unknown demod type %d\n", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//SQUELCH HERE
|
||||
|
||||
if (buffer[0] == 2) {
|
||||
new_squelch = chars_to_int(buffer);
|
||||
demod.squelch_level = new_squelch; //demod, or d*? or d->
|
||||
//full_demod(d);
|
||||
//new_freq = 850000000;
|
||||
//dongle.freq = new_freq;
|
||||
//optimal_settings(new_freq, demod.rate_in); //hacky way to 'squelch', just setting it to a dead freq instead
|
||||
//rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
||||
fprintf (stderr, "Changing squelch to %d \n", new_squelch);
|
||||
}
|
||||
|
||||
/*
|
||||
if (buffer[0] == 3) {
|
||||
new_gain = chars_to_int(buffer);
|
||||
if (new_gain == AUTO_GAIN) {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
} else {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
new_gain = nearest_gain(new_gain);
|
||||
r = rtlsdr_set_tuner_gain(dev, new_gain);
|
||||
}
|
||||
|
||||
if (r != 0) {
|
||||
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
||||
} else if (new_gain == AUTO_GAIN) {
|
||||
fprintf (stderr, "Tuner gain set to automatic.\n");
|
||||
} else {
|
||||
fprintf (stderr, "Tuner gain set to %0.2f dB.\n", new_gain/10.0);
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (buffer[0] == 8) {
|
||||
agc_mode = chars_to_int(buffer);
|
||||
if (agc_mode == 0 || agc_mode == 1) {
|
||||
fprintf (stderr, "Setting AGC to %d\n", agc_mode);
|
||||
rtlsdr_set_agc_mode(dev, agc_mode);
|
||||
} else {
|
||||
fprintf (stderr, "Failed to set AGC to %d\n", agc_mode);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
//UDP Control all above HERE
|
||||
//UDP stuff end
|
||||
|
||||
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
|
||||
|
||||
fprintf (stderr, "Signal caught, exiting!\n");
|
||||
rtlsdr_cancel_async(dongle.dev);
|
||||
//cleanup_rtlsdr_stream(); //thank the wraith for this one...if it works...didn't work
|
||||
//_Exit(1);
|
||||
}
|
||||
|
||||
void open_rtlsdr_stream(dsd_opts *opts)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
int r;
|
||||
rtl_bandwidth = opts->rtl_bandwidth * 1000; //multiple by 1000 to get rate
|
||||
//rtl_bandwidth = 48000;
|
||||
rtl_bandwidth = opts->rtl_bandwidth * 1000; //reverted back to straight value
|
||||
bandwidth_multiplier = (bandwidth_divisor / rtl_bandwidth);
|
||||
//bandwidth_multiplier = 1;
|
||||
|
||||
//this needs to be initted first, then we set the parameters
|
||||
dongle_init(&dongle);
|
||||
demod_init(&demod);
|
||||
output_init(&output);
|
||||
@@ -1070,29 +984,23 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
controller.freq_len++;
|
||||
}
|
||||
|
||||
if (opts->rtlsdr_ppm_error > 0 || opts->rtlsdr_ppm_error < 0) { //this way will adjust PPM based on negative values as well
|
||||
if (opts->rtlsdr_ppm_error != 0) {
|
||||
dongle.ppm_error = opts->rtlsdr_ppm_error;
|
||||
fprintf (stderr, "Setting RTL PPM Error Set to %d\n", opts->rtlsdr_ppm_error);
|
||||
}
|
||||
|
||||
if (opts->audio_in_type == 3) {
|
||||
dongle.dev_index = opts->rtl_dev_index;
|
||||
//rtl_bandwidth = opts->rtl_bandwidth * 1000; //multiple by 1000 to get rate
|
||||
//rtl_bandwidth = 48000;
|
||||
//bandwidth_multiplier = rtl_bandwidth / bandwidth_divisor; //find multiple with no remainder if oddball number entered
|
||||
//bandwidth_multiplier = 1;
|
||||
demod.squelch_level = opts->rtl_squelch_level; //adding user definable squelch level to prevent false positives on account of noise in NXDN etc
|
||||
fprintf (stderr, "Setting RTL VFO Bandwidth to %d Hz\n", rtl_bandwidth);
|
||||
fprintf (stderr, "Setting RTL Sample Multiplier to %d\n", bandwidth_multiplier);
|
||||
fprintf (stderr, "Setting RTL Squelch Level to %d\n", demod.squelch_level);
|
||||
port = opts->rtl_udp_port;
|
||||
}
|
||||
|
||||
dongle.dev_index = opts->rtl_dev_index;
|
||||
// demod.squelch_level = opts->rtl_squelch_level; //no longer used here, used in framesync vc rms value under select conditions
|
||||
fprintf (stderr, "Setting RTL Bandwidth to %d Hz\n", rtl_bandwidth);
|
||||
// fprintf (stderr, "Setting RTL Sample Multiplier to %d\n", bandwidth_multiplier);
|
||||
fprintf (stderr, "Setting RTL RMS Squelch Level to %d\n", opts->rtl_squelch_level);
|
||||
if (opts->rtl_udp_port != 0) port = opts->rtl_udp_port; //set this here, only open socket thread if set
|
||||
if (opts->rtl_gain_value > 0) {
|
||||
dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm really works
|
||||
dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm works
|
||||
}
|
||||
volume_multiplier = opts->rtl_volume_multiplier;
|
||||
fprintf (stderr, "Setting RTL Volume Multiplier to %d\n", volume_multiplier);
|
||||
// fprintf (stderr, "Setting RTL Volume Multiplier to %d\n", volume_multiplier);
|
||||
|
||||
/* quadruple sample_rate to limit to Δθ to ±π/2 */
|
||||
demod.rate_in *= demod.post_downsample;
|
||||
|
||||
@@ -1103,24 +1011,16 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
if (controller.freq_len > 1) demod.terminate_on_squelch = 0;
|
||||
|
||||
ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
|
||||
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
||||
|
||||
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf (stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index);
|
||||
exit(1);
|
||||
} else {
|
||||
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index); //Kindly tell us which device we are using
|
||||
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index);
|
||||
}
|
||||
|
||||
// sigact.sa_handler = sighandler;
|
||||
// sigemptyset(&sigact.sa_mask);
|
||||
// sigact.sa_flags = 0;
|
||||
// sigaction(SIGINT, &sigact, NULL);
|
||||
// sigaction(SIGTERM, &sigact, NULL);
|
||||
// sigaction(SIGQUIT, &sigact, NULL);
|
||||
// sigaction(SIGPIPE, &sigact, NULL);
|
||||
|
||||
if (demod.deemph) {
|
||||
demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
|
||||
}
|
||||
@@ -1128,9 +1028,11 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
/* Set the tuner gain */
|
||||
if (dongle.gain == AUTO_GAIN) {
|
||||
verbose_auto_gain(dongle.dev);
|
||||
fprintf (stderr, "Setting RTL Autogain. \n");
|
||||
} else {
|
||||
dongle.gain = nearest_gain(dongle.dev, dongle.gain);
|
||||
verbose_gain_set(dongle.dev, dongle.gain);
|
||||
// fprintf (stderr, "Setting RTL Nearest Gain to %d. \n", dongle.gain); //seems to be working now
|
||||
}
|
||||
|
||||
verbose_ppm_set(dongle.dev, dongle.ppm_error);
|
||||
@@ -1142,7 +1044,8 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
usleep(100000);
|
||||
pthread_create(&demod.thread, NULL, demod_thread_fn, (void*)(&demod));
|
||||
pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void*)(&dongle));
|
||||
pthread_create(&socket_freq, NULL, socket_thread_fn, (void *)(&controller));
|
||||
//only create socket thread IF user specified (for legacy uses), else don't use it
|
||||
if (port != 0) pthread_create(&socket_freq, NULL, socket_thread_fn, (void *)(&controller));
|
||||
}
|
||||
|
||||
void cleanup_rtlsdr_stream()
|
||||
@@ -1155,8 +1058,6 @@ void cleanup_rtlsdr_stream()
|
||||
safe_cond_signal(&output.ready, &output.ready_m);
|
||||
safe_cond_signal(&controller.hop, &controller.hop_m);
|
||||
pthread_join(controller.thread, NULL);
|
||||
//add socket thread
|
||||
//pthread_join(socket_freq, NULL);
|
||||
|
||||
//dongle_cleanup(&dongle);
|
||||
demod_cleanup(&demod);
|
||||
@@ -1164,32 +1065,70 @@ void cleanup_rtlsdr_stream()
|
||||
controller_cleanup(&controller);
|
||||
|
||||
rtlsdr_close(dongle.dev);
|
||||
|
||||
}
|
||||
|
||||
//void get_rtlsdr_sample(int16_t *sample)
|
||||
//original for safe keeping
|
||||
// void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
||||
// {
|
||||
// if (output.queue.empty())
|
||||
// {
|
||||
// safe_cond_wait(&output.ready, &output.ready_m);
|
||||
// }
|
||||
// pthread_rwlock_wrlock(&output.rw);
|
||||
// *sample = output.queue.front() * volume_multiplier;
|
||||
// output.queue.pop();
|
||||
// pthread_rwlock_unlock(&output.rw);
|
||||
// }
|
||||
|
||||
//find way to modify this function to allow hopping (tuning) while squelched and send 0 sample?
|
||||
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if (output.queue.empty())
|
||||
{
|
||||
if (opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
//ncursesPrinter(opts, state);
|
||||
//printw ("\n\n\n HELP I'M LOCKED!\n");
|
||||
}
|
||||
safe_cond_wait(&output.ready, &output.ready_m);
|
||||
//goto END;
|
||||
}
|
||||
|
||||
pthread_rwlock_wrlock(&output.rw);
|
||||
//*sample = output.queue.front();
|
||||
|
||||
*sample = output.queue.front() * volume_multiplier; //try multiplying by numbers here for 'gain'
|
||||
*sample = output.queue.front() * volume_multiplier;
|
||||
output.queue.pop();
|
||||
pthread_rwlock_unlock(&output.rw);
|
||||
// END:
|
||||
// if (1 == 2)
|
||||
// {
|
||||
// fprintf (stderr, "This is a dumb thing to fix");
|
||||
// }
|
||||
}
|
||||
|
||||
//function may lag since it isn't running as its own thread
|
||||
void rtl_dev_tune(dsd_opts * opts, long int frequency)
|
||||
{
|
||||
int r;
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\nTuning to %lu Hz.", frequency);
|
||||
dongle.freq = opts->rtlsdr_center_freq = frequency;
|
||||
optimal_settings(dongle.freq, demod.rate_in);
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, " (Center Frequency: %u Hz.) \n", dongle.freq);
|
||||
r = rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
||||
if (r < 0)
|
||||
fprintf (stderr, " (WARNING: Failed to set Center Frequency %u). \n", dongle.freq);
|
||||
|
||||
pthread_rwlock_wrlock(&output.rw); //prevent possible segfault when cleaning the queue
|
||||
rtl_clean_queue();
|
||||
pthread_rwlock_unlock(&output.rw); //resume
|
||||
|
||||
}
|
||||
|
||||
//return RMS value (root means square) power level -- used as soft squelch inside of framesync
|
||||
long int rtl_return_rms()
|
||||
{
|
||||
long int sr = 0;
|
||||
#ifdef __arm__
|
||||
sr = 100;
|
||||
#else
|
||||
sr = rms(demod.lowpassed, demod.lp_len, 1);
|
||||
#endif
|
||||
return (sr);
|
||||
}
|
||||
|
||||
//simple function to clear the rtl sample queue when tuning and during other events (ncurses menu open/close)
|
||||
void rtl_clean_queue()
|
||||
{
|
||||
//insert method to clear the entire queue to prevent sample 'lag'
|
||||
std::queue<int16_t> empty; //create an empty queue
|
||||
std::swap( output.queue, empty ); //swap in empty queue to effectively zero out current queue
|
||||
}
|
||||
539
src/trellis.cpp
539
src/trellis.cpp
@@ -1,539 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor, G4KLX
|
||||
*
|
||||
* Heavy Modificatins of Original Code to work for DSD-FME
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "dsd.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
const unsigned int INTERLEAVE_TABLE[] = {
|
||||
0U, 1U, 8U, 9U, 16U, 17U, 24U, 25U, 32U, 33U, 40U, 41U, 48U, 49U, 56U, 57U, 64U, 65U, 72U, 73U, 80U, 81U, 88U, 89U, 96U, 97U,
|
||||
2U, 3U, 10U, 11U, 18U, 19U, 26U, 27U, 34U, 35U, 42U, 43U, 50U, 51U, 58U, 59U, 66U, 67U, 74U, 75U, 82U, 83U, 90U, 91U,
|
||||
4U, 5U, 12U, 13U, 20U, 21U, 28U, 29U, 36U, 37U, 44U, 45U, 52U, 53U, 60U, 61U, 68U, 69U, 76U, 77U, 84U, 85U, 92U, 93U,
|
||||
6U, 7U, 14U, 15U, 22U, 23U, 30U, 31U, 38U, 39U, 46U, 47U, 54U, 55U, 62U, 63U, 70U, 71U, 78U, 79U, 86U, 87U, 94U, 95U};
|
||||
|
||||
const unsigned char ENCODE_TABLE[] = {
|
||||
0U, 8U, 4U, 12U, 2U, 10U, 6U, 14U,
|
||||
4U, 12U, 2U, 10U, 6U, 14U, 0U, 8U,
|
||||
1U, 9U, 5U, 13U, 3U, 11U, 7U, 15U,
|
||||
5U, 13U, 3U, 11U, 7U, 15U, 1U, 9U,
|
||||
3U, 11U, 7U, 15U, 1U, 9U, 5U, 13U,
|
||||
7U, 15U, 1U, 9U, 5U, 13U, 3U, 11U,
|
||||
2U, 10U, 6U, 14U, 0U, 8U, 4U, 12U,
|
||||
6U, 14U, 0U, 8U, 4U, 12U, 2U, 10U};
|
||||
|
||||
const unsigned char DECODE_TABLE[] = { //flip the rows and columns, right?
|
||||
0,4,1,5,3,7,2,6,
|
||||
8,12,9,13,11,15,10,14,
|
||||
4,2,5,3,7,1,6,0,
|
||||
12,10,13,11,15,9,14,8,
|
||||
2,6,3,7,1,5,0,4,
|
||||
10,14,11,15,9,13,8,12,
|
||||
6,0,7,1,5,3,4,2,
|
||||
14,8,15,9,13,11,12,10
|
||||
};
|
||||
|
||||
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||
|
||||
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||
|
||||
unsigned char state = 0U;
|
||||
//rework quickHamming to accept unsigned intergers instead and go bit by bit
|
||||
int quickHamming(unsigned int butt, unsigned int farts)
|
||||
{
|
||||
unsigned int i = 0, count = 0, shit = 0, shart = 0;
|
||||
//fprintf (stderr, "Distance Compare %X - %X \n", butt, farts );
|
||||
for (i; i < 3; i++) //shift three places tops;
|
||||
{
|
||||
shit = (butt >> i) & 0b1;
|
||||
shart = (farts >> i) & 0b1;
|
||||
if (shit != shart)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload)
|
||||
{
|
||||
//unsigned int bestPos = 0U;
|
||||
//unsigned int bestVal = 0U;
|
||||
|
||||
for (unsigned j = 0U; j < 20U; j++) {
|
||||
unsigned int bestPos = 0U;
|
||||
unsigned int bestVal = 0U;
|
||||
//fprintf (stderr, " fail%d-", failPos);
|
||||
|
||||
for (unsigned int i = 0U; i < 16U; i++) {
|
||||
points[failPos] = i;
|
||||
|
||||
//fprintf (stderr, "i%d", i);
|
||||
|
||||
unsigned char tribits[49U];
|
||||
unsigned int pos = CDMRTrellisCheckCode(points, tribits);
|
||||
if (pos == 999U) {
|
||||
CDMRTrellisTribitsToBits(tribits, payload);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pos > bestPos) {
|
||||
bestPos = pos;
|
||||
bestVal = i;
|
||||
}
|
||||
}
|
||||
|
||||
points[failPos] = bestVal;
|
||||
failPos = bestPos;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload)
|
||||
{
|
||||
|
||||
|
||||
unsigned char bits[144];
|
||||
for (int i = 0; i < 48; i++) {
|
||||
bits[(i * 3) + 0] = (tribits[i] >> 2) & 1;
|
||||
bits[(i * 3) + 1] = (tribits[i] >> 1) & 1;
|
||||
bits[(i * 3) + 2] = tribits[i] & 1;
|
||||
}
|
||||
|
||||
|
||||
// convert bits to bytes
|
||||
//fprintf (stderr, "\n Tribit Binary Sequence\n ");
|
||||
for (short i = 0; i < 144; i++)
|
||||
{
|
||||
//fprintf (stderr, "%b", bits[i]);
|
||||
}
|
||||
for(short int i = 0; i < 18; i++)
|
||||
{
|
||||
payload[i] = (bits[i * 8 + 0] << 7) | (bits[i * 8 + 1] << 6) | (bits[i * 8 + 2] << 5) | (bits[i * 8 + 3] << 4) |
|
||||
(bits[i * 8 + 4] << 3) | (bits[i * 8 + 5] << 2) | (bits[i * 8 + 6] << 1) | (bits[i * 8 + 7] << 0);
|
||||
}
|
||||
|
||||
//for (int i = 0; i < 144; i++)
|
||||
//payload[i/8] = (payload[i/8] << 1) | bits[i];
|
||||
//DmrDataBit[j + 0] = (TrellisReturn[17-i] >> 0) & 0x01; //example
|
||||
|
||||
}
|
||||
|
||||
unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits)
|
||||
{
|
||||
|
||||
//unsigned char state = 0U; //move outside of function to preserve state for every iteration
|
||||
//let's try reversing the points to pass through the decode table instead of flipping them here,
|
||||
//it may mess up the fixcode and failpos POS
|
||||
state = 0U;
|
||||
for (unsigned int i = 0U; i < 49U;) //total number of points to process
|
||||
{
|
||||
tribits[i] = 9U;
|
||||
for (unsigned int j = 0U; j < 8U; j++)
|
||||
{
|
||||
//if (points[i] == DECODE_TABLE[state * 8U + j])
|
||||
//if (points[48-i] == DECODE_TABLE[state * 8U + j])
|
||||
if (points[i] == ENCODE_TABLE[state * 8U + j])
|
||||
{
|
||||
tribits[i] = j;
|
||||
state = tribits[i]; //carry over if found right away
|
||||
i++; //increment i by one value
|
||||
break;
|
||||
}
|
||||
}
|
||||
//try to find shortest distance for surviving paths and decide on one
|
||||
//seems to be that two paths will have distance value 1, and two will have distance value 2
|
||||
//need to keep totaling up a few rounds before we can eliminate a path and resume?
|
||||
if (tribits[i] == 9U)
|
||||
{
|
||||
int distance = 0;
|
||||
int maxdistance = 99; //random metric for two position distance
|
||||
int pathdistance = 0;
|
||||
unsigned int match = 0;
|
||||
unsigned int nextmatch = 0;
|
||||
unsigned int q = 0;
|
||||
//only 4 possible states for each point, but in 8 (0-7) FSM states
|
||||
char path[99][99] = {0}; //[i][pathcount] = distance
|
||||
int pathcount = 0;
|
||||
for (unsigned int o = 0; o < 64; o++) //check entire state transition table for matches
|
||||
{
|
||||
if (points[i] == ENCODE_TABLE[o]) //ENCODE TABLE
|
||||
{
|
||||
match = o / (unsigned int)8; //get dividend no remainder/decimal I hope, get fsm state 0-7
|
||||
//fprintf (stderr, "\n Point #%d [%d] Match State %d Position %d Tribit Value %d \n", i, points[i], match, o, o % (unsigned int)8);
|
||||
distance = quickHamming(match, state);
|
||||
//fprintf (stderr, "Raw Distance Current %d\n", distance);
|
||||
path[i][pathcount] = distance ; //save which table values (paths) match as possible values and distance
|
||||
for (q; q < 64; q++) //check entire state transition table for next point match
|
||||
{
|
||||
if (points[i+1] == ENCODE_TABLE[q]) //ENCODE TABLE
|
||||
{
|
||||
nextmatch = q / (unsigned int)8;
|
||||
path[i+1][pathcount] = quickHamming(nextmatch, q % (unsigned int)8);
|
||||
//fprintf (stderr, "Raw Distance Next %d\n", path[i+1][pathcount]);
|
||||
pathcount++;
|
||||
//fprintf (stderr, "State 0 Match %d Distance %d \n", o, distance);
|
||||
}
|
||||
}
|
||||
for (short int z = 0; z <= pathcount; z++) //add metrics on paths to find shortest distance
|
||||
{
|
||||
pathdistance = path[i][0] + path[i+1][z];
|
||||
//fprintf (stderr, "Total Path Distance %d\n", pathdistance);
|
||||
if (pathdistance <= maxdistance) //equal too in case of tie?
|
||||
{
|
||||
maxdistance = pathdistance;
|
||||
tribits[i] = o % (unsigned int)8; //remainder value will be tribit value on table
|
||||
if (i < 49) //just in case we are on 49 already, don't want to crash or something.
|
||||
{
|
||||
tribits[i+1] = q % (unsigned int)8; //remainder value will be tribit value on table
|
||||
}
|
||||
|
||||
//fprintf (stderr, "Point #%d [%d] - Tribit Candidate %d\n", i, points[i], tribits[i] );
|
||||
//fprintf (stderr, "Point #%d [%d]- Tribit Candidate %d\n", i+1, points[i+1], tribits[i+1] );
|
||||
}
|
||||
}
|
||||
}
|
||||
//fprintf (stderr, "Selected Point #%d [%d] - Tribit Selection %d\n", i, points[i], tribits[i] );
|
||||
//fprintf (stderr, "Selected Point #%d [%d]- Tribit Selection %d\n", i+1, points[i+1], tribits[i+1] );
|
||||
}
|
||||
state = tribits[i+1]; //not quite sure if this will be needed or not, if so, set state to last found value
|
||||
i += 2; //increment i by two since we already got the next tribit value as well;
|
||||
//state = tribits[i]; //not quite sure if this will be needed or not, if so, set state to last found value
|
||||
//i++; //increment i by two since we already got the next tribit value as well;
|
||||
}
|
||||
|
||||
}
|
||||
return 999U;
|
||||
}
|
||||
|
||||
void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits)
|
||||
{
|
||||
int n;
|
||||
signed char dibit;
|
||||
//can only assume this is giving the correct dibits out, and not inverse or something.
|
||||
/*
|
||||
for (int i = 0; i < 98; i++) {
|
||||
n = i * 2;
|
||||
if (n >= 98) n += 68;
|
||||
bool b1 = data[n] != 0x0;
|
||||
|
||||
n = i * 2 + 1;
|
||||
if (n >= 98) n += 68;
|
||||
bool b2 = data[n] != 0x0;
|
||||
|
||||
if (!b1 && b2)
|
||||
dibit = +3; // 1 - 01
|
||||
else if (!b1 && !b2)
|
||||
dibit = +1; // 0 - 00
|
||||
else if (b1 && !b2)
|
||||
dibit = -1; // 2 - 10
|
||||
else
|
||||
dibit = -3; // 3 - 11
|
||||
|
||||
*/
|
||||
//Keep it simple!
|
||||
for (int i = 0; i < 98; i++)
|
||||
{
|
||||
n = INTERLEAVE_TABLE[97-i];
|
||||
//n = i;
|
||||
if (data[i] == 0)
|
||||
{
|
||||
dibits[n] = 1; //1
|
||||
}
|
||||
if (data[i] == 1)
|
||||
{
|
||||
dibits[n] = 3; //3
|
||||
}
|
||||
if (data[i] == 2)
|
||||
{
|
||||
dibits[n] = -1; //-1
|
||||
}
|
||||
if (data[i] == 3)
|
||||
{
|
||||
dibits[n] = -3; //-3
|
||||
}
|
||||
}
|
||||
|
||||
//n = INTERLEAVE_TABLE[i]; //should this go in reverse?
|
||||
//n = INTERLEAVE_TABLE[97-i]; //should this go in reverse?
|
||||
//dibits[n] = dibit; //should this go in reverse too? not sure on this one, but definitely the INTERLEAVE_TABLE
|
||||
//n = INTERLEAVE_TABLE[97-i]; //should this go in reverse?
|
||||
//dibits[97-n] = dibit;
|
||||
//}
|
||||
}
|
||||
|
||||
void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points)
|
||||
{
|
||||
for (unsigned int i = 0U; i < 49U; i++) {
|
||||
if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -1)
|
||||
points[i] = 0U;
|
||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -1)
|
||||
points[i] = 1U;
|
||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -3)
|
||||
points[i] = 2U;
|
||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -3)
|
||||
points[i] = 3U;
|
||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -1)
|
||||
points[i] = 4U;
|
||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -1)
|
||||
points[i] = 5U;
|
||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -3)
|
||||
points[i] = 6U;
|
||||
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -3)
|
||||
points[i] = 7U;
|
||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +3)
|
||||
points[i] = 8U;
|
||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +3)
|
||||
points[i] = 9U;
|
||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +1)
|
||||
points[i] = 10U;
|
||||
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +1)
|
||||
points[i] = 11U;
|
||||
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +3)
|
||||
points[i] = 12U;
|
||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +3)
|
||||
points[i] = 13U;
|
||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +1)
|
||||
points[i] = 14U;
|
||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +1)
|
||||
points[i] = 15U;
|
||||
}
|
||||
}
|
||||
|
||||
void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits)
|
||||
{
|
||||
for (unsigned int i = 0U; i < 49U; i++) {
|
||||
switch (points[i]) {
|
||||
case 0U:
|
||||
dibits[i * 2U + 0U] = +1;
|
||||
dibits[i * 2U + 1U] = -1;
|
||||
break;
|
||||
case 1U:
|
||||
dibits[i * 2U + 0U] = -1;
|
||||
dibits[i * 2U + 1U] = -1;
|
||||
break;
|
||||
case 2U:
|
||||
dibits[i * 2U + 0U] = +3;
|
||||
dibits[i * 2U + 1U] = -3;
|
||||
break;
|
||||
case 3U:
|
||||
dibits[i * 2U + 0U] = -3;
|
||||
dibits[i * 2U + 1U] = -3;
|
||||
break;
|
||||
case 4U:
|
||||
dibits[i * 2U + 0U] = -3;
|
||||
dibits[i * 2U + 1U] = -1;
|
||||
break;
|
||||
case 5U:
|
||||
dibits[i * 2U + 0U] = +3;
|
||||
dibits[i * 2U + 1U] = -1;
|
||||
break;
|
||||
case 6U:
|
||||
dibits[i * 2U + 0U] = -1;
|
||||
dibits[i * 2U + 1U] = -3;
|
||||
break;
|
||||
case 7U:
|
||||
dibits[i * 2U + 0U] = +1;
|
||||
dibits[i * 2U + 1U] = -3;
|
||||
break;
|
||||
case 8U:
|
||||
dibits[i * 2U + 0U] = -3;
|
||||
dibits[i * 2U + 1U] = +3;
|
||||
break;
|
||||
case 9U:
|
||||
dibits[i * 2U + 0U] = +3;
|
||||
dibits[i * 2U + 1U] = +3;
|
||||
break;
|
||||
case 10U:
|
||||
dibits[i * 2U + 0U] = -1;
|
||||
dibits[i * 2U + 1U] = +1;
|
||||
break;
|
||||
case 11U:
|
||||
dibits[i * 2U + 0U] = +1;
|
||||
dibits[i * 2U + 1U] = +1;
|
||||
break;
|
||||
case 12U:
|
||||
dibits[i * 2U + 0U] = +1;
|
||||
dibits[i * 2U + 1U] = +3;
|
||||
break;
|
||||
case 13U:
|
||||
dibits[i * 2U + 0U] = -1;
|
||||
dibits[i * 2U + 1U] = +3;
|
||||
break;
|
||||
case 14U:
|
||||
dibits[i * 2U + 0U] = +3;
|
||||
dibits[i * 2U + 1U] = +1;
|
||||
break;
|
||||
default:
|
||||
dibits[i * 2U + 0U] = -3;
|
||||
dibits[i * 2U + 1U] = +1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits)
|
||||
{
|
||||
for (unsigned int i = 0U; i < 48U; i++) {
|
||||
unsigned int n = 143U - i * 3U;
|
||||
|
||||
bool b1 = READ_BIT(payload, n) != 0x00U;
|
||||
n--;
|
||||
bool b2 = READ_BIT(payload, n) != 0x00U;
|
||||
n--;
|
||||
bool b3 = READ_BIT(payload, n) != 0x00U;
|
||||
|
||||
unsigned char tribit = 0U;
|
||||
tribit |= b1 ? 4U : 0U;
|
||||
tribit |= b2 ? 2U : 0U;
|
||||
tribit |= b3 ? 1U : 0U;
|
||||
|
||||
//tribits[i] = tribit;
|
||||
}
|
||||
|
||||
tribits[48U] = 0U;
|
||||
}
|
||||
|
||||
bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(payload != NULL);
|
||||
unsigned char tribits[49U];
|
||||
for (short i = 0; i < 49; i++)
|
||||
{
|
||||
tribits[i] = 0; //initialize with 0 values so we know later on if these values are actually being assigned or not
|
||||
}
|
||||
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\n Raw Trellis Dibits inside Decoder\n ");
|
||||
for (short i = 0; i < 98; i++)
|
||||
{
|
||||
fprintf (stderr, "#%d [%0d] ", i, data[i]);
|
||||
}
|
||||
}
|
||||
signed char dibits[98U];
|
||||
CDMRTrellisDeinterleave(data, dibits);
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\n Trellis Deinterleaved Dibits inside Decoder (converted to signed)\n ");
|
||||
for (short i = 0; i < 98; i++)
|
||||
{
|
||||
fprintf (stderr, "#%d [%d] ", i, dibits[i]); //signed char, values should be -3, -1, 1, 3 only
|
||||
}
|
||||
}
|
||||
unsigned char points[49U];
|
||||
unsigned char reverse_points[49U];
|
||||
CDMRTrellisDibitsToPoints(dibits, points);
|
||||
//maybe keep point 49 at 49, since its the flush?
|
||||
//fprintf (stderr, "\n Trellis Reverse Points inside Decoder\n ");
|
||||
for (short i = 0; i < 49; i++)
|
||||
{
|
||||
reverse_points[i] = points[48-i];
|
||||
//fprintf (stderr, "#%d [%02u] ", i, reverse_points[i]);
|
||||
}
|
||||
//reverse_points[48] = points[48];
|
||||
//fprintf (stderr, "#%d [%02u] ", 48, reverse_points[48]);
|
||||
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\n Trellis Points inside Decoder\n ");
|
||||
for (short i = 0; i < 49; i++)
|
||||
{
|
||||
fprintf (stderr, "#%d [%02u] ", i, points[i]);
|
||||
}
|
||||
}
|
||||
// Check the original code
|
||||
|
||||
unsigned int failPos = CDMRTrellisCheckCode(points, tribits);
|
||||
//unsigned int failPos = CDMRTrellisCheckCode(reverse_points, tribits); //stack smashing detected terminated
|
||||
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\n Check Code Trellis Tribits inside Decoder\n ");
|
||||
for (short i = 0; i < 49; i++)
|
||||
{
|
||||
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
|
||||
}
|
||||
}
|
||||
|
||||
if (failPos == 999U)
|
||||
{
|
||||
CDMRTrellisTribitsToBits(tribits, payload);
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\nTrellis Payload Tribits\n %s ", KCYN);
|
||||
for (short i = 0; i < 49; i++)
|
||||
{
|
||||
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
|
||||
}
|
||||
}
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\nTrellis Payload Tribits to Bytes inside Decoder\n %s ", KCYN);
|
||||
for (short i = 0; i < 18; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", payload[i]);
|
||||
}
|
||||
fprintf (stderr,"%s", KNRM); //change back to normal
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char savePoints[49U];
|
||||
for (unsigned int i = 0U; i < 49U; i++)
|
||||
savePoints[i] = points[i];
|
||||
//savePoints[i] = reverse_points[i];
|
||||
|
||||
bool ret = CDMRTrellisFixCode(points, failPos, payload);
|
||||
//bool ret = CDMRTrellisFixCode(reverse_points, failPos, payload);
|
||||
if (ret){
|
||||
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\n if return Trellis Tribits inside Decoder\n ");
|
||||
for (short i = 0; i < 49; i++)
|
||||
{
|
||||
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
|
||||
}
|
||||
}
|
||||
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\nTrellis Payload Tribits to Bits fix return true\n "); //this one seems to be happening
|
||||
for (short i = 0; i < 18; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", payload[i]);
|
||||
}
|
||||
}
|
||||
return true; }
|
||||
|
||||
if (failPos == 0U)
|
||||
{
|
||||
if (1 == 2)
|
||||
{
|
||||
fprintf (stderr, "\nTrellis Payload Tribits to Bytes failPos == 0U\n ");
|
||||
for (short i = 0; i < 18; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", payload[i]);
|
||||
}
|
||||
}
|
||||
return false; }
|
||||
|
||||
// Backtrack one place for a last go
|
||||
return CDMRTrellisFixCode(savePoints, failPos - 1U, payload);
|
||||
}
|
||||
BIN
tone24.wav
Normal file
BIN
tone24.wav
Normal file
Binary file not shown.
BIN
tone48.wav
Normal file
BIN
tone48.wav
Normal file
Binary file not shown.
4
virtualsink.sh
Normal file
4
virtualsink.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||
pactl load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user