60 Commits

Author SHA1 Message Date
lwvmobile
57629cefe4 Version/Date Update; 2023-08-27 15:06:32 -04:00
lwvmobile
fe3a135a92 Disable DMR MS/Simplex When Trunking Enabled; 2023-08-26 21:23:56 -04:00
lwvmobile
8d33c2b3d1 DMR SB TXI Tweaks; Add CRC4 Check to LE MI; 2023-08-26 17:28:06 -04:00
lwvmobile
593ffbbd66 DMR LE Minor Code Fix; Print Tweaks; 2023-08-26 09:32:40 -04:00
lwvmobile
592d57ad87 Fix M17 IV; 2023-08-25 09:16:34 -04:00
lwvmobile
9a31678d9a Fix M17 Enc Type Values; 2023-08-25 09:12:51 -04:00
lwvmobile
7b3a257df8 Fix EDACS Analog Call Preemption Conditions; 2023-08-22 09:21:03 -04:00
lwvmobile
55e792a925 Disable RTL RMS Function on ARM Devices (RPi); 2023-08-19 20:58:30 -04:00
lwvmobile
755f77f96c Temp Fix for EDACS Standard/Networked; 2023-08-19 12:45:22 -04:00
lwvmobile
1c17757a4e DMR 3/4 Simple Error Correction; 2023-08-19 07:43:30 -04:00
lwvmobile
abe2e61cf2 P25p2 I-ISCH/DUID Error Correction; 2023-08-17 13:44:22 -04:00
lwvmobile
c404825451 Analog Monitor Hold on SQL Break; Misc; 2023-08-13 11:43:04 -04:00
lwvmobile
769168da5b Prevent Possible Overflow in lbuf and lbuf2; 2023-08-11 14:59:50 -04:00
lwvmobile
14284c3cf1 More Cygwin M17 Related Bandaids; 2023-08-11 14:59:14 -04:00
lwvmobile
51f971b68d Update Install Notes and Include Arch Installer; 2023-08-11 12:52:28 -04:00
lwvmobile
02fdb7cd90 Fix Some NXDN Array Sizes and Chainbacks; 2023-08-11 12:21:22 -04:00
lwvmobile
64541a1958 M17 Misc Cleanup; 2023-08-11 12:20:47 -04:00
lwvmobile
0a675d3f0f Misc Code Cleanup; 2023-08-10 14:44:16 -04:00
lwvmobile
e79b6fd231 Simplify DMR Trellis Decoder; 2023-08-10 03:47:08 -04:00
lwvmobile
d356ed0dbc Add M17 CAN Value to Ncurses; Misc; 2023-08-09 20:54:07 -04:00
lwvmobile
495eb71090 Fixed Wrong Line; Fix the Correct Line This Time; 2023-08-09 04:10:03 -04:00
lwvmobile
6bf96f1df5 Forgot something; 2023-08-09 04:08:11 -04:00
lwvmobile
3a2db53c3b Fix RTL Source Audio Monitoring Bug; 2023-08-09 04:05:43 -04:00
lwvmobile
e038016c30 Fix Pulse Audio Output Source Monitor; 2023-08-09 02:16:12 -04:00
lwvmobile
7d6269efad WIP: Source Audio Monitoring on V2.1b; 2023-08-09 01:14:00 -04:00
lwvmobile
152f0ea7f6 EDACS Tweaks to Analog Call Handling; 2023-08-08 01:06:48 -04:00
lwvmobile
13443a25f3 Fix Annoying Alignment Issues; 2023-08-07 04:14:33 -04:00
lwvmobile
528f7294d9 Experimental EDACS Analog Voice Monitoring; 2023-08-07 03:48:39 -04:00
lwvmobile
83e3fa1061 Fix RTL RMS so it does't return Jank Values; 2023-08-07 03:43:39 -04:00
lwvmobile
9b3a2d96e3 Fix Some DateName Issues for dates in Aero; 2023-08-07 03:42:11 -04:00
lwvmobile
0829cdbdb0 Update Example_Usage for Icecast; #159 2023-08-07 03:38:15 -04:00
lwvmobile
9541aef382 Merge pull request #159 from francisuk1989/v2.1b-1
Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
2023-08-05 16:38:35 -04:00
lwvmobile
4caf6bb153 Update Example_Usage.md 2023-08-05 16:37:00 -04:00
Francis
dd77273218 Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
For them who wont to send audio to a icecast 2 server via WIndows.
2023-08-05 20:38:15 +01:00
lwvmobile
3bd3edb36f Fix Cygwin/Aero/OSS/M17 Junk; 2023-07-26 18:43:52 -04:00
lwvmobile
6f1cf0a279 Version/Tag Update 2.1b 2023-07-11 19:02:56 -04:00
lwvmobile
5d045b89e4 Fix Random Warnings on #152 2023-07-10 19:19:49 -04:00
lwvmobile
a2c4679632 M17 More Work and Fixes; #152 2023-07-10 19:13:16 -04:00
lwvmobile
986ed27d7d NXDN LZ Tweak on RCCH Disc; #123 2023-07-10 19:02:54 -04:00
lwvmobile
bae6a1545e Fix OSS Input/Output on M17 8K Sample; #152 2023-07-08 23:58:43 -04:00
lwvmobile
5240f00441 M17 Dbuf Temp Bug Fix; Misc; #152 2023-07-08 06:40:36 -04:00
lwvmobile
f7511e0976 Fix Cmake for Codec2 in Cygwin; #152 2023-07-08 06:07:09 -04:00
lwvmobile
bc27344b04 Fix M17 3200bps Voice; Misc M17 Tweaks; #152 2023-07-07 02:15:08 -04:00
lwvmobile
db97eb82a1 M17 Support (Partially Working Now); 2023-07-06 21:04:28 -04:00
lwvmobile
3f1b8ff736 M17 Initial Support (Non-Working State); 2023-07-05 14:27:25 -04:00
lwvmobile
54b9017146 Misc Minor Fixes; 2023-07-05 14:03:22 -04:00
lwvmobile
8ccaf2d261 DMR LE ENC Identifiers Tweak; 2023-07-03 12:31:58 -04:00
lwvmobile
209770175d Fix ysf.c Unused Variables Warnings; 2023-07-01 22:56:15 -04:00
lwvmobile
602079e681 Fix Trellis.c Unused Variables Warnings; 2023-07-01 22:47:36 -04:00
lwvmobile
82267b9ec8 Fix NXDN de-scrambling bug; 2023-07-01 22:40:05 -04:00
lwvmobile
87bf997b6e Add YSF to default decoding class; #143 2023-07-01 18:44:14 -04:00
lwvmobile
0a43d3202d YSF Fix CM Variable; Line Break; #146 2023-07-01 17:32:42 -04:00
lwvmobile
ee04cef6f2 YSF Radio ID Mode; Element Tweaks; #143 2023-07-01 17:32:22 -04:00
lwvmobile
b6fdfe48c1 Fix Line #137 2023-07-01 17:32:12 -04:00
lwvmobile
7a4bd2833f Refine/Fix YSF FICH Element Decode #143 2023-07-01 17:31:42 -04:00
lwvmobile
432ad448ba Fix YSF Full Rate Voice #143 2023-07-01 17:31:27 -04:00
lwvmobile
61be710bb0 Fix Code Tab Alignment #143 2023-07-01 17:30:57 -04:00
lwvmobile
3be8aacf77 WIP: YSF Decoding; #143 2023-07-01 17:30:29 -04:00
lwvmobile
4feb21cf0a Fix Exitflag Variable #136 2023-07-01 17:28:13 -04:00
lwvmobile
7d8162ab99 DMR LE/CAP+/Misc Tweaks; 2023-07-01 17:21:43 -04:00
37 changed files with 3698 additions and 1663 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ build
examples examples
*.bin *.bin
*.ans *.ans
*.patch

View File

@@ -31,12 +31,6 @@ if (PVC)
add_definitions(-DPVCONVENTIONAL) add_definitions(-DPVCONVENTIONAL)
endif () endif ()
#use cmake option -DNXDN=ON to enable the old NXDN Sync Pattern
option(NXDN
"Build with Old NXDN Sync Pattern Enabled" OFF)
if (NXDN)
add_definitions(-DNXDNOLDSYNC)
endif ()
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks #use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
option(LZ option(LZ
@@ -52,13 +46,6 @@ if (TN)
add_definitions(-DTONES) add_definitions(-DTONES)
endif () endif ()
#use cmake option -DZDEV to change designation of this build from MAIN to zDEV
option(ZDEV
"change designation of this build from MAIN to zDEV" OFF)
if (ZDEV)
add_definitions(-DZDEV_BUILD)
endif ()
include(git_revision) include(git_revision)
git_describe(GIT_TAG) git_describe(GIT_TAG)
@@ -68,6 +55,7 @@ find_package(ITPP REQUIRED)
find_package(RTLSDR) find_package(RTLSDR)
find_package(Curses REQUIRED) find_package(Curses REQUIRED)
find_package(PulseAudio REQUIRED) find_package(PulseAudio REQUIRED)
find_package(CODEC2)
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR}) 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}) set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
@@ -79,6 +67,12 @@ if(RTLSDR_FOUND)
add_definitions(-DUSE_RTLSDR) add_definitions(-DUSE_RTLSDR)
endif(RTLSDR_FOUND) 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 SRCS src/*.c src/*.cpp)
FILE(GLOB HEADERS include/*.h include/*.hpp) FILE(GLOB HEADERS include/*.h include/*.hpp)

View File

@@ -2,7 +2,7 @@
# Digital Speech Decoder - Florida Man Edition # 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 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, 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. [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. 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.

31
cmake/FindCODEC2.cmake Normal file
View 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)

View 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

View File

@@ -13,7 +13,7 @@ Y='y'
if [[ $Y == $ANSWER ]]; then if [[ $Y == $ANSWER ]]; then
sudo apt update 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 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 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. echo Please check to see that libitpp-dev has successfully been downloaded and installed from the repo.

View File

@@ -3,7 +3,7 @@
`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. `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 (P25 1 and 2, and DMR Stereo) -ft XDMA decoder class (P25p1 and p2, YSF, and DMR Stereo)
-fs DMR Stereo, also may need to use -xr if inverted DMR -fs DMR Stereo, also may need to use -xr if inverted DMR
-fa Legacy Auto (not recommended) -fa Legacy Auto (not recommended)
-fi NXDN48 -fi NXDN48
@@ -14,6 +14,7 @@
-f1 P25P1 -f1 P25P1
-f2 P25P2 (may need to specify wacn/sys/nac manually) -f2 P25P2 (may need to specify wacn/sys/nac manually)
-fx X2-TDMA -fx X2-TDMA
-fy YSF
``` ```
## Conventional Frequency "Fast Scanner" ## Conventional Frequency "Fast Scanner"
@@ -99,7 +100,7 @@ and in a second terminal tab, same folder, run
EDACS Trunking (w/ channel map import) 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 only, no analog voice monitoring) --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` `dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
@@ -190,4 +191,35 @@ e - Toggle Trunking Tuning to Encrypted Calls (P25)
9 - Connect to SDR++ RIGCTL Server with Defaults/Retry RIGCTL Connection 9 - Connect to SDR++ RIGCTL Server with Defaults/Retry RIGCTL Connection
D - Reset DMR Site Parms/Call Strings, etc. D - Reset DMR Site Parms/Call Strings, etc.
Z - Simulate NoCarrier/No VC/CC sync (capital Z) 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
```

View File

@@ -11,8 +11,18 @@ wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-insta
chmod +x download-and-install.sh chmod +x download-and-install.sh
./download-and-install.sh ./download-and-install.sh
``` ```
f
If you have dependencies already installed (i.e. need a fresh clean install on a system with DSD-FME already or using system other than Debian/Ubuntu, etc), please run this instead: ### 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 wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install-nodeps.sh
@@ -28,20 +38,31 @@ Debian/Mint/Ubuntu/Pi
``` ```
sudo apt update 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 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 Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
``` ```
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++ 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 ## 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. 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 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!! ### Build and Install ITPP - ONLY IF NOT IN REPO!!

View File

@@ -74,7 +74,11 @@
#include <locale.h> #include <locale.h>
#include <ncurses.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 //group csv import struct
typedef struct typedef struct
@@ -270,7 +274,7 @@ typedef struct
int rtl_udp_port; int rtl_udp_port;
int rtl_bandwidth; int rtl_bandwidth;
int rtl_started; int rtl_started;
int rtl_rms; long int rtl_rms;
int monitor_input_audio; int monitor_input_audio;
int pulse_raw_rate_in; int pulse_raw_rate_in;
int pulse_raw_rate_out; int pulse_raw_rate_out;
@@ -309,6 +313,9 @@ typedef struct
int inverted_ysf; int inverted_ysf;
short int aggressive_framesync; short int aggressive_framesync;
int frame_m17;
int inverted_m17;
FILE *symbolfile; FILE *symbolfile;
int call_alert; int call_alert;
@@ -407,6 +414,10 @@ typedef struct
float *audio_out_temp_buf_p; float *audio_out_temp_buf_p;
float audio_out_temp_bufR[160]; float audio_out_temp_bufR[160];
float *audio_out_temp_buf_pR; 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_idx;
int audio_out_idx2; int audio_out_idx2;
int audio_out_idxR; int audio_out_idxR;
@@ -706,14 +717,63 @@ typedef struct
//Upsampled Audio Smoothing //Upsampled Audio Smoothing
uint8_t 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; } dsd_state;
/* /*
* Frame sync patterns * Frame sync patterns
*/ */
#define FUSION_SYNC "31111311313113131131" //HA! //The inverse of LSF also seems to be Stream Frame Type, only going to work on Stream mode for now
#define INV_FUSION_SYNC "13333133131331313313" //HA! #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 INV_P25P1_SYNC "333331331133111131311111"
#define P25P1_SYNC "111113113311333313133333" #define P25P1_SYNC "111113113311333313133333"
@@ -879,14 +939,16 @@ void processX2TDMAdata (dsd_opts * opts, dsd_state * state);
void processX2TDMAvoice (dsd_opts * opts, dsd_state * state); void processX2TDMAvoice (dsd_opts * opts, dsd_state * state);
void processDSTAR_HD (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 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 processP2(dsd_opts * opts, dsd_state * state); //P2
void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block 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) 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 dmr_filter(short sample);
short nxdn_filter(short sample); short nxdn_filter(short sample);
short dpmr_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); uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
void ncursesOpen (dsd_opts * opts, dsd_state * state); void ncursesOpen (dsd_opts * opts, dsd_state * state);
@@ -979,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_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[]); 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]); 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 //Embedded Alias and GPS
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]); void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
@@ -1015,7 +1079,8 @@ uint8_t crc8(uint8_t bits[], unsigned int len);
bool crc8_ok(uint8_t bits[], unsigned int len); bool crc8_ok(uint8_t bits[], unsigned int len);
//modified CRC functions for SB/RC //modified CRC functions for SB/RC
uint8_t crc7(uint8_t bits[], unsigned int len); uint8_t crc7(uint8_t bits[], unsigned int len);
uint8_t crc3(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 and LFSRP 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 LFSR(dsd_state * state);
@@ -1121,24 +1186,16 @@ void cleanup_rtlsdr_stream();
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state); void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state);
void rtlsdr_sighandler(); void rtlsdr_sighandler();
void rtl_dev_tune(dsd_opts * opts, long int frequency); void rtl_dev_tune(dsd_opts * opts, long int frequency);
int rtl_return_rms(); long int rtl_return_rms();
void rtl_clean_queue(); void rtl_clean_queue();
#endif #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 //Phase 2 Helper Functions
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME 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_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
int isch_lookup (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 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 crc16_lb_bridge (int payload[190], int len);
int crc12_xb_bridge (int payload[190], int len); int crc12_xb_bridge (int payload[190], int len);

136
src/dmr_34.c Normal file
View 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);
}

View File

@@ -258,7 +258,6 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1; if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1;
else else
{ {
SlotTypeOk = -1;
SlotTypeOk = 0; SlotTypeOk = 0;
goto END; goto END;
} }

View File

@@ -418,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) if (is_trellis)
{ {
CRCExtracted = 0; CRCExtracted = 0;
CRCComputed = 0; CRCComputed = 0;
IrrecoverableErrors = 1; IrrecoverableErrors = 1;
bool trellis_good = TRUE;
uint8_t tdibits[98]; uint8_t tdibits[98];
memset (tdibits, 0, sizeof(tdibits)); 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++) for (i = 0; i < 98; i++)
{ tdibits[i] = (info[i*2] << 1) | info[i*2+1];
tdibits[97-i] = (info[i*2] << 1) | info[i*2+1];
}
unsigned char TrellisReturn[18]; uint8_t TrellisReturn[18];
memset (TrellisReturn, 0, sizeof(TrellisReturn)); memset (TrellisReturn, 0, sizeof(TrellisReturn));
IrrecoverableErrors = dmr_34(tdibits, TrellisReturn);
trellis_good = CDMRTrellisDecode(tdibits, TrellisReturn); //NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
if (trellis_good == TRUE) IrrecoverableErrors = 0; //they may have been successfully corrected, the CRC will reveal as much
// else (fprintf (stderr, " Trellis Failure")); //debug print
for (i = 0; i < pdu_len; i++) //18 for (i = 0; i < pdu_len; i++)
{ DMR_PDU[i] = TrellisReturn[i+pdu_start];
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
}
for(i = 0, j = 0; i < 18; i++, j+=8) for(i = 0, j = 0; i < 18; i++, j+=8)
{ {
@@ -471,7 +466,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
CRCExtracted = CRCExtracted ^ crcmask; CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check //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 < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i]; for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
@@ -482,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; state->data_block_crc_valid[slot][blockcounter] = 1;
} }
else else
{
// IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix
state->data_block_crc_valid[slot][blockcounter] = 0; state->data_block_crc_valid[slot][blockcounter] = 0;
}
} }
@@ -505,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; CRCExtracted = 0;
CRCComputed = 0; CRCComputed = 0;
@@ -605,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, "%s", KRED);
fprintf(stderr, " (FEC ERR)"); fprintf(stderr, " (FEC ERR)");

View File

@@ -51,6 +51,12 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
uint64_t go_test = 0; uint64_t go_test = 0;
uint64_t mi_corrected = 0; uint64_t mi_corrected = 0;
uint64_t go_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) | 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) | (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) |
@@ -77,12 +83,22 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
mi_corrected |= mi_go_bits[i]; mi_corrected |= mi_go_bits[i];
go_corrected = go_corrected << 1; go_corrected = go_corrected << 1;
go_corrected |= mi_go_bits[i+12]; go_corrected |= mi_go_bits[i+12];
//manipulate for crc check
mi_bits[i+(j*12)] = mi_go_bits[i];
} }
} }
int mi_final = 0; int mi_final = 0;
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF; 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 (g[0] && g[1] && g[2])
{ {
if (slot == 0 && state->payload_algid != 0) if (slot == 0 && state->payload_algid != 0)
@@ -90,8 +106,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
if (state->payload_mi != mi_final) if (state->payload_mi != mi_final)
{ {
fprintf (stderr, "%s", KCYN); fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", 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; 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); fprintf (stderr, "%s", KNRM);
} }
//run afterwards, or le verification won't match up properly //run afterwards, or le verification won't match up properly
@@ -106,8 +125,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
if (state->payload_miR != mi_final) if (state->payload_miR != mi_final)
{ {
fprintf (stderr, "%s", KCYN); 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; 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); fprintf (stderr, "%s", KNRM);
} }
//run afterwards, or le verification won't match up properly //run afterwards, or le verification won't match up properly
@@ -268,13 +290,19 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
} }
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 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; uint8_t alg = sbrc_hex & 0x7; //SEE: https://patents.google.com/patent/EP2347540B1/en
uint8_t key = (sbrc_hex >> 3) & 0xFF; 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 uint8_t txi_delay = (sbrc_hex >> 3) & 0x1F; //middle five are the 'delay' value on a TXI system
//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
//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 (opts->dmr_le == 1) //this will now require a user to switch it on or off until more testing/figuring can be done 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) fprintf (stderr, "\n%s SLOT %d SB/RC (FEC ERR) %d %s \n", KRED, slot, irr_err, KNRM);
if (irr_err == 0) if (irr_err == 0)
{ {
if (sbrc_hex == 0) ; //NULL, do nothing if (sbrc_hex == 0) ; //NULL, do nothing
@@ -289,26 +317,34 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
//do something with the reverse channel information //do something with the reverse channel information
} }
//if the call is interruptable (TXI) and the crc3 is okay //if the call is interruptable (TXI) and the crc3 is okay and TXI Opcode
else if (crc3_okay == 1) else if (crc3_okay == 1 && (sbrc_opcode == 0 || sbrc_opcode == 3) )
{ {
//opcodes -- 0 (NULL), BR Delay (3) //opcodes -- 0 (NULL), BR Delay (3)
fprintf (stderr, "\n"); if (opts->payload == 0) fprintf (stderr, "\n");
fprintf (stderr, " TXI Op: %X - ", sbrc_opcode); fprintf (stderr, "%s", KCYN);
fprintf (stderr, " TXI Op: %X -", sbrc_opcode);
if (sbrc_opcode == 0) fprintf (stderr, " Null; "); if (sbrc_opcode == 0) fprintf (stderr, " Null; ");
else if (sbrc_opcode == 3) else if (sbrc_opcode == 3)
{ {
if (txi_delay != 0) 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 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;"); 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; "); else fprintf (stderr, " Unk; ");
fprintf (stderr, "%s", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n"); //only during payload if (opts->payload == 1) fprintf (stderr, "\n"); //only during payload
} }
else //all that should be left in this field is the potential ENC identifiers 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 (slot == 0) //may not need the state->errs anymore //&& state->errs < 3
@@ -319,12 +355,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
if (state->M == 0) if (state->M == 0)
{ {
fprintf (stderr, "\n"); fprintf (stderr, "\n");
fprintf (stderr, "%s ", KYEL); fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 1"); fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key); fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
// fprintf (stderr, "\n");
fprintf (stderr, "%s ", KNRM); fprintf (stderr, "%s ", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
state->payload_keyid = key; state->payload_keyid = key;
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent) state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
} }
@@ -340,12 +375,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
if (state->M == 0) if (state->M == 0)
{ {
fprintf (stderr, "\n"); fprintf (stderr, "\n");
fprintf (stderr, "%s ", KYEL); fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 2"); fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key); fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
// fprintf (stderr, "\n");
fprintf (stderr, "%s ", KNRM); fprintf (stderr, "%s ", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
state->payload_keyidR = key; state->payload_keyidR = key;
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent) state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
} }
@@ -402,3 +436,26 @@ uint8_t crc3(uint8_t bits[], unsigned int len)
return crc; 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
}

View File

@@ -26,9 +26,11 @@ void closePulseOutput (dsd_opts * opts)
{ {
pa_simple_free (opts->pulse_digi_dev_out); pa_simple_free (opts->pulse_digi_dev_out);
if (opts->dmr_stereo == 1) if (opts->dmr_stereo == 1)
{
pa_simple_free (opts->pulse_digi_dev_outR); 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) 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.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 tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
if (opts->monitor_input_audio == 1) //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, "Raw Audio Out", &ss, NULL, NULL, NULL); opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Analog", &ss, 0, NULL, NULL);
}
//tt //tt
pa_channel_map* left = 0; //NULL and 0 are same in this context pa_channel_map* left = 0; //NULL and 0 are same in this context
@@ -637,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) else if (strncmp(extension, ".bin", 3) == 0)
{ {
struct stat stat_buf; struct stat stat_buf;

View File

@@ -265,18 +265,21 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) ||
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) || (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 // 1 -P25p1
// 3 -X2-TDMA (inverted signal voice frame) // 3 -X2-TDMA (inverted signal voice frame)
// 5 -X2-TDMA (inverted signal data frame) // 5 -X2-TDMA (inverted signal data frame)
// 9 -NXDN (inverted voice frame) // 9 -M17 LSR
// 11 -DMR (inverted signal voice frame) // 11 -DMR (inverted signal voice frame)
// 13 -DMR (inverted signal data frame) // 13 -DMR (inverted signal data frame)
// 17 -NXDN (inverted data frame) // 17 -M17 STR
// 29 -NXDN (inverted FSW) // 29 -NXDN (inverted FSW)
// 31 -YSF
// 36 -P25p2 // 36 -P25p2
// 99 -M17 Preamble
int valid; int valid;
int dibit; int dibit;
@@ -335,12 +338,14 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
// 0 +P25p1 // 0 +P25p1
// 2 +X2-TDMA (non inverted signal data frame) // 2 +X2-TDMA (non inverted signal data frame)
// 4 +X2-TDMA (non inverted signal voice 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) // 10 +DMR (non inverted signal data frame)
// 12 +DMR (non inverted signal voice frame) // 12 +DMR (non inverted signal voice frame)
// 16 +NXDN (non inverted data frame) // 16 +M17 STR
// 28 +NXND (FSW) // 28 +NXND (FSW)
// 30 +YSF
// 35 +p25p2 // 35 +p25p2
// 98 +M17 Preamble
int valid; int valid;
int dibit; int dibit;

View File

@@ -34,7 +34,11 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
} }
char * getDateF(void) { 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; char * curr2;
struct tm * to; struct tm * to;
time_t t; time_t t;

View File

@@ -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 // Original DMR filter
#define NZEROS 60 #define NZEROS 60
float ngain = 7.423339364f; float ngain = 7.423339364f;
static float xv[NZEROS+1]; static float xv[NZEROS+1];
float xcoeffs[] = float xcoeffs[61] =
{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f, { -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f,
-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f, -0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f,
+0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f, +0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f,
@@ -27,7 +55,7 @@ float xcoeffs[] =
float nxgain = 15.95930463f; float nxgain = 15.95930463f;
static float nxv[NXZEROS+1]; static float nxv[NXZEROS+1];
float nxcoeffs[] = float nxcoeffs[135] =
{ +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f, { +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f,
+0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f, +0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f,
-0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f, -0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f,
@@ -74,7 +102,7 @@ const float dmrgain = 6.82973073748f;
static float dxv[DMRNZEROS+1]; static float dxv[DMRNZEROS+1];
// DMR filter F4EXB - root raised cosine alpha=0.7 Ts = 6650 S/s Fc = 48kHz // 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.0301506278, 0.0269200615, 0.0159662432, -0.0013114705, -0.0216605133,
-0.0404938748, -0.0528141756, -0.0543747957, -0.0428325003, -0.0186176083, -0.0404938748, -0.0528141756, -0.0543747957, -0.0428325003, -0.0186176083,
0.0147202645, 0.0508418571, 0.0816392577, 0.0988113688, 0.0957187780, 0.0147202645, 0.0508418571, 0.0816392577, 0.0988113688, 0.0957187780,
@@ -98,7 +126,7 @@ static float dpmrxv[NXZEROS+1];
const float dpmrgain = 14.6083498224f; 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 // 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.0000983004, 0.0058388841, 0.0119748846, 0.0179185547, 0.0232592816,
0.0275919612, 0.0305433586, 0.0317982965, 0.0311240307, 0.0275919612, 0.0305433586, 0.0317982965, 0.0311240307,
0.0283911865, 0.0235897433, 0.0168387650, 0.0083888763, 0.0283911865, 0.0235897433, 0.0168387650, 0.0083888763,
@@ -156,6 +184,11 @@ dpmr_filter(short sample)
return dsd_input_filter(sample, 4); return dsd_input_filter(sample, 4);
} }
short m17_filter (short sample)
{
return dsd_input_filter(sample, 5);
}
short short
dsd_input_filter(short sample, int mode) dsd_input_filter(short sample, int mode)
@@ -189,6 +222,14 @@ dsd_input_filter(short sample, int mode)
coeffs = (float *)dpmrcoeffs; coeffs = (float *)dpmrcoeffs;
zeros = DPMRNZEROS; zeros = DPMRNZEROS;
break; break;
case 5:
gain = m17gain;
v = m17xv;
coeffs = (float *)m17coeffs;
zeros = M17ZEROS;
break;
default: default:
return sample; return sample;
} }

View File

@@ -177,19 +177,19 @@ processFrame (dsd_opts * opts, dsd_state * state)
{ {
sprintf (state->fsubtype, " VOICE "); 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->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 "); sprintf (state->slot2light, " slot2 ");
//we can safely open MBE on any MS or mono handling //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); 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) if (opts->dmr_mono == 1 && state->synctype == 32)
{ {
//we can safely open MBE on any MS or mono handling //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); 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 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 //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); 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 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_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state); if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
dmrMSData (opts, state); if (opts->p25_trunk == 0) dmrMSData (opts, state);
} }
else else
{ {
@@ -219,7 +219,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->err_str[0] = 0; state->err_str[0] = 0;
sprintf (state->slot1light, " slot1 "); sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 "); sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync
dmr_data_sync (opts, state); dmr_data_sync (opts, state);
} }
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata //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 state->dmr_stereo = 0; //set the state to zero for handling pure data frames
sprintf (state->slot1light, " slot1 "); sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 "); sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync
dmr_data_sync (opts, state); dmr_data_sync (opts, state);
} }
} }
@@ -290,16 +288,21 @@ processFrame (dsd_opts * opts, dsd_state * state)
//ysf //ysf
else if ((state->synctype == 30) || (state->synctype == 31)) else if ((state->synctype == 30) || (state->synctype == 31))
{ {
//Do stuff //relocate MBEout to inside frame handling -- Not Working Currently for YSF
//fprintf(stderr, "YSF Sync! \n");
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
//openMbeOutFile (opts, state);
}
//sprintf(state->fsubtype, " VOICE ");
processYSF(opts, state); processYSF(opts, state);
return; 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 //P25 P2
else if ((state->synctype == 35) || (state->synctype == 36)) else if ((state->synctype == 35) || (state->synctype == 36))
{ {

View File

@@ -18,39 +18,6 @@
#include "dsd.h" #include "dsd.h"
#include <locale.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 char * getTime(void) //get pretty hh:mm:ss timestamp
{ {
time_t t = time(NULL); time_t t = time(NULL);
@@ -67,7 +34,11 @@ char * getTime(void) //get pretty hh:mm:ss timestamp
} }
char * getDate(void) { char * getDate(void) {
char datename[32]; #ifdef AERO_BUILD
char datename[80];
#else
char datename[99];
#endif
char * curr2; char * curr2;
struct tm * to; struct tm * to;
time_t t; time_t t;
@@ -114,16 +85,16 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
* 5 = -X2-TDMA (inverted signal data frame) * 5 = -X2-TDMA (inverted signal data frame)
* 6 = +D-STAR * 6 = +D-STAR
* 7 = -D-STAR * 7 = -D-STAR
* 8 = +NXDN (non inverted voice frame) * 8 = +M17 STR (non inverted stream frame)
* 9 = -NXDN (inverted voice frame) * 9 = -M17 STR (inverted stream frame)
* 10 = +DMR (non inverted signal data frame) * 10 = +DMR (non inverted signal data frame)
* 11 = -DMR (inverted signal voice frame) * 11 = -DMR (inverted signal voice frame)
* 12 = +DMR (non inverted signal voice frame) * 12 = +DMR (non inverted signal voice frame)
* 13 = -DMR (inverted signal data frame) * 13 = -DMR (inverted signal data frame)
* 14 = +ProVoice * 14 = +ProVoice
* 15 = -ProVoice * 15 = -ProVoice
* 16 = +NXDN (non inverted data frame) * 16 = +M17 LSF (non inverted link frame)
* 17 = -NXDN (inverted data frame) * 17 = -M17 LSF (inverted link frame)
* 18 = +D-STAR_HD * 18 = +D-STAR_HD
* 19 = -D-STAR_HD * 19 = -D-STAR_HD
* 20 = +dPMR Frame Sync 1 * 20 = +dPMR Frame Sync 1
@@ -209,12 +180,13 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
char synctest[25]; char synctest[25];
char synctest12[13]; //dPMR char synctest12[13]; //dPMR
char synctest10[11]; //NXDN FSW only char synctest10[11]; //NXDN FSW only
char synctest19[20]; //NXDN Preamble + FSW
char synctest18[19]; char synctest18[19];
char synctest32[33]; char synctest32[33];
char synctest20[21]; //YSF char synctest20[21]; //YSF
char synctest21[22]; //P25 S-OEMI (SACCH) char synctest21[22]; //P25 S-OEMI (SACCH)
char synctest48[49]; //EDACS char synctest48[49]; //EDACS
char synctest8[9]; //M17
char synctest16[17]; //M17 Preamble
char modulation[8]; char modulation[8];
char *synctest_p; char *synctest_p;
int symboltest_pos; //symbol test position, match to synctest_pos int symboltest_pos; //symbol test position, match to synctest_pos
@@ -228,19 +200,27 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
{ {
t_max = 10; t_max = 10;
} }
//else if dPMR //dPMR
else if (opts->frame_dpmr == 1) else if (opts->frame_dpmr == 1)
{ {
t_max = 12; //based on Frame_Sync_2 pattern t_max = 12; //based on Frame_Sync_2 pattern
} }
//if Phase 2 (or YSF in future), then only 19 else if (opts->frame_m17 == 1)
else if (state->lastsynctype == 35 || state->lastsynctype == 36) //P2 {
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 t_max = 19; //Phase 2 S-ISCH is only 19
} }
else t_max = 24; //24 for everything else 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; int lsum;
char spectrum[64]; char spectrum[64];
//init the lbuf //init the lbuf
@@ -450,15 +430,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//if using an rtl input method, do not look for sync patterns if the rms value is lower than our 'soft squelch' level //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) //tests show floor level around 40, and signal breaking 100, default is 100 for 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) if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1 || opts->frame_dpmr == 1 || opts->frame_m17 == 1)
{ {
//should we update min/max here? yes or no?
// state->max = ((state->max) + lmax) / 2;
// state->min = ((state->min) + lmin) / 2;
goto SYNC_TEST_END; goto SYNC_TEST_END;
} }
} }
@@ -573,51 +548,138 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
} }
} }
//YSF sync //YSF sync
strncpy(synctest20, (synctest_p - 19), 20); //double check make sure this is right strncpy(synctest20, (synctest_p - 19), 20);
if(opts->frame_ysf == 1) //(opts->frame_ysf == 1 if(opts->frame_ysf == 1)
{ {
if (0 == 0) //opts->inverted_ysf == 0 if (strcmp(synctest20, FUSION_SYNC) == 0)
{ {
if (strcmp(synctest20, FUSION_SYNC) == 0) printFrameSync (opts, state, "+YSF ", synctest_pos + 1, modulation);
{ state->carrier = 1;
state->carrier = 1; state->offset = synctest_pos;
state->offset = synctest_pos; state->max = ((state->max) + lmax) / 2;
state->max = ((state->max) + lmax) / 2; state->min = ((state->min) + lmin) / 2;
state->min = ((state->min) + lmin) / 2; opts->inverted_ysf = 0;
fprintf (stderr, "\nYSF FUSION SYNC \n"); state->lastsynctype = 30;
opts->inverted_ysf = 0; //should we set this here? return (30);
state->lastsynctype = 30;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (30);
}
} }
} else if (strcmp(synctest20, INV_FUSION_SYNC) == 0)
if(opts->frame_ysf == 1) //(opts->frame_ysf == 1
{
if (0 == 0) //opts->inverted_ysf == 1
{ {
if (strcmp(synctest20, INV_FUSION_SYNC) == 0) printFrameSync (opts, state, "-YSF ", synctest_pos + 1, modulation);
{ state->carrier = 1;
state->carrier = 1; state->offset = synctest_pos;
state->offset = synctest_pos; state->max = ((state->max) + lmax) / 2;
state->max = ((state->max) + lmax) / 2; state->min = ((state->min) + lmin) / 2;
state->min = ((state->min) + lmin) / 2; opts->inverted_ysf = 1;
fprintf (stderr, "\nINVERTED YSF FUSION SYNC \n"); state->lastsynctype = 31;
opts->inverted_ysf = 1; //should we set this here? return (31);
state->lastsynctype = 31;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (31);
}
} }
} }
//end YSF sync //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 //P25 P2 sync S-ISCH VCH
strncpy(synctest20, (synctest_p - 19), 20); strncpy(synctest20, (synctest_p - 19), 20);
if(opts->frame_p25p2 == 1) if(opts->frame_p25p2 == 1)
@@ -648,10 +710,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
fprintf (stderr, " P2 Missing Parameters "); fprintf (stderr, " P2 Missing Parameters ");
fprintf (stderr, "%s", KNRM); 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); state->last_cc_sync_time = time(NULL);
return (35); //35 return (35); //35
} }
@@ -687,10 +745,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
} }
state->lastsynctype = 36; //36 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); state->last_cc_sync_time = time(NULL);
return (36); //36 return (36); //36
} }
@@ -722,10 +776,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+dPMR ", synctest_pos + 1, modulation); printFrameSync (opts, state, "+dPMR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 21; state->lastsynctype = 21;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (21); return (21);
} }
if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0) if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
@@ -758,10 +808,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
} }
state->lastsynctype = 25; state->lastsynctype = 25;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (25); return (25);
} }
if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0) if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
@@ -800,20 +846,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1; //state->firstframe = 1;
} }
state->lastsynctype = 33; //33 state->lastsynctype = 33; //33
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (33); //33 return (33); //33
} }
else //inverted MS voice frame else //inverted MS voice frame
{ {
sprintf(state->ftype, "DMR MS"); sprintf(state->ftype, "DMR MS");
state->lastsynctype = 32; state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (32); return (32);
} }
} }
@@ -840,10 +878,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1; //state->firstframe = 1;
} }
state->lastsynctype = 34; state->lastsynctype = 34;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (34); return (34);
} }
} }
@@ -869,20 +903,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1; //state->firstframe = 1;
} }
state->lastsynctype = 32; state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (32); return (32);
} }
else //inverted MS data frame else //inverted MS data frame
{ {
sprintf(state->ftype, "DMR MS"); sprintf(state->ftype, "DMR MS");
state->lastsynctype = 33; state->lastsynctype = 33;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (33); return (33);
} }
@@ -905,10 +931,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation); printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 10; 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); state->last_cc_sync_time = time(NULL);
return (10); return (10);
} }
@@ -925,10 +947,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1; state->firstframe = 1;
} }
state->lastsynctype = 11; 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); state->last_cc_sync_time = time(NULL);
return (11); //11 return (11); //11
} }
@@ -950,10 +968,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation); //printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 33; 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); state->last_cc_sync_time = time(NULL);
return (33); return (33);
} }
@@ -970,10 +984,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1; state->firstframe = 1;
} }
state->lastsynctype = 32; 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); state->last_cc_sync_time = time(NULL);
return (32); return (32);
} }
@@ -995,10 +1005,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation); //printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 33; 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); state->last_cc_sync_time = time(NULL);
return (33); return (33);
} }
@@ -1015,10 +1021,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1; state->firstframe = 1;
} }
state->lastsynctype = 32; 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); state->last_cc_sync_time = time(NULL);
return (32); return (32);
} }
@@ -1044,10 +1046,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1; state->firstframe = 1;
} }
state->lastsynctype = 12; 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); state->last_cc_sync_time = time(NULL);
return (12); return (12);
} }
@@ -1061,10 +1059,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 13; 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); state->last_cc_sync_time = time(NULL);
return (13); return (13);
} }
@@ -1090,10 +1084,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1; state->firstframe = 1;
} }
state->lastsynctype = 32; 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); state->last_cc_sync_time = time(NULL);
return (32); //treat Direct Mode same as MS mode for now return (32); //treat Direct Mode same as MS mode for now
} }
@@ -1130,10 +1120,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1; state->firstframe = 1;
} }
state->lastsynctype = 32; 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); state->last_cc_sync_time = time(NULL);
return (32); return (32);
} }
@@ -1146,10 +1132,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); //printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 33; 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); state->last_cc_sync_time = time(NULL);
return (33); return (33);
} }
@@ -1227,11 +1209,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+D-STAR ", synctest_pos + 1, modulation); printFrameSync (opts, state, "+D-STAR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 6; state->lastsynctype = 6;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (6); return (6);
} }
if (strcmp (synctest, INV_DSTAR_SYNC) == 0) if (strcmp (synctest, INV_DSTAR_SYNC) == 0)
@@ -1246,11 +1223,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "-D-STAR ", synctest_pos + 1, modulation); printFrameSync (opts, state, "-D-STAR ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 7; state->lastsynctype = 7;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (7); return (7);
} }
if (strcmp (synctest, DSTAR_HD) == 0) if (strcmp (synctest, DSTAR_HD) == 0)
@@ -1265,11 +1237,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+D-STAR_HD ", synctest_pos + 1, modulation); printFrameSync (opts, state, "+D-STAR_HD ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 18; state->lastsynctype = 18;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (18); return (18);
} }
if (strcmp (synctest, INV_DSTAR_HD) == 0) if (strcmp (synctest, INV_DSTAR_HD) == 0)
@@ -1284,172 +1251,31 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "-D-STAR_HD ", synctest_pos + 1, modulation); printFrameSync (opts, state, "-D-STAR_HD ", synctest_pos + 1, modulation);
} }
state->lastsynctype = 19; state->lastsynctype = 19;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (19); return (19);
} }
} }
#ifdef NXDNOLDSYNC //Use FSW vs strncmperr method //NXDN
//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)) else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
{ {
strncpy (synctest10, (synctest_p - 9), 10); //FSW only 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
}
}
#else //use Current FSW Pattern
//NXDN FSW sync and handling - using more exact frame sync values
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
//Disabling the Preamble+FSW version for now
//its nearly impossible to catch it
//Preamble plus FSW, proceed right away
// if (
// (strcmp (synctest19, "3131133313131331131") == 0 )
// || (strcmp (synctest19, "3131133313331331131") == 0 )
// || (strcmp (synctest19, "3131133313131331111") == 0 )
// || (strcmp (synctest19, "3131133313331331111") == 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, "\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->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, "\n -PANDF ");
// // if (opts->payload == 1)
// // fprintf (stderr, " %s \n", synctest19);
// return (29);
// }
// else if (
if ( if (
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C (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, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|| (strcmp (synctest10, "3131331111") == 0 ) || (strcmp (synctest10, "3131331111") == 0 )
|| (strcmp (synctest10, "3331331111") == 0 ) || (strcmp (synctest10, "3331331111") == 0 )
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason || (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
) )
{ {
// state->carrier = 1;
state->offset = synctest_pos; state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2; state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2; state->min = ((state->min) + lmin) / 2;
// state->last_cc_sync_time = time(NULL);
if (state->lastsynctype == 28) if (state->lastsynctype == 28)
{ {
state->last_cc_sync_time = time(NULL); state->last_cc_sync_time = time(NULL);
// if (opts->payload == 1)
// fprintf (stderr, "\n +FSW ");
// if (opts->payload == 1)
// fprintf (stderr, " %s \n", synctest10);
return (28); return (28);
} }
state->lastsynctype = 28; state->lastsynctype = 28;
@@ -1457,36 +1283,27 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
else if ( else if (
(strcmp (synctest10, "1313113313") == 0 ) (strcmp (synctest10, "1313113313") == 0 )
|| (strcmp (synctest10, "1113113313") == 0 ) || (strcmp (synctest10, "1113113313") == 0 )
|| (strcmp (synctest10, "1313113333") == 0 ) || (strcmp (synctest10, "1313113333") == 0 )
|| (strcmp (synctest10, "1113113333") == 0 ) || (strcmp (synctest10, "1113113333") == 0 )
|| (strcmp (synctest10, "1313133313") == 0 ) // || (strcmp (synctest10, "1313133313") == 0 )
) )
{ {
// state->carrier = 1;
state->offset = synctest_pos; state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2; state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2; state->min = ((state->min) + lmin) / 2;
// state->last_cc_sync_time = time(NULL);
if (state->lastsynctype == 29) if (state->lastsynctype == 29)
{ {
state->last_cc_sync_time = time(NULL); state->last_cc_sync_time = time(NULL);
// if (opts->payload == 1)
// fprintf (stderr, "\n -FSW ");
// if (opts->payload == 1)
// fprintf (stderr, " %s \n", synctest10);
return (29); return (29);
} }
state->lastsynctype = 29; state->lastsynctype = 29;
} }
} }
#endif //NXDN Sync Type Selection
//Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible //Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible
#ifdef PVCONVENTIONAL #ifdef PVCONVENTIONAL
if (opts->frame_provoice == 1) if (opts->frame_provoice == 1)

View File

@@ -26,6 +26,8 @@
#include "provoice_const.h" #include "provoice_const.h"
#include "git_ver.h" #include "git_ver.h"
volatile uint8_t exitflag; //fix for issue #136
int pretty_colors() int pretty_colors()
{ {
fprintf (stderr,"%sred\n", KRED); fprintf (stderr,"%sred\n", KRED);
@@ -51,7 +53,7 @@ char * FM_banner[9] = {
" ██╔══██╗██╔════╝██╔══██╗ ███║ ╚════██║", " ██╔══██╗██╔════╝██╔══██╗ ███║ ╚════██║",
" ██║ ██║╚█████╗ ██║ ██║ Lima ███║ ███╔═╝", " ██║ ██║╚█████╗ ██║ ██║ Lima ███║ ███╔═╝",
" ██║ ██║ ╚═══██╗██║ ██║ Zulu ███║ ██╔══╝ ", " ██║ ██║ ╚═══██╗██║ ██║ Zulu ███║ ██╔══╝ ",
" ██████╔╝██████╔╝██████╔╝ Edition V ████████╗███████╗", " ██████╔╝██████╔╝██████╔╝ Edition VI ████████╗███████╗",
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═══════╝╚══════╝", " ╚═════╝ ╚═════╝ ╚═════╝ ╚═══════╝╚══════╝",
" " " "
}; };
@@ -445,6 +447,36 @@ noCarrier (dsd_opts * opts, dsd_state * state)
sprintf (state->dpmr_caller_id, "%s", " "); sprintf (state->dpmr_caller_id, "%s", " ");
sprintf (state->dpmr_target_id, "%s", " "); sprintf (state->dpmr_target_id, "%s", " ");
//YSF Fusion Call Strings
sprintf (state->ysf_tgt, "%s", " "); //10 spaces
sprintf (state->ysf_src, "%s", " "); //10 spaces
sprintf (state->ysf_upl, "%s", " "); //10 spaces
sprintf (state->ysf_dnl, "%s", " "); //10 spaces
sprintf (state->ysf_rm1, "%s", " "); //5 spaces
sprintf (state->ysf_rm2, "%s", " "); //5 spaces
sprintf (state->ysf_rm3, "%s", " "); //5 spaces
sprintf (state->ysf_rm4, "%s", " "); //5 spaces
memset (state->ysf_txt, 0, sizeof(state->ysf_txt));
state->ysf_dt = 9;
state->ysf_fi = 9;
state->ysf_cm = 9;
//M17 Storage
memset (state->m17_lsf, 1, sizeof(state->m17_lsf));
state->m17_str_dt = 9;
state->m17_dst = 0;
state->m17_src = 0;
state->m17_can = 0;
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
sprintf (state->m17_dst_str, "%s", "");
sprintf (state->m17_src_str, "%s", "");
state->m17_enc = 0;
state->m17_enc_st = 0;
memset(state->m17_meta, 0, sizeof(state->m17_meta));
} //nocarrier } //nocarrier
void void
@@ -520,13 +552,15 @@ initOpts (dsd_opts * opts)
opts->frame_dmr = 1; opts->frame_dmr = 1;
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; //forgot to init this, and Cygwin treated as it was turned on. opts->frame_ysf = 1;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
opts->uvquality = 3; opts->uvquality = 3;
opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this
opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this
opts->inverted_m17 = 0; //samples from M17_Education seem to all be positive polarity (same from m17-tools programs)
opts->mod_threshold = 26; opts->mod_threshold = 26;
opts->ssize = 128; //36 default, max is 128, much cleaner data decodes on Phase 2 cqpsk at max opts->ssize = 128; //36 default, max is 128, much cleaner data decodes on Phase 2 cqpsk at max
opts->msize = 1024; //15 default, max is 1024, much cleaner data decodes on Phase 2 cqpsk at max opts->msize = 1024; //15 default, max is 1024, much cleaner data decodes on Phase 2 cqpsk at max
@@ -588,7 +622,7 @@ initOpts (dsd_opts * opts)
opts->dmr_mute_encL = 1; opts->dmr_mute_encL = 1;
opts->dmr_mute_encR = 1; opts->dmr_mute_encR = 1;
opts->monitor_input_audio = 0; opts->monitor_input_audio = 0; //enable with -8
opts->inverted_p2 = 0; opts->inverted_p2 = 0;
opts->p2counter = 0; opts->p2counter = 0;
@@ -682,6 +716,11 @@ initState (dsd_state * state)
//Upsampled Audio Smoothing //Upsampled Audio Smoothing
state->audio_smoothing = 0; state->audio_smoothing = 0;
//analog/raw signal audio buffers
state->analog_sample_counter = 0; //when it reaches 960, then dump the raw/analog audio signal and reset
memset (state->analog_out, 0, sizeof(state->analog_out) );
//
state->audio_out_buf = malloc (sizeof (short) * 1000000); state->audio_out_buf = malloc (sizeof (short) * 1000000);
state->audio_out_bufR = malloc (sizeof (short) * 1000000); state->audio_out_bufR = malloc (sizeof (short) * 1000000);
memset (state->audio_out_buf, 0, 100 * sizeof (short)); memset (state->audio_out_buf, 0, 100 * sizeof (short));
@@ -1011,6 +1050,42 @@ initState (dsd_state * state)
sprintf (state->dpmr_caller_id, "%s", " "); sprintf (state->dpmr_caller_id, "%s", " ");
sprintf (state->dpmr_target_id, "%s", " "); sprintf (state->dpmr_target_id, "%s", " ");
//YSF Fusion Call Strings
sprintf (state->ysf_tgt, "%s", " "); //10 spaces
sprintf (state->ysf_src, "%s", " "); //10 spaces
sprintf (state->ysf_upl, "%s", " "); //10 spaces
sprintf (state->ysf_dnl, "%s", " "); //10 spaces
sprintf (state->ysf_rm1, "%s", " "); //5 spaces
sprintf (state->ysf_rm2, "%s", " "); //5 spaces
sprintf (state->ysf_rm3, "%s", " "); //5 spaces
sprintf (state->ysf_rm4, "%s", " "); //5 spaces
memset (state->ysf_txt, 0, sizeof(state->ysf_txt));
state->ysf_dt = 9;
state->ysf_fi = 9;
state->ysf_cm = 9;
//M17 Storage
memset (state->m17_lsf, 1, sizeof(state->m17_lsf));
state->m17_str_dt = 9;
state->m17_dst = 0;
state->m17_src = 0;
state->m17_can = 0;
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
sprintf (state->m17_dst_str, "%s", "");
sprintf (state->m17_src_str, "%s", "");
state->m17_enc = 0;
state->m17_enc_st = 0;
memset(state->m17_meta, 0, sizeof(state->m17_meta));
#ifdef USE_CODEC2
state->codec2_3200 = codec2_create(CODEC2_MODE_3200);
state->codec2_1600 = codec2_create(CODEC2_MODE_1600);
#endif
} //init_state } //init_state
void void
@@ -1061,6 +1136,8 @@ usage ()
printf (" -r <files> Read/Play saved mbe data from file(s)\n"); printf (" -r <files> Read/Play saved mbe data from file(s)\n");
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n"); printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
printf (" -w <file> Output synthesized speech to a .wav file, legacy auto modes only.\n"); printf (" -w <file> Output synthesized speech to a .wav file, legacy auto modes only.\n");
printf (" -8 Enable Experimental Source Audio Monitor (OSS at 48k1 and Pulse Audio)\n");
printf (" (Its recommended to use Squelch in SDR++ or GQRX, etc, if monitoring mixed analog/digital)\n");
printf (" -P Enable Per Call WAV file saving in XDMA and NXDN decoding classes\n"); printf (" -P Enable Per Call WAV file saving in XDMA and NXDN decoding classes\n");
printf (" (Per Call can only be used in Ncurses Terminal!)\n"); printf (" (Per Call can only be used in Ncurses Terminal!)\n");
printf (" (Running in console will use static wav files)\n"); printf (" (Running in console will use static wav files)\n");
@@ -1095,6 +1172,8 @@ usage ()
printf (" -f2 Decode only P25 Phase 2 (6000 sps) **\n"); printf (" -f2 Decode only P25 Phase 2 (6000 sps) **\n");
printf (" -fd Decode only D-STAR\n"); printf (" -fd Decode only D-STAR\n");
printf (" -fx Decode only X2-TDMA\n"); printf (" -fx Decode only X2-TDMA\n");
printf (" -fy Decode only YSF\n");
printf (" -fz Decode only M17*\n");
printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n");
printf (" -fn Decode only NXDN96* (12.5 kHz)\n"); printf (" -fn Decode only NXDN96* (12.5 kHz)\n");
printf (" -fp Decode only EDACS/ProVoice*\n"); printf (" -fp Decode only EDACS/ProVoice*\n");
@@ -1104,6 +1183,7 @@ usage ()
printf (" -xx Expect non-inverted X2-TDMA signal\n"); printf (" -xx Expect non-inverted X2-TDMA signal\n");
printf (" -xr Expect inverted DMR signal\n"); printf (" -xr Expect inverted DMR signal\n");
printf (" -xd Expect inverted ICOM dPMR signal\n"); printf (" -xd Expect inverted ICOM dPMR signal\n");
printf (" -xz Expect inverted M17 signal\n");
printf ("\n"); printf ("\n");
printf (" * denotes frame types that cannot be auto-detected.\n"); printf (" * denotes frame types that cannot be auto-detected.\n");
printf (" ** Phase 2 Single Frequency may require user to manually set WACN/SYSID/CC parameters if MAC_SIGNAL not present.\n"); printf (" ** Phase 2 Single Frequency may require user to manually set WACN/SYSID/CC parameters if MAC_SIGNAL not present.\n");
@@ -1120,8 +1200,8 @@ usage ()
printf (" (default=36)\n"); printf (" (default=36)\n");
printf (" -M <num> Min/Max buffer size for QPSK decision point tracking\n"); printf (" -M <num> Min/Max buffer size for QPSK decision point tracking\n");
printf (" (default=15)\n"); printf (" (default=15)\n");
printf (" -ma Auto-select modulation optimizations (default)\n"); printf (" -ma Auto-select modulation optimizations\n");
printf (" -mc Use only C4FM modulation optimizations\n"); printf (" -mc Use only C4FM modulation optimizations (default)\n");
printf (" -mg Use only GFSK modulation optimizations\n"); printf (" -mg Use only GFSK modulation optimizations\n");
printf (" -mq Use only QPSK modulation optimizations\n"); printf (" -mq Use only QPSK modulation optimizations\n");
printf (" -m2 Use P25p2 6000 sps QPSK modulation optimizations\n"); printf (" -m2 Use P25p2 6000 sps QPSK modulation optimizations\n");
@@ -1130,8 +1210,6 @@ usage ()
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n"); printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n"); printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n"); printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n");
printf (" -F Relax NXDN SACCH/FACCH/CAC/F2U CRC Pass/Fail\n");
printf (" Not recommended on NXDN, but can be bypassed if desired.\n");
printf ("\n"); printf ("\n");
printf (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n"); printf (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
printf (" (NOTE: This used to be the 'K' option! \n"); printf (" (NOTE: This used to be the 'K' option! \n");
@@ -1159,9 +1237,6 @@ usage ()
printf (" \n"); printf (" \n");
printf (" -3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n"); printf (" -3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n");
printf (" Note: Disable this if false positives on Voice ENC occur. \n"); printf (" Note: Disable this if false positives on Voice ENC occur. \n");
// printf (" -3 Enable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n");
// printf (" Note: This is experimental and may produce false positives depending on system type, notably TXI. \n");
// printf (" Use -0 or -4 options above instead if needed. \n");
printf ("\n"); printf ("\n");
printf (" Trunking Options:\n"); printf (" Trunking Options:\n");
printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n"); printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n");
@@ -1183,6 +1258,7 @@ usage ()
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 7000; NXDN96: 9000; DMR - 7000; EDACS/PV - 12500;\n"); printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 7000; NXDN96: 9000; DMR - 7000; EDACS/PV - 12500;\n");
printf (" May vary based on system stregnth, etc.\n"); printf (" May vary based on system stregnth, etc.\n");
printf (" -t <secs> Set Trunking or Fast Scan VC/sync loss hangtime in seconds. (default = 1 second)\n"); printf (" -t <secs> Set Trunking or Fast Scan VC/sync loss hangtime in seconds. (default = 1 second)\n");
printf (" -9 Force Enable EDACS Standard or Networked Mode on Systems without a netcmd (temp fix) \n");
printf ("\n"); printf ("\n");
printf (" Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n"); printf (" Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
printf (" Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n"); printf (" Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
@@ -1229,6 +1305,12 @@ if (opts->audio_in_type == 1)
open_rtlsdr_stream(opts); open_rtlsdr_stream(opts);
opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again
#ifdef __arm__
fprintf (stderr, "WARNING: RMS Function is Disabled on ARM Devices (Raspberry Pi) due to High CPU use. \n");
fprintf (stderr, "RMS/Squelch Functionality for NXDN, dPMR, EDACS Analog, M17 and Raw Audio Monitor are unavailable and these modes will not function properly. \n");
if (opts->monitor_input_audio == 1) opts->monitor_input_audio = 0;
opts->rtl_squelch_level = 0;
#endif
} }
#endif #endif
@@ -1248,6 +1330,13 @@ if (opts->audio_out_type == 0)
openPulseOutput(opts); openPulseOutput(opts);
} }
#ifdef AERO_BUILD
//TODO: More Random Cygwin Related M17 Bugs to sort out
if(opts->frame_m17 == 1 && opts->audio_in_type != 0)
for (int i = 0; i < 960; i++) getSymbol(opts, state, 1); //I think this is actually just framesync being a pain
#endif
while (1) while (1)
{ {
@@ -1296,6 +1385,11 @@ if (opts->audio_out_type == 0)
void void
cleanupAndExit (dsd_opts * opts, dsd_state * state) cleanupAndExit (dsd_opts * opts, dsd_state * state)
{ {
#ifdef USE_CODEC2
codec2_destroy(state->codec2_1600);
codec2_destroy(state->codec2_3200);
#endif
noCarrier (opts, state); noCarrier (opts, state);
if (opts->wav_out_f != NULL) if (opts->wav_out_f != NULL)
{ {
@@ -1365,7 +1459,7 @@ main (int argc, char **argv)
mbe_printVersion (versionstr); mbe_printVersion (versionstr);
#ifdef LIMAZULUTWEAKS #ifdef LIMAZULUTWEAKS
fprintf (stderr," Digital Speech Decoder: LimaZulu Edition V\n"); fprintf (stderr," Digital Speech Decoder: LimaZulu Edition VI\n");
#else #else
fprintf (stderr," Digital Speech Decoder: Florida Man Edition\n"); fprintf (stderr," Digital Speech Decoder: Florida Man Edition\n");
#endif #endif
@@ -1374,12 +1468,16 @@ main (int argc, char **argv)
} }
#ifdef AERO_BUILD #ifdef AERO_BUILD
fprintf (stderr, "Build Version: v2.1 \n"); fprintf (stderr, "Build Version: v2.1b (20230901)\n");
#else #else
fprintf (stderr, "Build Version: %s \n", GIT_TAG); fprintf (stderr, "Build Version: %s \n", GIT_TAG);
#endif #endif
fprintf (stderr,"MBElib Version: %s\n", versionstr); fprintf (stderr,"MBElib Version: %s\n", versionstr);
#ifdef USE_CODEC2
fprintf (stderr,"CODEC2 Support Enabled\n");
#endif
initOpts (&opts); initOpts (&opts);
initState (&state); initState (&state);
@@ -1387,7 +1485,7 @@ main (int argc, char **argv)
exitflag = 0; exitflag = 0;
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1) while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89Ek:")) != -1)
{ {
opterr = 0; opterr = 0;
switch (c) switch (c)
@@ -1409,6 +1507,17 @@ main (int argc, char **argv)
//NOTE: The 'K' option for single BP key has been swapped to 'b' //NOTE: The 'K' option for single BP key has been swapped to 'b'
//'K' is now used for hexidecimal key.csv imports //'K' is now used for hexidecimal key.csv imports
case '9': //This is a temporary fix for RR issue until a permanent fix can be found
state.ea_mode = 0;
fprintf (stderr,"Force Enabling EDACS Standard/Networked Mode Mode\n");
break;
//experimental audio monitoring
case '8':
opts.monitor_input_audio = 1;
fprintf (stderr,"Experimental Raw Analog Source Monitoring Enabled\n");
break;
//rc4 enforcement on DMR (due to missing the PI header) //rc4 enforcement on DMR (due to missing the PI header)
case '0': case '0':
state.M = 0x21; state.M = 0x21;
@@ -1742,11 +1851,12 @@ main (int argc, char **argv)
opts.frame_dmr = 1; opts.frame_dmr = 1;
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 1;
opts.frame_m17 = 0;
opts.pulse_digi_rate_out = 48000; // /dev/dsp does need this set to 48000 to properly process the upsampling opts.pulse_digi_rate_out = 48000; // /dev/dsp does need this set to 48000 to properly process the upsampling
opts.pulse_digi_out_channels = 1; opts.pulse_digi_out_channels = 1;
opts.dmr_stereo = 1; //switching in 'stereo' for 'mono' opts.dmr_stereo = 0; //switching in 'stereo' for 'mono'
opts.dmr_mono = 0; opts.dmr_mono = 1;
state.dmr_stereo = 0; state.dmr_stereo = 0;
//opts.setmod_bw = 7000; //opts.setmod_bw = 7000;
sprintf (opts.output_name, "Legacy Auto"); sprintf (opts.output_name, "Legacy Auto");
@@ -1763,6 +1873,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
opts.pulse_digi_rate_out = 48000; opts.pulse_digi_rate_out = 48000;
opts.pulse_digi_out_channels = 1; opts.pulse_digi_out_channels = 1;
opts.dmr_stereo = 0; opts.dmr_stereo = 0;
@@ -1784,6 +1895,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
opts.pulse_digi_rate_out = 48000; opts.pulse_digi_rate_out = 48000;
opts.pulse_digi_out_channels = 1; opts.pulse_digi_out_channels = 1;
opts.dmr_stereo = 0; opts.dmr_stereo = 0;
@@ -1804,6 +1916,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 1; opts.frame_provoice = 1;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
state.samplesPerSymbol = 5; state.samplesPerSymbol = 5;
state.symbolCenter = 2; state.symbolCenter = 2;
opts.mod_c4fm = 0; opts.mod_c4fm = 0;
@@ -1819,6 +1932,7 @@ main (int argc, char **argv)
sprintf (opts.output_name, "EDACS/PV"); sprintf (opts.output_name, "EDACS/PV");
fprintf (stderr,"Setting symbol rate to 9600 / second\n"); fprintf (stderr,"Setting symbol rate to 9600 / second\n");
fprintf (stderr,"Decoding only ProVoice frames.\n"); fprintf (stderr,"Decoding only ProVoice frames.\n");
fprintf (stderr,"EDACS Analog Voice Channels are Experimental.\n");
//rtl specific tweaks //rtl specific tweaks
opts.rtl_bandwidth = 24; opts.rtl_bandwidth = 24;
// opts.rtl_gain_value = 36; // opts.rtl_gain_value = 36;
@@ -1835,6 +1949,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
opts.dmr_stereo = 0; opts.dmr_stereo = 0;
state.dmr_stereo = 0; state.dmr_stereo = 0;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
@@ -1864,6 +1979,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
state.samplesPerSymbol = 20; state.samplesPerSymbol = 20;
state.symbolCenter = 10; state.symbolCenter = 10;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
@@ -1893,8 +2009,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 1; opts.frame_ysf = 1;
state.samplesPerSymbol = 20; //10 opts.frame_m17 = 0;
state.symbolCenter = 10;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
opts.mod_qpsk = 0; opts.mod_qpsk = 0;
opts.mod_gfsk = 0; opts.mod_gfsk = 0;
@@ -1905,8 +2020,7 @@ main (int argc, char **argv)
state.dmr_stereo = 0; state.dmr_stereo = 0;
opts.dmr_mono = 0; opts.dmr_mono = 0;
sprintf (opts.output_name, "YSF"); sprintf (opts.output_name, "YSF");
fprintf (stderr,"Setting symbol rate to 2400 / second\n"); fprintf (stderr,"Decoding only YSF frames. \n");
fprintf (stderr,"Decoding only YSF frames.\nNot working yet!\n");
} }
else if (optarg[0] == '2') else if (optarg[0] == '2')
{ {
@@ -1920,6 +2034,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
state.samplesPerSymbol = 8; state.samplesPerSymbol = 8;
state.symbolCenter = 3; state.symbolCenter = 3;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
@@ -1946,6 +2061,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
opts.mod_qpsk = 0; opts.mod_qpsk = 0;
opts.mod_gfsk = 0; opts.mod_gfsk = 0;
@@ -1971,7 +2087,8 @@ main (int argc, char **argv)
opts.frame_dmr = 1; opts.frame_dmr = 1;
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 1;
opts.frame_m17 = 0;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
opts.mod_qpsk = 0; opts.mod_qpsk = 0;
opts.mod_gfsk = 0; opts.mod_gfsk = 0;
@@ -1998,6 +2115,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
opts.mod_qpsk = 0; opts.mod_qpsk = 0;
opts.mod_gfsk = 0; opts.mod_gfsk = 0;
@@ -2023,6 +2141,7 @@ main (int argc, char **argv)
opts.frame_dpmr = 0; opts.frame_dpmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_ysf = 0; opts.frame_ysf = 0;
opts.frame_m17 = 0;
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
opts.mod_qpsk = 0; opts.mod_qpsk = 0;
opts.mod_gfsk = 0; // opts.mod_gfsk = 0; //
@@ -2049,7 +2168,8 @@ main (int argc, char **argv)
opts.frame_dmr = 0; opts.frame_dmr = 0;
opts.frame_provoice = 0; opts.frame_provoice = 0;
opts.frame_dpmr = 1; opts.frame_dpmr = 1;
opts.frame_ysf = 0; //testing with NXDN48 parameters opts.frame_ysf = 0;
opts.frame_m17 = 0;
state.samplesPerSymbol = 20; //same as NXDN48 - 20 state.samplesPerSymbol = 20; //same as NXDN48 - 20
state.symbolCenter = 10; //same as NXDN48 - 10 state.symbolCenter = 10; //same as NXDN48 - 10
opts.mod_c4fm = 1; opts.mod_c4fm = 1;
@@ -2065,6 +2185,32 @@ main (int argc, char **argv)
fprintf(stderr, "Notice: dPMR cannot autodetect polarity. \n Use -xd option if Inverted Signal expected.\n"); fprintf(stderr, "Notice: dPMR cannot autodetect polarity. \n Use -xd option if Inverted Signal expected.\n");
fprintf(stderr, "Decoding only dPMR frames.\n"); fprintf(stderr, "Decoding only dPMR frames.\n");
} }
else if (optarg[0] == 'z') //placeholder letter
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 0;
opts.frame_p25p2 = 0;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_provoice = 0;
opts.frame_dpmr = 0;
opts.frame_ysf = 0;
opts.frame_m17 = 1;
opts.mod_c4fm = 1;
opts.mod_qpsk = 0;
opts.mod_gfsk = 0;
state.rf_mod = 0;
opts.pulse_digi_rate_out = 8000;
opts.pulse_digi_out_channels = 1;
opts.dmr_stereo = 0;
opts.dmr_mono = 0;
state.dmr_stereo = 0;
sprintf (opts.output_name, "M17");
fprintf(stderr, "Notice: M17 cannot autodetect polarity. \n Use -xz option if Inverted Signal expected.\n");
fprintf(stderr, "Decoding only M17 frames.\n");
}
break; break;
//don't mess with the modulations unless you really need to //don't mess with the modulations unless you really need to
case 'm': case 'm':
@@ -2150,20 +2296,25 @@ main (int argc, char **argv)
break; break;
case 'x': case 'x':
if (optarg[0] == 'x') if (optarg[0] == 'x')
{ {
opts.inverted_x2tdma = 0; opts.inverted_x2tdma = 0;
fprintf (stderr,"Expecting non-inverted X2-TDMA signals.\n"); fprintf (stderr,"Expecting non-inverted X2-TDMA signals.\n");
} }
else if (optarg[0] == 'r') else if (optarg[0] == 'r')
{ {
opts.inverted_dmr = 1; opts.inverted_dmr = 1;
fprintf (stderr,"Expecting inverted DMR signals.\n"); fprintf (stderr,"Expecting inverted DMR signals.\n");
} }
else if (optarg[0] == 'd') else if (optarg[0] == 'd')
{ {
opts.inverted_dpmr = 1; opts.inverted_dpmr = 1;
fprintf (stderr, "Expecting inverted ICOM dPMR signals.\n"); fprintf (stderr, "Expecting inverted ICOM dPMR signals.\n");
} }
else if (optarg[0] == 'z')
{
opts.inverted_m17 = 1;
fprintf (stderr, "Expecting inverted M17 signals.\n");
}
break; break;
case 'A': case 'A':
sscanf (optarg, "%i", &opts.mod_threshold); sscanf (optarg, "%i", &opts.mod_threshold);
@@ -2363,7 +2514,8 @@ main (int argc, char **argv)
// } // }
int fmt; int fmt;
int speed = 48000; int speed = 48000;
//NOTE: Both /dev/audio AND /dev/dsp randomly open multiple input streams in Linux under padsp wrapper //NOTE: Both /dev/audio AND /dev/dsp randomly open multiple input streams in Linux under padsp wrapper
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0)) if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
@@ -2412,6 +2564,16 @@ main (int argc, char **argv)
opts.audio_in_type = 5; //5 will become OSS input type opts.audio_in_type = 5; //5 will become OSS input type
} }
//OSS cannot open different rate/channel configs on /dev/dsp on real hardware and in Cygwin
//So, in Aero builds, we need to keep the rate the same but upscale Codec2
//padsp opens a virtual output, so mixing and matching rates/channels is possible there
#ifdef AERO_BUILD
// speed = 48000;
#else
if (opts.frame_m17 == 1)
speed = 8000;
#endif
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0)) if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
{ {
sprintf (opts.audio_out_dev, "%s", "/dev/dsp"); sprintf (opts.audio_out_dev, "%s", "/dev/dsp");

View File

@@ -582,7 +582,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->dropL += 7; state->dropL += 7;
short z = 0; short z = 0;
for (short p = 0; p < 6; p++) for (short p = 0; p <= 6; p++)
{ {
//convert bytes back to bits and load into ambe_d array. //convert bytes back to bits and load into ambe_d array.
short b = 0; //reset b to use again short b = 0; //reset b to use again
@@ -660,7 +660,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->dropL += 7; state->dropL += 7;
short z = 0; short z = 0;
for (short p = 0; p < 6; p++) for (short p = 0; p <= 6; p++)
{ {
//convert bytes back to bits and load into ambe_d array. //convert bytes back to bits and load into ambe_d array.
short b = 0; //reset b to use again short b = 0; //reset b to use again
@@ -867,7 +867,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->dropR += 7; state->dropR += 7;
short z = 0; short z = 0;
for (short p = 0; p < 6; p++) for (short p = 0; p <= 6; p++)
{ {
//convert bytes back to bits and load into ambe_d array. //convert bytes back to bits and load into ambe_d array.
short b = 0; //reset b to use again short b = 0; //reset b to use again
@@ -945,7 +945,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->dropR += 7; state->dropR += 7;
short z = 0; short z = 0;
for (short p = 0; p < 6; p++) for (short p = 0; p <= 6; p++)
{ {
//convert bytes back to bits and load into ambe_d array. //convert bytes back to bits and load into ambe_d array.
short b = 0; //reset b to use again short b = 0; //reset b to use again
@@ -1058,9 +1058,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
} }
#endif #endif
state->debug_audio_errors += state->errs2 + state->errs;
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
{ {
state->debug_audio_errors += state->errs2;
if (opts->audio_out == 1) if (opts->audio_out == 1)
{ {
processAudio(opts, state); processAudio(opts, state);
@@ -1128,9 +1129,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
} }
#endif #endif
state->debug_audio_errorsR += state->errs2R + state->errsR;
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
{ {
state->debug_audio_errorsR += state->errs2R;
if (opts->audio_out == 1) if (opts->audio_out == 1)
{ {
processAudioR(opts, state); processAudioR(opts, state);
@@ -1145,7 +1147,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
//if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types //if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types
if (opts->dmr_mono == 0 && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) if (opts->dmr_mono == 0 && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) )
{ {
state->debug_audio_errors += state->errs2; state->debug_audio_errors += state->errs2 + state->errs;
if (opts->audio_out == 1) if (opts->audio_out == 1)
{ {
processAudio(opts, state); processAudio(opts, state);

View File

@@ -85,7 +85,7 @@ char * SyncTypes[44] = {
"NXDN", "NXDN",
"NXDN", "NXDN",
"YSF", //30 "YSF", //30
"YSF", "YSF", //31
"DMR", "DMR",
"DMR", "DMR",
"DMR", "DMR",
@@ -248,7 +248,11 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
#endif #endif
char * getDateN(void) { char * getDateN(void) {
char datename[80]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text #ifdef AERO_BUILD
char datename[80];
#else
char datename[99];
#endif
char * curr2; char * curr2;
struct tm * to; struct tm * to;
time_t t; time_t t;
@@ -274,9 +278,9 @@ char * getTimeN(void) //get pretty hh:mm:ss timestamp
return curr; return curr;
} }
//this version is broken now in Cygwin with the 80 value, reverted back
char * getDateC(time_t t) { char * getDateC(time_t t) {
char datename[99]; //Ubuntu 32-bit, use 80; everything else, use 99 char datename[99];
char * curr2; char * curr2;
struct tm * to; struct tm * to;
@@ -301,7 +305,7 @@ char * getTimeC(time_t t) //get pretty hh:mm:ss timestamp
//testing a few things, going to put this into ncursesMenu //testing a few things, going to put this into ncursesMenu
#define WIDTH 36 #define WIDTH 36
#define HEIGHT 23 #define HEIGHT 25
int startx = 0; int startx = 0;
int starty = 0; int starty = 0;
@@ -338,7 +342,8 @@ char *choices[] = {
"Decode dPMR", "Decode dPMR",
"Decode NXDN48", "Decode NXDN48",
"Decode NXDN96", "Decode NXDN96",
"Decode DMR Stereo", //was X2-TDMA* "Decode DMR TDMA",
"Decode YSF FUSION",
"Toggle Signal Inversion", "Toggle Signal Inversion",
"Key Entry", "Key Entry",
"Reset Call History", "Reset Call History",
@@ -542,7 +547,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
info_win = newwin(6, WIDTH+18, starty, startx+20); info_win = newwin(6, WIDTH+18, starty, startx+20);
box (info_win, 0, 0); box (info_win, 0, 0);
mvwprintw(info_win, 2, 2, " Legacy Auto can only detect the following:"); mvwprintw(info_win, 2, 2, " Legacy Auto can only detect the following:");
mvwprintw(info_win, 3, 2, " P25-P1, D-STAR, DMR Mono, and X2-TDMA"); mvwprintw(info_win, 3, 2, " P25p1, D-STAR, DMR Mono, YSF, and X2-TDMA");
wrefresh(info_win); wrefresh(info_win);
} }
@@ -551,13 +556,13 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
info_win = newwin(7, WIDTH+18, starty, startx+20); info_win = newwin(7, WIDTH+18, starty, startx+20);
box (info_win, 0, 0); box (info_win, 0, 0);
mvwprintw(info_win, 2, 2, " XDMA Decoding Class Supports the following:"); mvwprintw(info_win, 2, 2, " XDMA Decoding Class Supports the following:");
mvwprintw(info_win, 3, 2, " P25-P1, P25-P2, and DMR Stereo BS/MS"); mvwprintw(info_win, 3, 2, " P25p1, P25p2, YSF, and DMR BS/MS");
mvwprintw(info_win, 4, 2, " --C4FM / FSK4 only, and OP25 P2 Capture Bins"); mvwprintw(info_win, 4, 2, " C4FM, FSK4, QPSK only (no H8D-QPSK)");
wrefresh(info_win); wrefresh(info_win);
} }
//Input Output Options //Input Output Options
if (choice == 17) if (choice == 18)
{ {
//test making a new window while other window is open //test making a new window while other window is open
test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5); test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5);
@@ -1086,7 +1091,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
} }
//Privacy Key Entry //Privacy Key Entry
if (choice == 13) if (choice == 14)
{ {
state->payload_keyid = 0; state->payload_keyid = 0;
state->payload_keyidR = 0; state->payload_keyidR = 0;
@@ -1259,7 +1264,8 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dmr = 1; opts->frame_dmr = 1;
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 1;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1290,6 +1296,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 1; opts->frame_provoice = 1;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 0; opts->mod_c4fm = 0;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 1; opts->mod_gfsk = 1;
@@ -1318,6 +1325,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1356,6 +1364,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1392,7 +1401,8 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_nxdn96 = 0; opts->frame_nxdn96 = 0;
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 1;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1420,6 +1430,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1447,6 +1458,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 1; opts->frame_dpmr = 1;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1477,6 +1489,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
//opts->unmute_encrypted_p25 = 0; //opts->unmute_encrypted_p25 = 0;
// opts->mod_qpsk = 0; // opts->mod_qpsk = 0;
@@ -1504,6 +1517,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1532,6 +1546,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->frame_dpmr = 0; opts->frame_dpmr = 0;
opts->frame_provoice = 0; opts->frame_provoice = 0;
opts->frame_ysf = 0; opts->frame_ysf = 0;
opts->frame_m17 = 0;
opts->mod_c4fm = 1; opts->mod_c4fm = 1;
opts->mod_qpsk = 0; opts->mod_qpsk = 0;
opts->mod_gfsk = 0; opts->mod_gfsk = 0;
@@ -1539,6 +1554,60 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
//opts->unmute_encrypted_p25 = 0; //opts->unmute_encrypted_p25 = 0;
} }
if (choice == 12) if (choice == 12)
{
//Decode YSF Fusion
// resetState (state); //use sparingly, may cause memory leak
state->samplesPerSymbol = 10;
state->symbolCenter = 4;
sprintf (opts->output_name, "YSF");
opts->dmr_mono = 0;
opts->dmr_stereo = 0; //this value is the end user option
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
opts->pulse_digi_rate_out = 48000;
opts->pulse_digi_out_channels = 1;
opts->frame_dstar = 0;
opts->frame_x2tdma = 0;
opts->frame_p25p1 = 0;
opts->frame_nxdn48 = 0;
opts->frame_nxdn96 = 0;
opts->frame_dmr = 0;
opts->frame_dpmr = 0;
opts->frame_provoice = 0;
opts->frame_ysf = 1;
opts->frame_m17 = 0;
opts->mod_c4fm = 1;
opts->mod_qpsk = 0;
opts->mod_gfsk = 0;
state->rf_mod = 0;
}
if (choice == 99) //TODO: Slot this into the menu choices, and maybe rearrange them into the correct order as well
{
//Decode M17
// resetState (state); //use sparingly, may cause memory leak
state->samplesPerSymbol = 10;
state->symbolCenter = 4;
sprintf (opts->output_name, "M17");
opts->dmr_mono = 0;
opts->dmr_stereo = 0; //this value is the end user option
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
opts->pulse_digi_rate_out = 8000;
opts->pulse_digi_out_channels = 1;
opts->frame_dstar = 0;
opts->frame_x2tdma = 0;
opts->frame_p25p1 = 0;
opts->frame_nxdn48 = 0;
opts->frame_nxdn96 = 0;
opts->frame_dmr = 0;
opts->frame_dpmr = 0;
opts->frame_provoice = 0;
opts->frame_ysf = 0;
opts->frame_m17 = 1;
opts->mod_c4fm = 1;
opts->mod_qpsk = 0;
opts->mod_gfsk = 0;
state->rf_mod = 0;
}
if (choice == 13)
{ {
//Set all signal for inversion or uninversion //Set all signal for inversion or uninversion
if (opts->inverted_dmr == 0) if (opts->inverted_dmr == 0)
@@ -1547,6 +1616,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->inverted_dpmr = 1; opts->inverted_dpmr = 1;
opts->inverted_x2tdma = 1; opts->inverted_x2tdma = 1;
opts->inverted_ysf = 1; opts->inverted_ysf = 1;
opts->inverted_m17 = 1;
} }
else else
{ {
@@ -1554,10 +1624,11 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->inverted_dpmr = 0; opts->inverted_dpmr = 0;
opts->inverted_x2tdma = 0; opts->inverted_x2tdma = 0;
opts->inverted_ysf = 0; opts->inverted_ysf = 0;
opts->inverted_m17 = 0;
} }
} }
if (choice == 14) //reset call history (usually if janky output when switching modes) if (choice == 15) //reset call history (usually if janky output when switching modes)
{ {
for (short int k = 0; k <= 9; k++) for (short int k = 0; k <= 9; k++)
{ {
@@ -1582,7 +1653,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
state->lasttgR = 0; state->lasttgR = 0;
} }
if (choice == 15) //toggle payload printing if (choice == 16) //toggle payload printing
{ {
if (opts->payload == 0) if (opts->payload == 0)
{ {
@@ -1595,7 +1666,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
fprintf(stderr, "Payload Off\n"); fprintf(stderr, "Payload Off\n");
} }
} }
if (choice == 16) if (choice == 17)
{ {
//hardset P2 WACN, SYSID, and NAC //hardset P2 WACN, SYSID, and NAC
entry_win = newwin(6, WIDTH+16, starty+10, startx+10); entry_win = newwin(6, WIDTH+16, starty+10, startx+10);
@@ -1648,7 +1719,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
} }
if (choice == 18) if (choice == 19)
{ {
short int lrrpchoice = 0; short int lrrpchoice = 0;
entry_win = newwin(10, WIDTH+16, starty+10, startx+10); entry_win = newwin(10, WIDTH+16, starty+10, startx+10);
@@ -1714,7 +1785,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
opts->lrrp_out_file[0] = 0; opts->lrrp_out_file[0] = 0;
} }
} }
if (choice == 19) if (choice == 20)
{ {
ncursesClose(); ncursesClose();
//cleanup_rtlsdr_stream(); //cleanup_rtlsdr_stream();
@@ -1754,7 +1825,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
rtl_clean_queue(); rtl_clean_queue();
reset_dibit_buffer(state); //test and observe for any random issues, disable if needed reset_dibit_buffer(state); //test and observe for any random issues, disable if needed
#elif AERO_BUILD #elif AERO_BUILD
opts->audio_out_type = 3; //hopefully the audio stream is still/already open opts->audio_out_type = 5; //hopefully the audio stream is still/already open //shouldn't this be 5? Was set to 3
#else #else
opts->audio_out_type = 0; //need to see if we need to open pulseoutput as well here? opts->audio_out_type = 0; //need to see if we need to open pulseoutput as well here?
openPulseOutput (opts); openPulseOutput (opts);
@@ -2158,21 +2229,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->ncurses_compact == 1) if (opts->ncurses_compact == 1)
{ {
printw ("------------------------------------------------------------------------------\n"); printw ("------------------------------------------------------------------------------\n");
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.1 "); printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.1b (20230901)");
printw ("------------------------------------------------------------------------------\n"); printw ("------------------------------------------------------------------------------\n");
} }
#elif LIMAZULUTWEAKS #elif LIMAZULUTWEAKS
if (opts->ncurses_compact == 1) if (opts->ncurses_compact == 1)
{ {
printw ("------------------------------------------------------------------------------\n"); printw ("------------------------------------------------------------------------------\n");
printw ("| Digital Speech Decoder: LimaZulu Edition V: The Empire Strikes Back \n"); printw ("| Digital Speech Decoder: LimaZulu Edition VI: Return of the Zulu \n");
printw ("------------------------------------------------------------------------------\n");
}
#elif ZDEV_BUILD
if (opts->ncurses_compact == 1)
{
printw ("------------------------------------------------------------------------------\n");
printw ("| Digital Speech Decoder: Florida Man Edition - zDEV %s \n", GIT_TAG);
printw ("------------------------------------------------------------------------------\n"); printw ("------------------------------------------------------------------------------\n");
} }
#else #else
@@ -2191,13 +2255,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("%s", FM_bannerN[i]); printw("%s", FM_bannerN[i]);
if (i == 1) printw (" ESC to Menu"); if (i == 1) printw (" ESC to Menu");
if (i == 2) printw (" 'q' to Quit "); if (i == 2) printw (" 'q' to Quit ");
if (i == 4) printw (" MBElib %s", versionstr); if (i == 4 && opts->frame_m17 == 0) printw (" MBElib %s", versionstr);
#ifdef USE_CODEC2
if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2");
#endif
#ifdef AERO_BUILD #ifdef AERO_BUILD
if (i == 5) printw (" %s ", "Aero Build"); if (i == 5) printw (" %s ", "Aero Build");
if (i == 6) printw (" v2.1 \n"); if (i == 6) printw (" v2.1b (20230901) \n");
#elif ZDEV_BUILD
if (i == 5) printw (" %s ", "zDEV Build");
if (i == 6) printw (" %s \n", GIT_TAG);
#else #else
if (i == 5) printw (" %s ", "Main Build"); if (i == 5) printw (" %s ", "Main Build");
if (i == 6) printw (" %s \n", GIT_TAG); if (i == 6) printw (" %s \n", GIT_TAG);
@@ -2248,7 +2312,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw (" Gain: %idB;", opts->rtl_gain_value); printw (" Gain: %idB;", opts->rtl_gain_value);
printw (" PPM: %i;", opts->rtlsdr_ppm_error); printw (" PPM: %i;", opts->rtlsdr_ppm_error);
printw (" SQ: %i;", opts->rtl_squelch_level); printw (" SQ: %i;", opts->rtl_squelch_level);
printw (" RMS: %04i;", opts->rtl_rms); printw (" RMS: %04li;", opts->rtl_rms);
printw (" BW: %i kHz;", opts->rtl_bandwidth); printw (" BW: %i kHz;", opts->rtl_bandwidth);
printw (" FRQ: %i;", opts->rtlsdr_center_freq); printw (" FRQ: %i;", opts->rtlsdr_center_freq);
if (opts->rtl_udp_port != 0) printw ("\n| External Tuning on UDP Port: %i", opts->rtl_udp_port); if (opts->rtl_udp_port != 0) printw ("\n| External Tuning on UDP Port: %i", opts->rtl_udp_port);
@@ -2260,15 +2324,22 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (state->audio_smoothing == 1) printw (" - Smoothing On"); if (state->audio_smoothing == 1) printw (" - Smoothing On");
printw (" \n"); printw (" \n");
} }
if ( opts->audio_out_type == 0 && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
{
printw ("| Pulse Audio Output: %i kHz; %i Ch; RMS: %04ld Analog", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->rtl_rms);
printw (" \n");
}
if (opts->audio_out_type == 5) if (opts->audio_out_type == 5)
{ {
printw ("| OSS Audio Output: [%2i] kHz [1] Channel", SAMPLE_RATE_OUT/1000); printw ("| OSS Audio Output: [%2i] kHz [1] Channel", SAMPLE_RATE_OUT/1000);
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
printw (" - Analog RMS: %04ld ", opts->rtl_rms);
if (state->audio_smoothing == 1) printw (" - Smoothing On"); if (state->audio_smoothing == 1) printw (" - Smoothing On");
printw (" \n"); printw (" \n");
} }
if (opts->monitor_input_audio == 1) if (opts->monitor_input_audio == 1)
{ {
printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected\n"); printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected (WIP)\n");
} }
if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0) if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0)
{ {
@@ -2352,7 +2423,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{ {
printw ("| Fast Scan Mode Enabled "); printw ("| Fast Scan Mode Enabled ");
if (state->lcn_freq_roll != 0) if (state->lcn_freq_roll != 0)
printw (" - Frequency: [%.06lf] Mhz", (double)state->trunk_lcn_freq[state->lcn_freq_roll-1]/1000000); printw (" - Frequency: %.06lf Mhz", (double)state->trunk_lcn_freq[state->lcn_freq_roll-1]/1000000);
printw (" Speed: %.02lf sec \n", opts->trunk_hangtime); //not sure values less than 1 make a difference, may be system/environment dependent printw (" Speed: %.02lf sec \n", opts->trunk_hangtime); //not sure values less than 1 make a difference, may be system/environment dependent
} }
@@ -2409,6 +2480,133 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
} }
} }
//M17
if (lls == 8 || lls == 9 || lls == 16 || lls == 17)
{
printw ("| ");
printw ("M17: ");
//insert data type and frame information
if (state->m17_str_dt == 0) printw("Reserved");
if (state->m17_str_dt == 1) printw("Data ");
if (state->m17_str_dt == 2) printw("Voice (3200) ");
if (state->m17_str_dt == 3) printw("Voice (1600) + Data");
printw ("\n");
printw ("| ");
printw ("DST: ");
if (state->m17_dst == 0xFFFFFFFFFFFF)
printw("BROADCAST ");
else if (state->m17_dst != 0 && state->m17_dst >= 0xEE6B28000000)
printw("RESERVED (%012llx) ", state->m17_dst);
else
printw("%s", state->m17_dst_str);
printw ("\n");
printw ("| ");
printw ("SRC: ");
if (state->m17_src != 0 && state->m17_src >= 0xEE6B28000000)
printw("RESERVED (%012llx)", state->m17_src);
else
printw("%s", state->m17_src_str);
printw ("\n");
printw ("| ");
printw ("CAN: %02d ", state->m17_can);
printw ("\n");
printw ("| ");
//fill in any extra info, like Meta (IV, etc)
if (state->m17_enc == 1)
{
printw (" Scrambler - Type: %d", state->m17_enc_st);
}
if (state->m17_enc == 2)
{
printw (" AES-CTR - IV: ");
//display packed meta as IV
for (i = 0; i < 14; i++)
printw ("%02X", state->m17_meta[i]);
}
if (state->m17_enc == 3)
{
printw (" Reserved Enc - Type: %d", state->m17_enc_st);
}
printw ("\n");
}
//YSF
if (lls == 30 || lls == 31)
{
// printw ("\n");
printw ("| ");
printw ("Fusion - ");
//insert data type and frame information
if (state->ysf_dt == 0) printw("V/D1 ");
if (state->ysf_dt == 1) printw("DATA ");
if (state->ysf_dt == 2) printw("V/D2 ");
if (state->ysf_dt == 3) printw("VWFR ");
printw (" ");
if (state->ysf_cm == 0) printw("Group/CQ ");
if (state->ysf_cm == 3) printw("Private ");
if (state->ysf_cm == 1) printw("Radio ID ");
if (state->ysf_cm == 2) printw("Reserved ");
if (state->ysf_fi == 0) printw("HC ");
if (state->ysf_fi == 1) printw("CC ");
if (state->ysf_fi == 2) printw("TC ");
if (state->ysf_fi == 3) printw("XX ");
printw ("\n");
printw ("| ");
//NOTE: In Radio ID Mode, the DST will be split on Destination and Source Radio ID values
printw ("DST: %s ", state->ysf_tgt);
printw ("SRC: %s ", state->ysf_src);
printw ("\n");
printw ("| ");
printw ("UPL: %s ", state->ysf_upl);
printw ("DNL: %s ", state->ysf_dnl);
printw ("\n");
printw ("| ");
printw ("RM1: %s ", state->ysf_rm1);
printw ("RM2: %s ", state->ysf_rm2);
printw ("\n");
printw ("| ");
printw ("RM3: %s ", state->ysf_rm3);
printw ("RM4: %s ", state->ysf_rm4);
//these texts can get pretty long and out of sorts, and lots of 0x20 spaces
//just going to leave these to only be in the console output
// printw ("\n");
// printw ("| ");
// printw ("TXT: ");
// for (i = 4; i < 8; i++)
// {
// for (int j = 0; j < 20; j++)
// {
// //no spaces and no asterisks
// if (state->ysf_txt[i][j] != 0x2A)
// printw ("%c", state->ysf_txt[i][j]);
// }
// // printw (" "); //just a single space between each 'block'
// }
printw ("\n");
}
//NXDN //NXDN
if (lls == 28 || lls == 29) if (lls == 28 || lls == 29)
{ {
@@ -2424,7 +2622,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 Channel if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 Channel
if (state->p25_cc_freq != 0) if (state->p25_cc_freq != 0)
{ {
printw (" - Frequency: [%.06lf] Mhz ", (double)state->p25_cc_freq/1000000); printw (" - Frequency: %.06lf Mhz ", (double)state->p25_cc_freq/1000000);
} }
} }
else if (opts->p25_is_tuned == 1) else if (opts->p25_is_tuned == 1)
@@ -2433,7 +2631,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2 if (idas == 1) printw ("Monitoring RTCH2 Channel"); //Idas RTCH2
if (state->p25_vc_freq[0] != 0) if (state->p25_vc_freq[0] != 0)
{ {
printw (" - Frequency: [%.06lf] Mhz ", (double)state->p25_vc_freq[0]/1000000); printw (" - Frequency: %.06lf Mhz ", (double)state->p25_vc_freq[0]/1000000);
} }
} }
@@ -2443,13 +2641,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("| "); printw ("| ");
#ifdef LIMAZULUTWEAKS // #ifdef LIMAZULUTWEAKS
if (idas == 0) printw ("NXDN - RAN: [%02d] ", state->nxdn_last_ran); if (idas == 0) printw ("NXDN - RAN: [%02d] ", state->nxdn_last_ran);
if (idas == 1) printw ("IDAS - Area: [%02d] ", state->nxdn_last_ran); if (idas == 1) printw ("IDAS - Area: [%02d] ", state->nxdn_last_ran);
#else // #else
if (idas == 0) printw ("NXDN - RAN: [%02d] ", rn); // if (idas == 0) printw ("NXDN - RAN: [%02d] ", rn);
if (idas == 1) printw ("IDAS - Area: [%02d] ", rn); // if (idas == 1) printw ("IDAS - Area: [%02d] ", rn);
#endif // #endif
if (state->nxdn_location_site_code != 0) if (state->nxdn_location_site_code != 0)
{ {
printw ("Cat: [%s] ", state->nxdn_location_category); printw ("Cat: [%s] ", state->nxdn_location_category);
@@ -2581,15 +2779,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("%s", state->dmr_site_parms); //site id, net id, etc printw ("%s", state->dmr_site_parms); //site id, net id, etc
if (state->dmr_rest_channel > 0) if (state->dmr_rest_channel > 0)
{ {
printw ("Rest Channel: [%02d] ", state->dmr_rest_channel); printw ("Rest LSN: %02d; ", state->dmr_rest_channel);
if (state->trunk_chan_map[state->dmr_rest_channel] != 0) if (state->trunk_chan_map[state->dmr_rest_channel] != 0)
{ {
printw ("Freq: [%.06lf] Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000); printw ("Freq: %.06lf Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000);
} }
} }
else if (state->p25_cc_freq != 0) else if (state->p25_cc_freq != 0)
{ {
printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000); printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
} }
} }
@@ -2602,7 +2800,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("P25 P1 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid); printw ("P25 P1 - [%05llX][%03llX][%03llX] RFSS: [%lld] SITE: [%lld] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
if (state->p25_cc_freq != 0) if (state->p25_cc_freq != 0)
{ {
printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000); printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
} }
} }
else if (lls == 35 || lls == 36) //P2 else if (lls == 35 || lls == 36) //P2
@@ -2624,7 +2822,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{ {
if (state->p25_cc_freq != 0) if (state->p25_cc_freq != 0)
{ {
printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000); printw ("Freq: %.06lf MHz", (double)state->p25_cc_freq/1000000);
} }
} }
} }
@@ -2721,7 +2919,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("Double DES"); printw("Double DES");
attron(COLOR_PAIR(3)); attron(COLOR_PAIR(3));
} }
if (state->payload_algid == 0x83 || state->payload_algid == 0x23) if (state->payload_algid == 0x83)
{ {
attron(COLOR_PAIR(1)); attron(COLOR_PAIR(1));
printw("Triple DES"); printw("Triple DES");
@@ -2914,7 +3112,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("DES-OFB"); printw("DES-OFB");
attron(COLOR_PAIR(3)); attron(COLOR_PAIR(3));
} }
if (state->payload_algidR == 0x83 || state->payload_algidR == 0x23) if (state->payload_algidR == 0x83)
{ {
attron(COLOR_PAIR(1)); attron(COLOR_PAIR(1));
printw("Triple DES"); printw("Triple DES");
@@ -3049,7 +3247,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (state->p25_vc_freq[0] != 0) if (state->p25_vc_freq[0] != 0)
{ {
attron(COLOR_PAIR(4)); attron(COLOR_PAIR(4));
printw ("Frequency: [%.06lf] MHz ", (double)state->p25_vc_freq[0]/1000000); printw ("Frequency: %.06lf MHz ", (double)state->p25_vc_freq[0]/1000000);
} }
if (state->carrier == 1) attron(COLOR_PAIR(3)); if (state->carrier == 1) attron(COLOR_PAIR(3));
else attroff(COLOR_PAIR(4)); else attroff(COLOR_PAIR(4));
@@ -3363,6 +3561,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
opts->inverted_dpmr = 1; opts->inverted_dpmr = 1;
opts->inverted_x2tdma = 1; opts->inverted_x2tdma = 1;
opts->inverted_ysf = 1; opts->inverted_ysf = 1;
opts->inverted_m17 = 1;
} }
else else
{ {
@@ -3370,6 +3569,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
opts->inverted_dpmr = 0; opts->inverted_dpmr = 0;
opts->inverted_x2tdma = 0; opts->inverted_x2tdma = 0;
opts->inverted_ysf = 0; opts->inverted_ysf = 0;
opts->inverted_m17 = 0;
} }
} }

View File

@@ -17,6 +17,29 @@
#include "dsd.h" #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 int
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) 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); 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 //open pulse input if we are pulse output AND using ncurses terminal
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1) if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
{ {
@@ -129,14 +152,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
else if (opts->audio_in_type == 3) else if (opts->audio_in_type == 3)
{ {
#ifdef USE_RTLSDR #ifdef USE_RTLSDR
// TODO: need to read demodulated stream here // Read demodulated stream here
// get_rtlsdr_sample(&sample);
get_rtlsdr_sample(&sample, opts, state); 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(); opts->rtl_rms = rtl_return_rms();
#endif #endif
@@ -247,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 //Source Audio Monitoring
// else if (opts->audio_in_type == 8) if (have_sync == 0 && opts->monitor_input_audio == 1)
// { {
// result = sf_read_short(opts->tcp_file_in, &sample, 1); //sanity check to prevent an overflow
// if(result == 0) { if (state->analog_sample_counter > 959)
state->analog_sample_counter = 959;
// fprintf (stderr, "Connection to TCP Server Disconnected.\n"); state->analog_out[state->analog_sample_counter++] = sample;
// //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);
// }
// }
//UDP Socket input...not working correct. Reads samples, but no sync if (state->analog_sample_counter == 960)
// else if (opts->audio_in_type == 6) {
// { //get an rms value if not using the rtl built in version
//I think this doesn't get the entire dgram when we run sf_read_short on the udp dgram if (opts->audio_in_type != 3)
// result = sf_read_short(opts->udp_file_in, &sample, 1); opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
// if (sample != 0)
// fprintf (stderr, "Result = %d Sample = %d \n", result, sample); //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 (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); sample = dmr_filter(sample);
} }
else if (state->lastsynctype == 8 || state->lastsynctype == 9 || else if (state->lastsynctype == 8 || state->lastsynctype == 9 ||state->lastsynctype == 16 || state->lastsynctype == 17)
state->lastsynctype == 16 || state->lastsynctype == 17 || {
sample = m17_filter(sample);
}
else if (
state->lastsynctype == 20 || state->lastsynctype == 21 || state->lastsynctype == 20 || state->lastsynctype == 21 ||
state->lastsynctype == 22 || state->lastsynctype == 23 || state->lastsynctype == 22 || state->lastsynctype == 23 ||
state->lastsynctype == 24 || state->lastsynctype == 25 || state->lastsynctype == 24 || state->lastsynctype == 25 ||
@@ -522,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 // opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
fclose(opts->symbolfile); 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 //open pulse input if we are pulse output AND using ncurses terminal
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1) if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
{ {

View File

@@ -14,12 +14,16 @@
* 1994-7 * 1994-7
* *
* LWVMOBILE * LWVMOBILE
* 2022-10 Version EDACS-FM Florida Man Edition * 2023-08 Version EDACS-FM Florida Man Edition
*-----------------------------------------------------------------------------*/ *-----------------------------------------------------------------------------*/
#include "dsd.h" #include "dsd.h"
char * getDateE(void) { 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; char * curr2;
struct tm * to; struct tm * to;
time_t t; time_t t;
@@ -45,6 +49,191 @@ char * getTimeE(void) //get pretty hh:mm:ss timestamp
return curr; 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) 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) //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 command = 0xFF;
unsigned char mt1 = 0x1F; unsigned char mt1 = 0x1F;
unsigned char mt2 = 0xF; unsigned char mt2 = 0xF;
unsigned char mta = 0;
unsigned char lcn = 0; unsigned char lcn = 0;
//commands; may not use these anymore //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 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. 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 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 //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 //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 //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 //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)) ) 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 //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 //Start Extended Addressing Mode
if (state->ea_mode == 1) 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); 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); 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 //do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
@@ -292,8 +481,9 @@ void edacs(dsd_opts * opts, dsd_state * state)
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); 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 SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
state->edacs_tuned_lcn = lcn; 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 if (opts->audio_in_type == 3) //rtl dongle
@@ -302,6 +492,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]); rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
state->edacs_tuned_lcn = lcn; 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 #endif
} }
@@ -400,46 +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) if (command == 0xEE)
{
//no handling for raw audio yet...that works properly atleast
fprintf (stderr, " Analog"); 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"); 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 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 (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3)) if (command == 0xEF) openWavOutFile (opts, state); //digital
{ if (command == 0xEE) openWavOutFile48k (opts, state); //analog at 48k
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->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
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw); state->edacs_tuned_lcn = lcn;
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero opts->p25_is_tuned = 1;
state->edacs_tuned_lcn = lcn; if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
opts->p25_is_tuned = 1; }
}
if (opts->audio_in_type == 3) //rtl dongle
if (opts->audio_in_type == 3) //rtl dongle {
{ #ifdef USE_RTLSDR
#ifdef USE_RTLSDR rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]); state->edacs_tuned_lcn = lcn;
state->edacs_tuned_lcn = lcn; opts->p25_is_tuned = 1;
opts->p25_is_tuned = 1; if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
#endif #endif
}
} }
} }
} }
fprintf (stderr, "%s", KNRM); fprintf (stderr, "%s", KNRM);
} }
@@ -460,7 +663,9 @@ void edacs(dsd_opts * opts, dsd_state * state)
} //end Standard or Networked } //end Standard or Networked
} }
ENDPV:
fprintf (stderr, "\n"); fprintf (stderr, "\n");

View File

@@ -178,146 +178,166 @@ int ez_rs28_sacch (int payload[180], int parity[132])
return (ec); return (ec);
} }
//I-ISCH Lookup section, borrowed from OP25 std::map <std::uint64_t, int> isch_map;
std::map <std::string, int> isch_map;
void map_isch() void map_isch()
{ {
isch_map["184229d461"] = 0; isch_map[0x184229d461ULL] = 0;
isch_map["18761451f6"] = 1; isch_map[0x18761451f6ULL] = 1;
isch_map["181ae27e2f"] = 2; isch_map[0x181ae27e2fULL] = 2;
isch_map["182edffbb8"] = 3; isch_map[0x182edffbb8ULL] = 3;
isch_map["18df8a7510"] = 4; isch_map[0x18df8a7510ULL] = 4;
isch_map["18ebb7f087"] = 5; isch_map[0x18ebb7f087ULL] = 5;
isch_map["188741df5e"] = 6; isch_map[0x188741df5eULL] = 6;
isch_map["18b37c5ac9"] = 7; isch_map[0x18b37c5ac9ULL] = 7;
isch_map["1146a44f13"] = 8; isch_map[0x1146a44f13ULL] = 8;
isch_map["117299ca84"] = 9; isch_map[0x117299ca84ULL] = 9;
isch_map["111e6fe55d"] = 10; isch_map[0x111e6fe55dULL] = 10;
isch_map["112a5260ca"] = 11; isch_map[0x112a5260caULL] = 11;
isch_map["11db07ee62"] = 12; isch_map[0x11db07ee62ULL] = 12;
isch_map["11ef3a6bf5"] = 13; isch_map[0x11ef3a6bf5ULL] = 13;
isch_map["1183cc442c"] = 14; isch_map[0x1183cc442cULL] = 14;
isch_map["11b7f1c1bb"] = 15; isch_map[0x11b7f1c1bbULL] = 15;
isch_map["1a4a2e239e"] = 16; isch_map[0x1a4a2e239eULL] = 16;
isch_map["1a7e13a609"] = 17; isch_map[0x1a7e13a609ULL] = 17;
isch_map["1a12e589d0"] = 18; isch_map[0x1a12e589d0ULL] = 18;
isch_map["1a26d80c47"] = 19; isch_map[0x1a26d80c47ULL] = 19;
isch_map["1ad78d82ef"] = 20; isch_map[0x1ad78d82efULL] = 20;
isch_map["1ae3b00778"] = 21; isch_map[0x1ae3b00778ULL] = 21;
isch_map["1a8f4628a1"] = 22; isch_map[0x1a8f4628a1ULL] = 22;
isch_map["1abb7bad36"] = 23; isch_map[0x1abb7bad36ULL] = 23;
isch_map["134ea3b8ec"] = 24; isch_map[0x134ea3b8ecULL] = 24;
isch_map["137a9e3d7b"] = 25; isch_map[0x137a9e3d7bULL] = 25;
isch_map["13166812a2"] = 26; isch_map[0x13166812a2ULL] = 26;
isch_map["1322559735"] = 27; isch_map[0x1322559735ULL] = 27;
isch_map["13d300199d"] = 28; isch_map[0x13d300199dULL] = 28;
isch_map["13e73d9c0a"] = 29; isch_map[0x13e73d9c0aULL] = 29;
isch_map["138bcbb3d3"] = 30; isch_map[0x138bcbb3d3ULL] = 30;
isch_map["13bff63644"] = 31; isch_map[0x13bff63644ULL] = 31;
isch_map["1442f705ef"] = 32; isch_map[0x1442f705efULL] = 32;
isch_map["1476ca8078"] = 33; isch_map[0x1476ca8078ULL] = 33;
isch_map["141a3cafa1"] = 34; isch_map[0x141a3cafa1ULL] = 34;
isch_map["142e012a36"] = 35; isch_map[0x142e012a36ULL] = 35;
isch_map["14df54a49e"] = 36; isch_map[0x14df54a49eULL] = 36;
isch_map["14eb692109"] = 37; isch_map[0x14eb692109ULL] = 37;
isch_map["14879f0ed0"] = 38; isch_map[0x14879f0ed0ULL] = 38;
isch_map["14b3a28b47"] = 39; isch_map[0x14b3a28b47ULL] = 39;
isch_map["1d467a9e9d"] = 40; isch_map[0x1d467a9e9dULL] = 40;
isch_map["1d72471b0a"] = 41; isch_map[0x1d72471b0aULL] = 41;
isch_map["1d1eb134d3"] = 42; isch_map[0x1d1eb134d3ULL] = 42;
isch_map["1d2a8cb144"] = 43; isch_map[0x1d2a8cb144ULL] = 43;
isch_map["1ddbd93fec"] = 44; isch_map[0x1ddbd93fecULL] = 44;
isch_map["1defe4ba7b"] = 45; isch_map[0x1defe4ba7bULL] = 45;
isch_map["1d831295a2"] = 46; isch_map[0x1d831295a2ULL] = 46;
isch_map["1db72f1035"] = 47; isch_map[0x1db72f1035ULL] = 47;
isch_map["164af0f210"] = 48; isch_map[0x164af0f210ULL] = 48;
isch_map["167ecd7787"] = 49; isch_map[0x167ecd7787ULL] = 49;
isch_map["16123b585e"] = 50; isch_map[0x16123b585eULL] = 50;
isch_map["162606ddc9"] = 51; isch_map[0x162606ddc9ULL] = 51;
isch_map["16d7535361"] = 52; isch_map[0x16d7535361ULL] = 52;
isch_map["16e36ed6f6"] = 53; isch_map[0x16e36ed6f6ULL] = 53;
isch_map["168f98f92f"] = 54; isch_map[0x168f98f92fULL] = 54;
isch_map["16bba57cb8"] = 55; isch_map[0x16bba57cb8ULL] = 55;
isch_map["1f4e7d6962"] = 56; isch_map[0x1f4e7d6962ULL] = 56;
isch_map["1f7a40ecf5"] = 57; isch_map[0x1f7a40ecf5ULL] = 57;
isch_map["1f16b6c32c"] = 58; isch_map[0x1f16b6c32cULL] = 58;
isch_map["1f228b46bb"] = 59; isch_map[0x1f228b46bbULL] = 59;
isch_map["1fd3dec813"] = 60; isch_map[0x1fd3dec813ULL] = 60;
isch_map["1fe7e34d84"] = 61; isch_map[0x1fe7e34d84ULL] = 61;
isch_map["1f8b15625d"] = 62; isch_map[0x1f8b15625dULL] = 62;
isch_map["1fbf28e7ca"] = 63; isch_map[0x1fbf28e7caULL] = 63;
isch_map["84d62c339"] = 64; isch_map[0x084d62c339ULL] = 64;
isch_map["8795f46ae"] = 65; isch_map[0x08795f46aeULL] = 65;
isch_map["815a96977"] = 66; isch_map[0x0815a96977ULL] = 66;
isch_map["82194ece0"] = 67; isch_map[0x082194ece0ULL] = 67;
isch_map["8d0c16248"] = 68; isch_map[0x08d0c16248ULL] = 68;
isch_map["8e4fce7df"] = 69; isch_map[0x08e4fce7dfULL] = 69;
isch_map["8880ac806"] = 70; isch_map[0x08880ac806ULL] = 70;
isch_map["8bc374d91"] = 71; isch_map[0x08bc374d91ULL] = 71;
isch_map["149ef584b"] = 72; isch_map[0x0149ef584bULL] = 72;
isch_map["17dd2dddc"] = 73; isch_map[0x017dd2dddcULL] = 73;
isch_map["11124f205"] = 74; isch_map[0x011124f205ULL] = 74;
isch_map["125197792"] = 75; isch_map[0x0125197792ULL] = 75;
isch_map["1d44cf93a"] = 76; isch_map[0x01d44cf93aULL] = 76;
isch_map["1e0717cad"] = 77; isch_map[0x01e0717cadULL] = 77;
isch_map["18c875374"] = 78; isch_map[0x018c875374ULL] = 78;
isch_map["1b8bad6e3"] = 79; isch_map[0x01b8bad6e3ULL] = 79;
isch_map["a456534c6"] = 80; isch_map[0x0a456534c6ULL] = 80;
isch_map["a7158b151"] = 81; isch_map[0x0a7158b151ULL] = 81;
isch_map["a1dae9e88"] = 82; isch_map[0x0a1dae9e88ULL] = 82;
isch_map["a29931b1f"] = 83; isch_map[0x0a29931b1fULL] = 83;
isch_map["ad8c695b7"] = 84; isch_map[0x0ad8c695b7ULL] = 84;
isch_map["aecfb1020"] = 85; isch_map[0x0aecfb1020ULL] = 85;
isch_map["a800d3ff9"] = 86; isch_map[0x0a800d3ff9ULL] = 86;
isch_map["ab430ba6e"] = 87; isch_map[0x0ab430ba6eULL] = 87;
isch_map["341e8afb4"] = 88; isch_map[0x0341e8afb4ULL] = 88;
isch_map["375d52a23"] = 89; isch_map[0x0375d52a23ULL] = 89;
isch_map["3192305fa"] = 90; isch_map[0x03192305faULL] = 90;
isch_map["32d1e806d"] = 91; isch_map[0x032d1e806dULL] = 91;
isch_map["3dc4b0ec5"] = 92; isch_map[0x03dc4b0ec5ULL] = 92;
isch_map["3e8768b52"] = 93; isch_map[0x03e8768b52ULL] = 93;
isch_map["38480a48b"] = 94; isch_map[0x038480a48bULL] = 94;
isch_map["3b0bd211c"] = 95; isch_map[0x03b0bd211cULL] = 95;
isch_map["44dbc12b7"] = 96; isch_map[0x044dbc12b7ULL] = 96;
isch_map["479819720"] = 97; isch_map[0x0479819720ULL] = 97;
isch_map["41577b8f9"] = 98; isch_map[0x041577b8f9ULL] = 98;
isch_map["4214a3d6e"] = 99; isch_map[0x04214a3d6eULL] = 99;
isch_map["4d01fb3c6"] = 100; isch_map[0x04d01fb3c6ULL] = 100;
isch_map["4e4223651"] = 101; isch_map[0x04e4223651ULL] = 101;
isch_map["488d41988"] = 102; isch_map[0x0488d41988ULL] = 102;
isch_map["4bce99c1f"] = 103; isch_map[0x04bce99c1fULL] = 103;
isch_map["d493189c5"] = 104; isch_map[0x0d493189c5ULL] = 104;
isch_map["d7d0c0c52"] = 105; isch_map[0x0d7d0c0c52ULL] = 105;
isch_map["d11fa238b"] = 106; isch_map[0x0d11fa238bULL] = 106;
isch_map["d25c7a61c"] = 107; isch_map[0x0d25c7a61cULL] = 107;
isch_map["dd49228b4"] = 108; isch_map[0x0dd49228b4ULL] = 108;
isch_map["de0afad23"] = 109; isch_map[0x0de0afad23ULL] = 109;
isch_map["d8c5982fa"] = 110; isch_map[0x0d8c5982faULL] = 110;
isch_map["db864076d"] = 111; isch_map[0x0db864076dULL] = 111;
isch_map["645bbe548"] = 112; isch_map[0x0645bbe548ULL] = 112;
isch_map["6718660df"] = 113; isch_map[0x06718660dfULL] = 113;
isch_map["61d704f06"] = 114; isch_map[0x061d704f06ULL] = 114;
isch_map["6294dca91"] = 115; isch_map[0x06294dca91ULL] = 115;
isch_map["6d8184439"] = 116; isch_map[0x06d8184439ULL] = 116;
isch_map["6ec25c1ae"] = 117; isch_map[0x06ec25c1aeULL] = 117;
isch_map["680d3ee77"] = 118; isch_map[0x0680d3ee77ULL] = 118;
isch_map["6b4ee6be0"] = 119; isch_map[0x06b4ee6be0ULL] = 119;
isch_map["f41367e3a"] = 120; isch_map[0x0f41367e3aULL] = 120;
isch_map["f750bfbad"] = 121; isch_map[0x0f750bfbadULL] = 121;
isch_map["f19fdd474"] = 122; isch_map[0x0f19fdd474ULL] = 122;
isch_map["f2dc051e3"] = 123; isch_map[0x0f2dc051e3ULL] = 123;
isch_map["fdc95df4b"] = 124; isch_map[0x0fdc95df4bULL] = 124;
isch_map["fe8a85adc"] = 125; isch_map[0x0fe8a85adcULL] = 125;
isch_map["f845e7505"] = 126; isch_map[0x0f845e7505ULL] = 126;
isch_map["fb063f092"] = 127; 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 map_isch(); //initialize the lookup map
char s[64]; int decoded = -2;
int decoded = -2; //initialize lookup to an invalid number
sprintf(s, "%llx", isch); // Must contain bit errors if no exact match, so
decoded = isch_map[s]; // look for codeword with smallest hamming distance
return(decoded); 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
View 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

View File

@@ -36,13 +36,13 @@
/* Global variables ---------------------------------------------------------*/ /* 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 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]) #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_TABLE1[8] = {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_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_D2 = 8U;
static const unsigned int CNXDNConvolution_NUM_OF_STATES = 16U; static const unsigned int CNXDNConvolution_NUM_OF_STATES = 16U;

View File

@@ -25,7 +25,9 @@
#include "dsd.h" #include "dsd.h"
#include "nxdn_const.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, 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, 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, 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 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 //decoding functions here
void nxdn_descramble(uint8_t dibits[], int len) 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]) void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
{ {
uint8_t deperm[200]; //144 uint8_t deperm[144]; //144
uint8_t depunc[200]; //192 uint8_t depunc[192]; //192
uint8_t trellis_buf[400]; //96 uint8_t trellis_buf[96]; //96
uint16_t crc = 0; //crc calculated by function uint16_t crc = 0; //crc calculated by function
uint16_t check = 0; //crc from payload for comparison uint16_t check = 0; //crc from payload for comparison
int out; 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 //switch to the convolutional decoder
uint8_t temp[210]; uint8_t temp[200];
uint8_t s0; uint8_t s0;
uint8_t s1; uint8_t s1;
uint8_t m_data[20]; //13 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)); memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 192; i++) for (int i = 0; i < 192; i++)
{
temp[i] = depunc[i] << 1; temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+192] = 0;
}
CNXDNConvolution_start(); CNXDNConvolution_start();
for (int i = 0U; i < 100U; i++) for (int i = 0; i < 96; i++)
{ {
s0 = temp[(2*i)]; s0 = temp[(2*i)];
s1 = temp[(2*i)+1]; 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_decode(s0, s1);
} }
CNXDNConvolution_chainback(m_data, 96U); CNXDNConvolution_chainback(m_data, 92);
for(int i = 0; i < 12; i++) for(int i = 0; i < 12; i++)
{ {
@@ -122,7 +112,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
} }
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf); 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) if (opts->payload == 1)
{ {
@@ -146,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]) void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
{ {
//see about initializing these variables //see about initializing these variables
uint8_t deperm[200]; //60 uint8_t deperm[60]; //60
uint8_t depunc[200]; //72 uint8_t depunc[72]; //72
uint8_t trellis_buf[400]; //32 uint8_t trellis_buf[32]; //32
memset (deperm, 0, sizeof(deperm)); memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc)); memset (depunc, 0, sizeof(depunc));
@@ -179,27 +169,20 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
} }
//switch to the convolutional decoder //switch to the convolutional decoder
uint8_t temp[90]; uint8_t temp[80];
uint8_t s0; uint8_t s0;
uint8_t s1; uint8_t s1;
uint8_t m_data[10]; //5 uint8_t m_data[5]; //5
memset (temp, 0, sizeof (temp)); memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data)); memset (m_data, 0, sizeof (m_data));
memset (trellis_buf, 0, sizeof(trellis_buf)); memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 72; i++) for (int i = 0; i < 72; i++)
{
temp[i] = depunc[i] << 1; temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+72] = 0;
}
CNXDNConvolution_start(); CNXDNConvolution_start();
for (int i = 0U; i < 36U; i++) //40 for (int i = 0; i < 36; i++)
{ {
s0 = temp[(2*i)]; s0 = temp[(2*i)];
s1 = temp[(2*i)+1]; s1 = temp[(2*i)+1];
@@ -208,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 //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++) for(int i = 0; i < 4; i++)
{ {
@@ -235,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); if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " "); else fprintf (stderr, " ");
uint8_t nsf_sacch[400]; uint8_t nsf_sacch[26];
memset (nsf_sacch, 0, sizeof(nsf_sacch)); memset (nsf_sacch, 0, sizeof(nsf_sacch));
for (int i = 0; i < 26; i++) for (int i = 0; i < 26; i++)
{ {
@@ -353,9 +336,9 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type) 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 deperm[348]; //348
uint8_t depunc[500]; //406 uint8_t depunc[406]; //406
uint8_t trellis_buf[400]; //199 uint8_t trellis_buf[208]; //199
int id = 0; int id = 0;
uint16_t crc = 0; uint16_t crc = 0;
uint16_t check = 0; uint16_t check = 0;
@@ -384,26 +367,19 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
} }
//switch to the convolutional decoder //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 s0;
uint8_t s1; uint8_t s1;
uint8_t m_data[52]; //26 uint8_t m_data[26]; //26
memset (trellis_buf, 0, sizeof(trellis_buf)); memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp)); memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data)); memset (m_data, 0, sizeof (m_data));
for (int i = 0; i < 406; i++) for (int i = 0; i < 406; i++)
{
temp[i] = depunc[i] << 1; temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+203] = 0;
}
CNXDNConvolution_start(); CNXDNConvolution_start();
for (int i = 0U; i < 207U; i++) for (int i = 0; i < 203; i++)
{ {
s0 = temp[(2*i)]; s0 = temp[(2*i)];
s1 = temp[(2*i)+1]; s1 = temp[(2*i)+1];
@@ -412,7 +388,7 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
} }
//numerals seem okay now //numerals seem okay now
CNXDNConvolution_chainback(m_data, 203U); CNXDNConvolution_chainback(m_data, 199);
for(int i = 0; i < 26; i++) for(int i = 0; i < 26; i++)
{ {
@@ -443,7 +419,7 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
//just going to leave this all here in case its needed, like in cac, //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 //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]; 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 == 1) NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
if (type == 0) ; //need handling for user data (text messages and AVL) if (type == 0) ; //need handling for user data (text messages and AVL)
} }
else if (opts->aggressive_framesync == 0) // else if (opts->aggressive_framesync == 0)
{ // {
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer); // 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 (type == 0) {} //need handling for user data (text messages and AVL)
} // }
if (opts->payload == 1) if (opts->payload == 1)
{ {
@@ -498,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]) void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
{ {
uint8_t deperm[500]; //300 uint8_t deperm[300]; //300
uint8_t depunc[500]; //350 uint8_t depunc[350]; //350
uint8_t trellis_buf[400]; //171 uint8_t trellis_buf[176]; //176
int id = 0; int id = 0;
int ran = 0; int ran = 0;
uint16_t crc = 0; uint16_t crc = 0;
@@ -529,21 +505,19 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
} }
//switch to the convolutional decoder //switch to the convolutional decoder
uint8_t temp[360]; uint8_t temp[179];
uint8_t s0; uint8_t s0;
uint8_t s1; uint8_t s1;
uint8_t m_data[52]; //26 uint8_t m_data[22]; //26
memset (trellis_buf, 0, sizeof(trellis_buf)); memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp)); memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data)); memset (m_data, 0, sizeof (m_data));
for (int i = 0; i < 350; i++) for (int i = 0; i < 350; i++)
{
temp[i] = depunc[i] << 1; temp[i] = depunc[i] << 1;
}
CNXDNConvolution_start(); CNXDNConvolution_start();
for (int i = 0U; i < 179U; i++) for (int i = 0; i < 175; i++) //179
{ {
s0 = temp[(2*i)]; s0 = temp[(2*i)];
s1 = temp[(2*i)+1]; s1 = temp[(2*i)+1];
@@ -551,7 +525,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
CNXDNConvolution_decode(s0, s1); CNXDNConvolution_decode(s0, s1);
} }
CNXDNConvolution_chainback(m_data, 175U); CNXDNConvolution_chainback(m_data, 171); //175
for(int i = 0; i < 22; i++) for(int i = 0; i < 22; i++)
{ {
@@ -567,11 +541,11 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
crc = crc16cac(trellis_buf, 171); 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)); memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field //shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field and ending crc
for (int i = 0; i < 160; i++) for (int i = 0; i < 147; i++)
{ {
cac_message_buffer[i] = trellis_buf[i+8]; cac_message_buffer[i] = trellis_buf[i+8];
} }
@@ -597,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); 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) if (opts->payload == 1)
{ {
@@ -621,9 +595,9 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
fprintf (stderr, " SCCH"); fprintf (stderr, " SCCH");
//see about initializing these variables //see about initializing these variables
uint8_t deperm[200]; //60 uint8_t deperm[60]; //60
uint8_t depunc[200]; //72 uint8_t depunc[72]; //72
uint8_t trellis_buf[400]; //32 uint8_t trellis_buf[32]; //32
memset (deperm, 0, sizeof(deperm)); memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc)); memset (depunc, 0, sizeof(depunc));
@@ -653,27 +627,20 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
} }
//switch to the convolutional decoder //switch to the convolutional decoder
uint8_t temp[90]; uint8_t temp[72];
uint8_t s0; uint8_t s0;
uint8_t s1; uint8_t s1;
uint8_t m_data[10]; //5 uint8_t m_data[5]; //5
memset (temp, 0, sizeof (temp)); memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data)); memset (m_data, 0, sizeof (m_data));
memset (trellis_buf, 0, sizeof(trellis_buf)); memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 72; i++) for (int i = 0; i < 72; i++)
{
temp[i] = depunc[i] << 1; temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+72] = 0;
}
CNXDNConvolution_start(); CNXDNConvolution_start();
for (int i = 0U; i < 36U; i++) for (int i = 0; i < 36; i++)
{ {
s0 = temp[(2*i)]; s0 = temp[(2*i)];
s1 = temp[(2*i)+1]; s1 = temp[(2*i)+1];
@@ -681,7 +648,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
CNXDNConvolution_decode(s0, s1); CNXDNConvolution_decode(s0, s1);
} }
CNXDNConvolution_chainback(m_data, 32U); CNXDNConvolution_chainback(m_data, 32);
for(int i = 0; i < 4; i++) for(int i = 0; i < 4; i++)
{ {
@@ -734,7 +701,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
//like everything else does //like everything else does
if (crc == check) NXDN_decode_scch (opts, state, trellis_buf, direction); 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); fprintf (stderr, "%s", KNRM);
@@ -760,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) 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 deperm[144]; //144
uint8_t depunc[300]; //192 uint8_t depunc[192]; //192
uint8_t trellis_buf[600]; //96 uint8_t trellis_buf[96]; //96
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached 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 uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
uint16_t crc[2]; //crc calculated by function uint16_t crc[2]; //crc calculated by function
@@ -770,10 +737,10 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
int out; int out;
//switch to the convolutional decoder //switch to the convolutional decoder
uint8_t temp[500]; uint8_t temp[192];
uint8_t s0; uint8_t s0;
uint8_t s1; uint8_t s1;
uint8_t m_data[40]; //13 uint8_t m_data[12]; //13
memset (temp, 0, sizeof(temp)); memset (temp, 0, sizeof(temp));
memset (m_data, 0, sizeof(m_data)); memset (m_data, 0, sizeof(m_data));
memset (trellis_buf, 0, sizeof(trellis_buf)); memset (trellis_buf, 0, sizeof(trellis_buf));
@@ -797,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++) for (int i = 0; i < 192; i++)
{
temp[i] = depunc[i] << 1; temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+192] = 0;
}
CNXDNConvolution_start(); CNXDNConvolution_start();
for (int i = 0U; i < 100U; i++) for (int i = 0; i < 96; i++)
{ {
s0 = temp[(2*i)]; s0 = temp[(2*i)];
s1 = temp[(2*i)+1]; s1 = temp[(2*i)+1];
@@ -815,7 +775,7 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
CNXDNConvolution_decode(s0, s1); CNXDNConvolution_decode(s0, s1);
} }
CNXDNConvolution_chainback(m_data, 96U); CNXDNConvolution_chainback(m_data, 92);
for(int i = 0; i < 12; i++) for(int i = 0; i < 12; i++)
{ {
@@ -852,11 +812,11 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf); if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
if (type == 0) ; //need handling for user data (text messages and AVL) if (type == 0) ; //need handling for user data (text messages and AVL)
} }
else if (opts->aggressive_framesync == 0) // else if (opts->aggressive_framesync == 0)
{ // {
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf); // 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 (type == 0) {} //need handling for user data (text messages and AVL)
} // }
if (opts->payload == 1) if (opts->payload == 1)
{ {

View File

@@ -14,8 +14,8 @@
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state) 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[10]; uint8_t sacch_bytes[9];
uint32_t i; uint32_t i;
uint8_t CrcCorrect = 1; uint8_t CrcCorrect = 1;
@@ -38,7 +38,7 @@ void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
/* Decodes the element content */ /* Decodes the element content */
// currently only going to run this if all four CRCs are good // currently only going to run this if all four CRCs are good
if (CrcCorrect == 1) NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH); 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 //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_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
@@ -144,6 +144,10 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
NXDN_decode_VCALL(opts, state, ElementsContent); NXDN_decode_VCALL(opts, state, ElementsContent);
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment)); 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 //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) if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
{ {
@@ -174,7 +178,8 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
state->last_cc_sync_time = time(NULL); //allow tuners a second to catch up, particularly rtl input state->last_cc_sync_time = time(NULL); //allow tuners a second to catch up, particularly rtl input
} }
#endif
break; break;
//Idle //Idle

View File

@@ -469,7 +469,7 @@ processHDU(dsd_opts* opts, dsd_state* state)
{ {
fprintf (stderr, "%s", KYEL); fprintf (stderr, "%s", KYEL);
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3); 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_algid = algidhex;
state->payload_keyid = kidhex; state->payload_keyid = kidhex;
if (state->R != 0 && state->payload_algid == 0xAA) if (state->R != 0 && state->payload_algid == 0xAA)
@@ -477,6 +477,11 @@ processHDU(dsd_opts* opts, dsd_state* state)
fprintf (stderr, " Key: %010llX", state->R); fprintf (stderr, " Key: %010llX", state->R);
opts->unmute_encrypted_p25 = 1; 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); fprintf (stderr, "%s", KNRM);
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3 //only use 64 MSB, trailing 8 bits aren't used, so no mihex3
state->payload_miP = (mihex1 << 32) | (mihex2); state->payload_miP = (mihex1 << 32) | (mihex2);

View File

@@ -371,7 +371,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
if (irrecoverable_errors == 0) if (irrecoverable_errors == 0)
{ {
fprintf (stderr, "%s", KYEL); fprintf (stderr, "%s", KYEL);
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3); 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_algid = algidhex;
state->payload_keyid = kidhex; state->payload_keyid = kidhex;
if (state->R != 0 && state->payload_algid == 0xAA) if (state->R != 0 && state->payload_algid == 0xAA)
@@ -379,6 +379,11 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
fprintf (stderr, " Key: %010llX", state->R); fprintf (stderr, " Key: %010llX", state->R);
opts->unmute_encrypted_p25 = 1; 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); fprintf (stderr, "%s", KNRM);
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3 //only use 64 MSB, trailing 8 bits aren't used, so no mihex3
state->payload_miP = (mihex1 << 32) | (mihex2); state->payload_miP = (mihex1 << 32) | (mihex2);

View File

@@ -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 //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[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%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;
} }

View File

@@ -446,4 +446,9 @@ processTDULC (dsd_opts* opts, dsd_state* state)
sprintf (state->call_string[0], "%s", " "); //21 spaces sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%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;
} }

View File

@@ -75,7 +75,7 @@ int dibit = 0;
int vc_counter = 0; int vc_counter = 0;
int framing_counter = 0; int framing_counter = 0;
unsigned long long int isch = 0; uint64_t isch = 0;
int isch_decoded = -1; int isch_decoded = -1;
int p2_duid[8] = {0}; int p2_duid[8] = {0};
int16_t duid_decoded = 0; int16_t duid_decoded = 0;

View File

@@ -463,11 +463,14 @@ void dc_block_filter(struct demod_state *fm)
} }
fm->dc_avg = avg; fm->dc_avg = avg;
} }
//TODO: Fix This so we don't get random negative values in Cygwin (or 32-bit builds?)
int rms(int16_t *samples, int len, int step) //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 */ /* largely lifted from rtl_power */
{ {
int i; int i;
long int rms;
long p, t, s; long p, t, s;
double dc, err; double dc, err;
@@ -481,7 +484,10 @@ int rms(int16_t *samples, int len, int step)
dc = (double)(t*step) / (double)len; dc = (double)(t*step) / (double)len;
err = t * 2 * dc - dc * dc * 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) void full_demod(struct demod_state *d)
@@ -1108,13 +1114,14 @@ void rtl_dev_tune(dsd_opts * opts, long int frequency)
} }
//return RMS value (root means square) power level -- used as soft squelch inside of framesync //return RMS value (root means square) power level -- used as soft squelch inside of framesync
int rtl_return_rms() long int rtl_return_rms()
{ {
int sr = 0; long int sr = 0;
#ifdef __arm__
sr = 100;
#else
sr = rms(demod.lowpassed, demod.lp_len, 1); sr = rms(demod.lowpassed, demod.lp_len, 1);
// 'Fix' potential negative value overflow from the rms function -- Observed in Windows builds #endif
sr = abs(sr);
if (sr > 9999) sr = 9999;
return (sr); return (sr);
} }

View File

@@ -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);
}

1299
src/ysf.c

File diff suppressed because it is too large Load Diff