mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f1cf0a279 | ||
|
|
5d045b89e4 | ||
|
|
a2c4679632 | ||
|
|
986ed27d7d | ||
|
|
bae6a1545e | ||
|
|
5240f00441 | ||
|
|
f7511e0976 | ||
|
|
bc27344b04 | ||
|
|
db97eb82a1 | ||
|
|
3f1b8ff736 | ||
|
|
54b9017146 | ||
|
|
8ccaf2d261 | ||
|
|
209770175d | ||
|
|
602079e681 | ||
|
|
82267b9ec8 | ||
|
|
87bf997b6e | ||
|
|
0a43d3202d | ||
|
|
ee04cef6f2 | ||
|
|
b6fdfe48c1 | ||
|
|
7a4bd2833f | ||
|
|
432ad448ba | ||
|
|
61be710bb0 | ||
|
|
3be8aacf77 | ||
|
|
4feb21cf0a | ||
|
|
7d8162ab99 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,4 +7,3 @@ build
|
|||||||
examples
|
examples
|
||||||
*.bin
|
*.bin
|
||||||
*.ans
|
*.ans
|
||||||
*.patch
|
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ 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
|
||||||
@@ -39,13 +45,19 @@ if (LZ)
|
|||||||
add_definitions(-DLIMAZULUTWEAKS)
|
add_definitions(-DLIMAZULUTWEAKS)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
#use cmake option -DSID=ON to enable P25p1 Soft ID decoding -- Experimental
|
#use cmake option -DTONES to change default location of the tones.wav files (lwvmobile precompiled 'Aero' releases only)
|
||||||
option(SID
|
option(TN
|
||||||
"Build with P25p1 LSD/Soft ID Enabled" OFF)
|
"Build with tone wav files in the dsd-fme folder and not in /usr/share/" OFF)
|
||||||
if (SID)
|
if (TN)
|
||||||
add_definitions(-DSOFTID)
|
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)
|
||||||
@@ -89,9 +101,6 @@ include_directories("${PROJECT_SOURCE_DIR}/include")
|
|||||||
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
||||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||||
|
|
||||||
target_compile_options(dsd-fme PRIVATE -Wunused-but-set-variable -Wunused-variable -Wunused-parameter
|
|
||||||
-Wempty-body -Wunused-label $<$<COMPILE_LANGUAGE:C>:-Wpointer-sign>)
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -2,17 +2,17 @@
|
|||||||
# 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, YSF, M17, 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. Thanks to volo-zyko for cleaning up a lot of code. 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.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Information
|
## Information
|
||||||
|
|
||||||
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/audio_work/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/trunking.sh "trunking examples").
|
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/main/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/main/examples/trunking.sh "trunking examples").
|
||||||
|
|
||||||
## License
|
## License
|
||||||
Copyright (C) 2010 DSD Author
|
Copyright (C) 2010 DSD Author
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#! /bin/bash
|
|
||||||
#
|
|
||||||
cdir=$(pwd)
|
|
||||||
clear
|
|
||||||
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer For Arch Linux\n
|
|
||||||
This will install the required packages, clone, build, and install DSD-FME only.
|
|
||||||
This has been tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal.\n
|
|
||||||
MBELib is considered a requirement on this build.
|
|
||||||
You must view the Patent Notice prior to continuing.
|
|
||||||
The Patent Notice can be found at the site below.
|
|
||||||
https://github.com/lwvmobile/mbelib#readme
|
|
||||||
Please confirm that you have viewed the patent notice by entering y below.\n\n"
|
|
||||||
read -p "Have you viewed the patent notice? y/N " ANSWER
|
|
||||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
|
||||||
if [ "$ANSWER" = "y" ]; then
|
|
||||||
|
|
||||||
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
|
|
||||||
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
|
|
||||||
|
|
||||||
printf "Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal\n"
|
|
||||||
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
sudo rm -R itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
|
|
||||||
git clone https://github.com/lwvmobile/mbelib
|
|
||||||
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.so /usr/lib/libmbe.so
|
|
||||||
cd $cdir
|
|
||||||
|
|
||||||
git clone https://github.com/lwvmobile/dsd-fme
|
|
||||||
### For branch audio_work - git clone --branch audio_work https://github.com/lwvmobile/dsd-fme
|
|
||||||
cd dsd-fme
|
|
||||||
#git checkout audio_work
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j $(nproc)
|
|
||||||
sudo make install
|
|
||||||
sudo ldconfig
|
|
||||||
|
|
||||||
printf "Any issues, Please report to either:\nhttps://github.com/lwvmobile/dsd-fme/issues or\nhttps://forums.radioreference.com/threads/dsd-fme.438137/\n\n"
|
|
||||||
|
|
||||||
else
|
|
||||||
printf "Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.\n\n"
|
|
||||||
fi
|
|
||||||
@@ -1,17 +1,23 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
clear
|
clear
|
||||||
printf "\nDigital Speech Decoder: Florida Man Edition - Auto Installer\n
|
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||||
This will clone, build, and install DSD-FME only.
|
echo This will clone, build, and install DSD-FME only.
|
||||||
If DSD-FME has never been installed on this machine,
|
echo If you need dependencies installed, please run download-and-install.sh instead.
|
||||||
then you will need to install the dependencies first!
|
echo
|
||||||
Please run download-and-install.sh instead.\n\n"
|
|
||||||
read -p "Press Enter to continue..." x
|
read -p "Press enter to continue"
|
||||||
|
|
||||||
git clone https://github.com/lwvmobile/dsd-fme
|
git clone https://github.com/lwvmobile/dsd-fme
|
||||||
cd dsd-fme
|
cd dsd-fme
|
||||||
#git checkout audio_work
|
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
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
make -j $(nproc)
|
make -j `nproc`
|
||||||
sudo make install
|
sudo make install
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
|
|||||||
@@ -1,44 +1,67 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
#
|
|
||||||
cdir=$(pwd)
|
|
||||||
clear
|
clear
|
||||||
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer\n
|
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||||
MBELib is considered a requirement on this build.
|
echo MBELib is considered a requirement on this build.
|
||||||
You must view the Patent Notice prior to continuing.
|
echo You must view this notice prior to continuing.
|
||||||
The Patent Notice can be found at the site below.
|
echo The Patent Notice can be found at the site below.
|
||||||
https://github.com/lwvmobile/mbelib#readme
|
echo https://github.com/lwvmobile/mbelib#readme
|
||||||
Please confirm that you have viewed the patent notice by entering y below:\n\n"
|
echo Please confirm that you have viewed the patent notice by entering y below.
|
||||||
read -p "Have you viewed the patent notice? y/N " ANSWER
|
echo
|
||||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
echo y/N
|
||||||
if [ "$ANSWER" = "y" ]; then
|
read ANSWER
|
||||||
sudo apt update
|
Y='y'
|
||||||
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
|
if [[ $Y == $ANSWER ]]; then
|
||||||
chkitpp=$(sudo apt list libitpp-dev 2>&1|grep -ci "installed")
|
|
||||||
if [ "$chkitpp" -lt "1" ];then
|
sudo apt update
|
||||||
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
|
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
|
||||||
read -p "Press Enter to exit..." x
|
|
||||||
exit 1
|
echo ITPP Manual Build and Install has been temporarily removed from this script due to issues with older versions of Ubuntu.
|
||||||
fi
|
echo Please check to see that libitpp-dev has successfully been downloaded and installed from the repo.
|
||||||
git clone https://github.com/lwvmobile/mbelib
|
read -p "Press enter to continue"
|
||||||
cd mbelib
|
|
||||||
git checkout ambe_tones
|
#wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
||||||
mkdir build
|
#tar xjf itpp*
|
||||||
cd build
|
#if you can't cd into this folder, double check folder name first
|
||||||
cmake ..
|
#cd itpp-4.3.1
|
||||||
make -j $(nproc)
|
#mkdir build
|
||||||
sudo make install
|
#cd build
|
||||||
sudo ldconfig
|
#cmake ..
|
||||||
cd $cdir
|
#make -j `nproc`
|
||||||
git clone https://github.com/lwvmobile/dsd-fme
|
#sudo make install
|
||||||
cd dsd-fme
|
#sudo ldconfig
|
||||||
#git checkout audio_work
|
#cd ..
|
||||||
mkdir build
|
#cd ..
|
||||||
cd build
|
|
||||||
cmake ..
|
git clone https://github.com/lwvmobile/mbelib
|
||||||
make -j $(nproc)
|
cd mbelib
|
||||||
sudo make install
|
mkdir build
|
||||||
sudo ldconfig
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j `nproc`
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
cd ..
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
git clone https://github.com/lwvmobile/dsd-fme
|
||||||
|
cd dsd-fme
|
||||||
|
sudo cp tone8.wav /usr/share/
|
||||||
|
sudo cp tone24.wav /usr/share/
|
||||||
|
sudo cp tone48.wav /usr/share/
|
||||||
|
sudo chmod 777 /usr/share/tone8.wav
|
||||||
|
sudo chmod 777 /usr/share/tone24.wav
|
||||||
|
sudo chmod 777 /usr/share/tone48.wav
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j `nproc`
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
|
||||||
else
|
else
|
||||||
printf "\nSorry, you cannot build DSD-FME without acknowledging the Patent Notice.\nExiting...\n\n"
|
echo
|
||||||
exit 2
|
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
dsd-fme2.png
BIN
dsd-fme2.png
Binary file not shown.
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 125 KiB |
BIN
dsd-fme3.png
BIN
dsd-fme3.png
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 251 KiB |
@@ -8,19 +8,19 @@
|
|||||||
-fa Legacy Auto (not recommended)
|
-fa Legacy Auto (not recommended)
|
||||||
-fi NXDN48
|
-fi NXDN48
|
||||||
-fn NXDN96
|
-fn NXDN96
|
||||||
-fp EDACS/Provoice
|
-fp ProVoice
|
||||||
-fm dPMR, also may need to use -xd if inverted dPMR.
|
-fm dPMR, also may need to use -xd if inverted dPMR.
|
||||||
|
-fr DMR Mono, also may need to use -xr if inverted DMR.
|
||||||
-f1 P25P1
|
-f1 P25P1
|
||||||
-f2 P25P2 (may need to specify wacn/sys/nac manually if traffic channel)
|
-f2 P25P2 (may need to specify wacn/sys/nac manually)
|
||||||
-fx X2-TDMA
|
-fx X2-TDMA
|
||||||
-fy YSF
|
-fy YSF
|
||||||
-fz M17 Audio
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Conventional Frequency Scanner
|
## Conventional Frequency "Fast Scanner"
|
||||||
This feature is used to allow DSD-FME to use RIGCTL or RTL input and cycle through frequencies to attain a frame sync.
|
This feature is used to allow DSD-FME to use RIGCTL or RTL input and cycle through frequencies as fast as possible to attain a frame sync.
|
||||||
|
|
||||||
This works almost identically to how the trunkng methods work, but instead of locking onto a control channel and tuning based on its decoding, it tunes through all loaded frequencies in a CSV file and stops when it finds a frame sync. This method is meant for loading a bunch of conventional non-trunking frequencies that signal only when voice or short data bursts are present (DMR T2, Conventional P25 P1, Conventional NXDN, etc) and decode them until the frame sync stops and then resume its scan. This method uses SDR++ RIGCTL, or RTL internal handling to go through signal. -Y is the scan switch. Note: This method will NOT perform at a level similar to a real hardware scanner, SDR tuning is not nearly as fast or reliable at locking onto signal.
|
This works almost identically to how the trunkng methods work, but instead of locking onto a control channel and tuning based on its decoding, it rapidly tunes through all loaded frequencies in a CSV file and stops when it finds a frame sync. This method is meant for loading a bunch of conventional non-trunking frequencies that signal only when voice or short data bursts are present (DMR T2, Conventional P25 P1, Conventional NXDN, etc) and decode them until the frame sync stops and then resume its scan. This method uses SDR++ RIGCTL, or RTL internal handling to go through signal. -Y is the fast scanner switch.
|
||||||
|
|
||||||
To scan through a mixture of DMR and P25 Conventional, use:
|
To scan through a mixture of DMR and P25 Conventional, use:
|
||||||
`dsd-fme -i tcp -C channel_map.csv -G group.csv -Y -U 4532 -N 2> log.ans`
|
`dsd-fme -i tcp -C channel_map.csv -G group.csv -Y -U 4532 -N 2> log.ans`
|
||||||
@@ -31,9 +31,9 @@ To scan through NXDN48 only conventional, use:
|
|||||||
To scan through NXDN96 only conventional, use:
|
To scan through NXDN96 only conventional, use:
|
||||||
`dsd-fme -fn -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
`dsd-fme -fn -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
||||||
|
|
||||||
The Channel Map setup will be identical to any of the channel maps found for trunking systems, channel numbers do not matter and can be arbitrarily organized, and frequencies can be duplicated to be 'scanned' more frequently in larger CSV files. Scan speed by default is 1 second, and is most stable at that speed. This can be adjusted by using the `-t 2` option, for example, to specify 2 seconds of hang time per frequency. ~~If activity occurs on a frequency, an additional 2 seconds of 'hangtime' will occur on that frequency for any follow up voice activity.~~ Using `-t 0` will forego the one second wait time, and this can work in some situations, but is not advised as it may skip during the middle of transmissions, or skip over them entirely without a framesync.
|
The Channel Map setup will be identical to any of the channel maps found for trunking systems, channel numbers do not matter and can be arbitrarily organized, and frequencies can be duplicated to be 'scanned' more frequently in larger CSV files. Scan speed by default is 1 second, and is most stable at that speed. This can be adjusted by using the `-t 2` option, for example, to specify 2 seconds of hang time per frequency. ~~If activity occurs on a frequency, an additional 2 seconds of 'hangtime' will occur on that frequency for any follow up voice activity.~~
|
||||||
|
|
||||||
Please Note: DMR Simplex may not behave well on scan, I have not been able to test it as such, but given the nature of the on-off timeslot signalling on DMR Simplex, missed frame syncs and skipping/resuming scan may occur.
|
Please Note: DMR Simplex may not behave well on fast scan, I have not been able to test it as such, but given the nature of the on-off timeslot signalling on DMR Simplex, missed frame syncs and skipping/resuming scan may occur.
|
||||||
|
|
||||||
## Trunking Examples
|
## Trunking Examples
|
||||||
Please see trunking.sh for sample start up scripts or scroll down to the bottom for more explanation.
|
Please see trunking.sh for sample start up scripts or scroll down to the bottom for more explanation.
|
||||||
@@ -100,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, Analog Voice Monitoring and Per Call is Experimental)
|
--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)
|
||||||
|
|
||||||
`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`
|
||||||
|
|
||||||
@@ -134,16 +134,14 @@ Trunking Note1: All samples above can also be run with the RTL input method and
|
|||||||
|
|
||||||
Trunking Note2: QPSK Phase 1 and Phase 2 Systems may be subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
|
Trunking Note2: QPSK Phase 1 and Phase 2 Systems may be subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
|
||||||
|
|
||||||
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but setting a fake channel number (i.e. 999) first with the CC frequency will result in finding the CC faster on startup if desired. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus style LSN-esque numbering into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the lpcn (12-bit logical physical channel number - decimal format) values from the log, and not the LPCN+TS (13-bit DSDPlus LSN) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
|
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but setting a fake channel number (i.e. 999) first with the CC frequency will result in finding the CC faster on startup if desired. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus channel numbering (as best as I can figure it, but they seem consistent) into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the Cd (channel decimal) values from the log, and not the C+ (dsdplus) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
|
||||||
|
|
||||||
```
|
```
|
||||||
00:43:00 Sync: +DMR [slot1] slot2 | Color Code=00 | CSBK
|
|
||||||
Talkgroup Voice Channel Grant (TV_GRANT) - Logical
|
Talkgroup Voice Channel Grant (TV_GRANT) - Logical
|
||||||
LPCN: 0075; TS: 2; LPCN+TS: 0152; Target: 16518173 - Source: 16533625
|
Ch [036] Cd [0054] C+ [0110] - TS [1] - Target [01900500] - Source [01900505]
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Use channel 75 in your import file, which would correspond to dsdplus channels 151 and 152 (151 = TS1 / 152 = TS2).
|
Use channel 54 in your import file, which would correspond to dsdplus channels 109 and 110 (109 = TS0 / 110 = TS1).
|
||||||
|
|
||||||
For Connect Plus, enumerate your list from 1 to the last channel and add the frequency. For Capacity Plus, LSN 1 and 2 will share the same frequency, 3 and 4 will share, 5 and 6 will share, and 7-8 will share, as Capacity Plus counts each 'channel' as two seperate channels (LSN), one for each time slot. Capacity Plus Quirk: DSD-FME makes its best effort to follow the rest channel in the event that the sync is lost for longer than the hangtime, but occassionally, DSD-FME may lose the rest channel and will have to hunt through all frequencies to find it again.
|
For Connect Plus, enumerate your list from 1 to the last channel and add the frequency. For Capacity Plus, LSN 1 and 2 will share the same frequency, 3 and 4 will share, 5 and 6 will share, and 7-8 will share, as Capacity Plus counts each 'channel' as two seperate channels (LSN), one for each time slot. Capacity Plus Quirk: DSD-FME makes its best effort to follow the rest channel in the event that the sync is lost for longer than the hangtime, but occassionally, DSD-FME may lose the rest channel and will have to hunt through all frequencies to find it again.
|
||||||
|
|
||||||
@@ -181,8 +179,9 @@ P - start per call decoded wav files (Capital P)
|
|||||||
p - stop per call decoded wav files (Lower p)
|
p - stop per call decoded wav files (Lower p)
|
||||||
t - toggle trunking (needs either rtl input, or rigctl connection)
|
t - toggle trunking (needs either rtl input, or rigctl connection)
|
||||||
y - toggle scanner (needs either rtl input, or rigctl connection)
|
y - toggle scanner (needs either rtl input, or rigctl connection)
|
||||||
1 - Toggle Voice Synthesis in TDMA Slot 1 or FDMA Conventional Voice
|
1 - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
||||||
2 - Toggle Voice Synthesis in TDMA Slot 2
|
2 - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
||||||
|
0 - Toggle Audio Smoothing - May produce crackling if enabled on RTL/TCP or wav/bin files
|
||||||
w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode
|
w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode
|
||||||
g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN)
|
g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN)
|
||||||
u - Toggle Trunking Tuning to Private Calls (DMR T3, Cap+, P25)
|
u - Toggle Trunking Tuning to Private Calls (DMR T3, Cap+, P25)
|
||||||
@@ -192,81 +191,4 @@ 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)
|
||||||
|
```
|
||||||
! - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
|
||||||
@ - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
|
||||||
|
|
||||||
k - Hold TG in Slot 1 or Conventional, or clear current hold (Testing/WIP: DMR T3 Only)
|
|
||||||
l - Hold TG in Slot 2 on TDMA Systems, or clear current hold (Testing/WIP: DMR T3 Only)
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: Do not run this command for ffmpeg/icecast piped to the main dsd-fme command, make sure these are running in seperate terminals.
|
|
||||||
|
|
||||||
## Sending Audio to UDP Target/Port
|
|
||||||
|
|
||||||
Audio can be sent to a target address on your local area network with the UDP blaster using the `-o udp:targetaddress:port` option.
|
|
||||||
Note: Any analog audio monitoring will not function properly over UDP port (rate difference issues)
|
|
||||||
|
|
||||||
Example (Short 8k/2):
|
|
||||||
`dsd-fme -fs -o udp:192.168.7.8:23470`
|
|
||||||
|
|
||||||
Receiving End (Short 8k/2):
|
|
||||||
`socat stdio udp-listen:23470 | play --buffer 640 -q -b 16 -r 8000 -c2 -t s16 -`
|
|
||||||
|
|
||||||
Example (Short 8k/1):
|
|
||||||
`dsd-fme -f1 -o udp:192.168.7.8:23469`
|
|
||||||
|
|
||||||
Receiving End (Short 8k/1):
|
|
||||||
`socat stdio udp-listen:23469 | play --buffer 320 -q -b 16 -r 8000 -c1 -t s16 -`
|
|
||||||
|
|
||||||
Example (Float 8k/2):
|
|
||||||
`dsd-fme -ft -y -o udp:192.168.7.8:23468`
|
|
||||||
|
|
||||||
Receiving End (Float 8k/2):
|
|
||||||
`socat stdio udp-listen:23468 | play --buffer 1280 -q -b 16 -r 8000 -c2 -t f32 -`
|
|
||||||
|
|
||||||
Example (Float 8k/1):
|
|
||||||
`dsd-fme -fi -y -o udp:192.168.7.8:23467`
|
|
||||||
|
|
||||||
Receiving End (Float 8k/1):
|
|
||||||
`socat stdio udp-listen:23467 | play --buffer 640 -q -b 16 -r 8000 -c1 -t f32 -`
|
|
||||||
|
|
||||||
Note: --buffer option in play is calculated by (channels * samples * sizeof(samples)),
|
|
||||||
where samples is 160 for mono, 320 for stereo, and short samples are 2 and float samples are 4.
|
|
||||||
This is vital to prevent 'lag' or cut-off audio when the UDP audio doesn't fill the default buffer size.
|
|
||||||
|
|
||||||
Note2: Be sure to start the receiving end AFTER starting DSD-FME. If DSD-FME is restarted, make sure to restart the receiving end as well, as socat/UDP closes the UDP port listening when DSD-FME closes the UDP socket.
|
|
||||||
@@ -7,25 +7,15 @@ Using the included download-and-install.sh should make for a simple and painless
|
|||||||
If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run:
|
If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run:
|
||||||
|
|
||||||
```
|
```
|
||||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install.sh
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install.sh
|
||||||
chmod +x download-and-install.sh
|
chmod +x download-and-install.sh
|
||||||
./download-and-install.sh
|
./download-and-install.sh
|
||||||
```
|
```
|
||||||
|
f
|
||||||
### Arch Based Distros:
|
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:
|
||||||
|
|
||||||
```
|
```
|
||||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-Arch.sh
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install-nodeps.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/audio_work/download-and-install-nodeps.sh
|
|
||||||
chmod +x download-and-install-nodeps.sh
|
chmod +x download-and-install-nodeps.sh
|
||||||
./download-and-install-nodeps.sh
|
./download-and-install-nodeps.sh
|
||||||
```
|
```
|
||||||
@@ -41,22 +31,11 @@ sudo apt update
|
|||||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
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 (Recent Releases) -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo dnf update
|
|
||||||
sudo dnf install libsndfile-devel fftw-devel lapack-devel rtl-sdr-devel pulseaudio-libs-devel libusb-devel cmake git ncurses ncurses-devel gcc wget pavucontrol gcc-c++ codec2-devel
|
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.
|
||||||
@@ -82,11 +61,10 @@ cd ..
|
|||||||
cd ..
|
cd ..
|
||||||
```
|
```
|
||||||
|
|
||||||
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice")
|
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice") This version of MBELib is 1.3.2 and prints to STDERR, using the stock 1.3.0 MBElib may cause problems with print alignments if paired with this version of DSD-FME, or cause future compatibility issues.
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/lwvmobile/mbelib
|
git clone https://github.com/lwvmobile/mbelib
|
||||||
git checkout ambe_tones
|
|
||||||
cd mbelib
|
cd mbelib
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
@@ -99,26 +77,19 @@ cd ..
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
|
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
|
||||||
|
`sudo cp libmbe* /usr/lib`
|
||||||
```
|
|
||||||
cp libmbe* /usr/lib
|
|
||||||
cp cygmbe* /usr/lib
|
|
||||||
cp cygmbe* /bin
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo cp libmbe* /usr/lib
|
|
||||||
sudo cp cygmbe* /usr/lib
|
|
||||||
sudo cp cygmbe* /bin
|
|
||||||
```
|
|
||||||
|
|
||||||
Finish by running these steps to clone and build DSD-FME.
|
Finish by running these steps to clone and build DSD-FME.
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/lwvmobile/dsd-fme
|
git clone https://github.com/lwvmobile/dsd-fme
|
||||||
cd dsd-fme
|
cd dsd-fme
|
||||||
|
sudo cp tone8.wav /usr/share/
|
||||||
|
sudo cp tone24.wav /usr/share/
|
||||||
|
sudo cp tone48.wav /usr/share/
|
||||||
|
sudo chmod 777 /usr/share/tone8.wav
|
||||||
|
sudo chmod 777 /usr/share/tone24.wav
|
||||||
|
sudo chmod 777 /usr/share/tone48.wav
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
@@ -145,6 +116,12 @@ Then you can build and install using
|
|||||||
```
|
```
|
||||||
git clone https://github.com/lwvmobile/dsd-fme
|
git clone https://github.com/lwvmobile/dsd-fme
|
||||||
cd dsd-fme
|
cd dsd-fme
|
||||||
|
cp tone8.wav /usr/share/
|
||||||
|
cp tone24.wav /usr/share/
|
||||||
|
cp tone48.wav /usr/share/
|
||||||
|
chmod 777 /usr/share/tone8.wav
|
||||||
|
chmod 777 /usr/share/tone24.wav
|
||||||
|
chmod 777 /usr/share/tone48.wav
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
# -DAERO=ON is optional, but recommended if you want the older OSS support as well
|
# -DAERO=ON is optional, but recommended if you want the older OSS support as well
|
||||||
@@ -175,31 +152,13 @@ sudo make install
|
|||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
### Applying Patches -- Recommended For Advanced Users Only
|
If the call alert wav files aren't playing, then make sure to run the following in the dsd-fme folder to copy the wav files to the /usr/share/ folder and give them adequate permission to be accessed.
|
||||||
|
|
||||||
More experimental or potentially functionality changing or temperamental features may be included as seperate .patch files inside of the patch folder, and are not included in the source code by default.
|
|
||||||
If users wish to try or use these patches, then they can apply patches and build/rebuild with the following procedure. Make sure you have changed to the dsd-fme directory first, either by the top
|
|
||||||
command, or by otherwise opening the terminal to the clone folder.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
cd dsd-fme
|
sudo cp tone8.wav /usr/share/
|
||||||
git apply patch/patchname.patch
|
sudo cp tone24.wav /usr/share/
|
||||||
cd build
|
sudo cp tone48.wav /usr/share/
|
||||||
make
|
sudo chmod 777 /usr/share/tone8.wav
|
||||||
sudo make install
|
sudo chmod 777 /usr/share/tone24.wav
|
||||||
```
|
sudo chmod 777 /usr/share/tone48.wav
|
||||||
|
```
|
||||||
If you later wish to update to the latest version via `git pull`, you may first need to reset any patches, perform the `git pull`, and then reapply patches.
|
|
||||||
A procedure for this is similar to, but not limited to:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd dsd-fme
|
|
||||||
git reset --hard
|
|
||||||
git pull
|
|
||||||
git apply patch/xyz.patch
|
|
||||||
cd build
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
```
|
|
||||||
|
|
||||||
NOTE: Patches can potential break over time with further changes to code, requiring merge resolution or other manual intervention to re-apply patches.
|
|
||||||
@@ -9,6 +9,10 @@
|
|||||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -mq -N 2> log.ans
|
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -mq -N 2> log.ans
|
||||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -mq -N 2> log.ans
|
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -mq -N 2> log.ans
|
||||||
|
|
||||||
|
#P25 P2 TDMA CC with QPSK (Simulcast)
|
||||||
|
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -m2 -N 2> log.ans
|
||||||
|
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
|
||||||
|
|
||||||
#P25 P2 TDMA CC with C4FM
|
#P25 P2 TDMA CC with C4FM
|
||||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -N 2> log.ans
|
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -N 2> log.ans
|
||||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
|
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
|
|||||||
state = S2; // lower path
|
state = S2; // lower path
|
||||||
} else {
|
} else {
|
||||||
state = S0; // upper path
|
state = S0; // upper path
|
||||||
} // end else - if
|
}; // end else - if
|
||||||
out[loop]=0;
|
out[loop]=0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
|
|||||||
state = S2; // lower path
|
state = S2; // lower path
|
||||||
} else {
|
} else {
|
||||||
state = S0; // upper path
|
state = S0; // upper path
|
||||||
} // end else - if
|
}; // end else - if
|
||||||
out[loop]=1;
|
out[loop]=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
|
|||||||
state = S3; // lower path
|
state = S3; // lower path
|
||||||
} else {
|
} else {
|
||||||
state = S1; // upper path
|
state = S1; // upper path
|
||||||
} // end else - if
|
}; // end else - if
|
||||||
out[loop]=0;
|
out[loop]=0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -79,12 +79,12 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
|
|||||||
state = S3; // lower path
|
state = S3; // lower path
|
||||||
} else {
|
} else {
|
||||||
state = S1; // upper path
|
state = S1; // upper path
|
||||||
} // end else - if
|
}; // end else - if
|
||||||
out[loop]=1;
|
out[loop]=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} // end switch
|
}; // end switch
|
||||||
} // end for
|
}; // end for
|
||||||
|
|
||||||
return(length);
|
return(length);
|
||||||
}; // end function
|
}; // end function
|
||||||
|
|||||||
176
include/dsd.h
176
include/dsd.h
@@ -65,7 +65,7 @@
|
|||||||
#include <pulse/error.h> //PULSE AUDIO
|
#include <pulse/error.h> //PULSE AUDIO
|
||||||
|
|
||||||
#define SAMPLE_RATE_IN 48000 //48000
|
#define SAMPLE_RATE_IN 48000 //48000
|
||||||
#define SAMPLE_RATE_OUT 8000 //8000
|
#define SAMPLE_RATE_OUT 48000 //8000,
|
||||||
|
|
||||||
#ifdef USE_RTLSDR
|
#ifdef USE_RTLSDR
|
||||||
#include <rtl-sdr.h>
|
#include <rtl-sdr.h>
|
||||||
@@ -74,12 +74,6 @@
|
|||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
|
||||||
#define UNUSED(x) ((void)x)
|
|
||||||
#define UNUSED2(x1, x2) (UNUSED(x1), UNUSED(x2))
|
|
||||||
#define UNUSED3(x1, x2, x3) (UNUSED(x1), UNUSED(x2), UNUSED(x3))
|
|
||||||
#define UNUSED4(x1, x2, x3, x4) (UNUSED(x1), UNUSED(x2), UNUSED(x3), UNUSED(x4))
|
|
||||||
#define UNUSED5(x1, x2, x3, x4, x5) (UNUSED(x1), UNUSED(x2), UNUSED(x3), UNUSED(x4), UNUSED(x5))
|
|
||||||
|
|
||||||
#ifdef USE_CODEC2
|
#ifdef USE_CODEC2
|
||||||
#include <codec2/codec2.h>
|
#include <codec2/codec2.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -233,13 +227,13 @@ typedef struct
|
|||||||
float audio_gainR;
|
float audio_gainR;
|
||||||
int audio_out;
|
int audio_out;
|
||||||
int dmr_stereo_wav;
|
int dmr_stereo_wav;
|
||||||
char wav_out_dir[512];
|
|
||||||
char wav_out_file[1024];
|
char wav_out_file[1024];
|
||||||
char wav_out_fileR[1024];
|
char wav_out_fileR[1024];
|
||||||
char wav_out_file_raw[1024];
|
char wav_out_file_raw[1024];
|
||||||
char symbol_out_file[1024];
|
char symbol_out_file[1024];
|
||||||
char lrrp_out_file[1024];
|
char lrrp_out_file[1024];
|
||||||
char szNumbers[1024]; //**tera 10/32/64 char str
|
char szNumbers[1024]; //**tera 10/32/64 char str
|
||||||
|
short int symbol_out;
|
||||||
short int mbe_out; //flag for mbe out, don't attempt fclose more than once
|
short int mbe_out; //flag for mbe out, don't attempt fclose more than once
|
||||||
short int mbe_outR; //flag for mbe out, don't attempt fclose more than once
|
short int mbe_outR; //flag for mbe out, don't attempt fclose more than once
|
||||||
SNDFILE *wav_out_f;
|
SNDFILE *wav_out_f;
|
||||||
@@ -280,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;
|
||||||
long int rtl_rms;
|
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;
|
||||||
@@ -331,10 +325,11 @@ typedef struct
|
|||||||
int rigctlportno;
|
int rigctlportno;
|
||||||
char rigctlhostname[1024];
|
char rigctlhostname[1024];
|
||||||
|
|
||||||
//UDP Socket Blaster Audio
|
//udp socket for GQRX, SDR++, etc
|
||||||
int udp_sockfd;
|
int udp_sockfd;
|
||||||
int udp_portno;
|
int udp_portno;
|
||||||
char udp_hostname[1024];
|
char * udp_hostname;
|
||||||
|
SNDFILE *udp_file_in;
|
||||||
|
|
||||||
//tcp socket for SDR++, etc
|
//tcp socket for SDR++, etc
|
||||||
int tcp_sockfd;
|
int tcp_sockfd;
|
||||||
@@ -388,13 +383,9 @@ typedef struct
|
|||||||
//Trunking - Tune Enc Calls (P25 only on applicable grants with svc opts)
|
//Trunking - Tune Enc Calls (P25 only on applicable grants with svc opts)
|
||||||
uint8_t trunk_tune_enc_calls;
|
uint8_t trunk_tune_enc_calls;
|
||||||
|
|
||||||
//OSS audio 48k/1 - slot preference
|
//OSS audio - slot preference
|
||||||
int slot_preference;
|
int slot_preference;
|
||||||
|
|
||||||
//hard set slots to synthesize
|
|
||||||
int slot1_on;
|
|
||||||
int slot2_on;
|
|
||||||
|
|
||||||
//'DSP' Format Output
|
//'DSP' Format Output
|
||||||
uint8_t use_dsp_output;
|
uint8_t use_dsp_output;
|
||||||
char dsp_out_file[2048];
|
char dsp_out_file[2048];
|
||||||
@@ -402,9 +393,6 @@ typedef struct
|
|||||||
//Use P25p1 heuristics
|
//Use P25p1 heuristics
|
||||||
uint8_t use_heuristics;
|
uint8_t use_heuristics;
|
||||||
|
|
||||||
//Use floating point audio output
|
|
||||||
int floating_point;
|
|
||||||
|
|
||||||
} dsd_opts;
|
} dsd_opts;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -426,25 +414,6 @@ 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;
|
|
||||||
//new stereo float sample storage
|
|
||||||
float f_l[160]; //single sample left
|
|
||||||
float f_r[160]; //single sample right
|
|
||||||
float f_l4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
float f_r4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
//new stereo short sample storage
|
|
||||||
short s_l[160]; //single sample left
|
|
||||||
short s_r[160]; //single sample right
|
|
||||||
short s_l4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
short s_r4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
//new stereo short sample storage tapped from 48_k internal upsampling
|
|
||||||
short s_lu[160*6]; //single sample left
|
|
||||||
short s_ru[160*6]; //single sample right
|
|
||||||
short s_l4u[4][160*6]; //quad sample for up to a P25p2 4V
|
|
||||||
short s_r4u[4][160*6]; //quad sample for up to a P25p2 4V
|
|
||||||
//end
|
|
||||||
int audio_out_idx;
|
int audio_out_idx;
|
||||||
int audio_out_idx2;
|
int audio_out_idx2;
|
||||||
int audio_out_idxR;
|
int audio_out_idxR;
|
||||||
@@ -598,10 +567,10 @@ typedef struct
|
|||||||
|
|
||||||
//new stuff below here
|
//new stuff below here
|
||||||
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
|
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
|
||||||
uint8_t dmr_pdu_sf[2][24*128]; //unified pdu 'superframe' //[slot][byte] -- increased capacity to 127(+1) full rate blocks
|
uint8_t dmr_pdu_sf[2][288]; //unified pdu 'superframe' //[slot][byte]
|
||||||
uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot
|
uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot
|
||||||
uint8_t cap_plus_block_num[2]; //received block number storage -- per timeslot
|
uint8_t cap_plus_block_num[2]; //received block number storage -- per timeslot
|
||||||
uint8_t data_block_crc_valid[2][127]; //flag each individual block as good crc on confirmed data
|
uint8_t data_block_crc_valid[2][25]; //flag each individual block as good crc on confirmed data
|
||||||
char dmr_embedded_signalling[2][7][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
|
char dmr_embedded_signalling[2][7][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
|
||||||
|
|
||||||
char dmr_cach_fragment[4][17]; //unsure of size, will need to check/verify
|
char dmr_cach_fragment[4][17]; //unsure of size, will need to check/verify
|
||||||
@@ -674,14 +643,15 @@ typedef struct
|
|||||||
int symbol_throttle; //throttle speed
|
int symbol_throttle; //throttle speed
|
||||||
int use_throttle; //only use throttle if set to 1
|
int use_throttle; //only use throttle if set to 1
|
||||||
|
|
||||||
|
//dstar header for ncurses
|
||||||
|
unsigned char dstarradioheader[41];
|
||||||
|
|
||||||
//dmr trunking stuff
|
//dmr trunking stuff
|
||||||
int dmr_rest_channel;
|
int dmr_rest_channel;
|
||||||
int dmr_mfid; //just when 'fid' is used as a manufacturer ID and not a feature set id
|
int dmr_mfid; //just when 'fid' is used as a manufacturer ID and not a feature set id
|
||||||
int dmr_vc_lcn;
|
int dmr_vc_lcn;
|
||||||
int dmr_vc_lsn;
|
int dmr_vc_lsn;
|
||||||
int dmr_tuned_lcn;
|
int dmr_tuned_lcn;
|
||||||
uint16_t dmr_cc_lpcn; //dmr t3 logical physical channel number
|
|
||||||
uint32_t tg_hold; //single TG to hold on when enabled
|
|
||||||
|
|
||||||
//edacs
|
//edacs
|
||||||
int ea_mode;
|
int ea_mode;
|
||||||
@@ -757,21 +727,12 @@ typedef struct
|
|||||||
char ysf_rm4[6];
|
char ysf_rm4[6];
|
||||||
char ysf_txt[21][21]; //text storage blocks
|
char ysf_txt[21][21]; //text storage blocks
|
||||||
|
|
||||||
//DSTAR Call Strings and Info
|
|
||||||
char dstar_rpt1[9];
|
|
||||||
char dstar_rpt2[9];
|
|
||||||
char dstar_dst[9];
|
|
||||||
char dstar_src[13];
|
|
||||||
char dstar_txt[60];
|
|
||||||
char dstar_gps[60];
|
|
||||||
|
|
||||||
//M17 Storage
|
//M17 Storage
|
||||||
uint8_t m17_lsf[360];
|
uint8_t m17_lsf[360];
|
||||||
uint8_t m17_str_dt; //stream contents
|
uint8_t m17_str_dt; //stream contents
|
||||||
|
|
||||||
unsigned long long int m17_dst;
|
unsigned long long int m17_dst;
|
||||||
unsigned long long int m17_src;
|
unsigned long long int m17_src;
|
||||||
uint8_t m17_can;
|
|
||||||
|
|
||||||
char m17_dst_csd[20];
|
char m17_dst_csd[20];
|
||||||
char m17_src_csd[20];
|
char m17_src_csd[20];
|
||||||
@@ -779,14 +740,10 @@ typedef struct
|
|||||||
char m17_src_str[50];
|
char m17_src_str[50];
|
||||||
char m17_dst_str[50];
|
char m17_dst_str[50];
|
||||||
|
|
||||||
uint8_t m17_meta[16]; //packed meta
|
uint8_t m17_meta[14]; //packed meta
|
||||||
uint8_t m17_enc; //enc type
|
uint8_t m17_enc; //enc type
|
||||||
uint8_t m17_enc_st; //scrambler or data subtye
|
uint8_t m17_enc_st; //scrambler or data subtye
|
||||||
|
|
||||||
//misc str storage
|
|
||||||
char str50a[50];
|
|
||||||
char str50b[50];
|
|
||||||
|
|
||||||
//Codec2
|
//Codec2
|
||||||
#ifdef USE_CODEC2
|
#ifdef USE_CODEC2
|
||||||
struct CODEC2 *codec2_3200; //M17 fullrate
|
struct CODEC2 *codec2_3200; //M17 fullrate
|
||||||
@@ -862,10 +819,6 @@ typedef struct
|
|||||||
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
|
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
|
||||||
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
|
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
|
||||||
|
|
||||||
//EDACS/PV EOT dotting sequence
|
|
||||||
#define DOTTING_SEQUENCE_A "131313131313131313131313131313131313131313131313" //0xAAAA...
|
|
||||||
#define DOTTING_SEQUENCE_B "313131313131313131313131313131313131313131313131" //0x5555...
|
|
||||||
|
|
||||||
//define the provoice conventional string pattern to default 85/85 if not enabled, else mute it so we won't double sync on accident in frame_sync
|
//define the provoice conventional string pattern to default 85/85 if not enabled, else mute it so we won't double sync on accident in frame_sync
|
||||||
#ifdef PVCONVENTIONAL
|
#ifdef PVCONVENTIONAL
|
||||||
#define PROVOICE_CONV "00000000000000000000000000000000" //all zeroes should be unobtainable string in the frame_sync synctests
|
#define PROVOICE_CONV "00000000000000000000000000000000" //all zeroes should be unobtainable string in the frame_sync synctests
|
||||||
@@ -874,7 +827,7 @@ typedef struct
|
|||||||
#define PROVOICE_CONV "13131333111311311313131313131313" //TX 85 RX 85 (default programming value)
|
#define PROVOICE_CONV "13131333111311311313131313131313" //TX 85 RX 85 (default programming value)
|
||||||
#define INV_PROVOICE_CONV "31313111333133133131313131313131" //TX 85 RX 85 (default programming value)
|
#define INV_PROVOICE_CONV "31313111333133133131313131313131" //TX 85 RX 85 (default programming value)
|
||||||
#endif
|
#endif
|
||||||
//we use the short sync instead of the default 85/85 when PVCONVENTIONAL is defined by cmake
|
//we use the short sync instead of the default 85/85 wnen PVCONVENTIONAL is defined by cmake
|
||||||
#define PROVOICE_CONV_SHORT "1313133311131131" //16-bit short pattern, last 16-bits change based on TX an RX values
|
#define PROVOICE_CONV_SHORT "1313133311131131" //16-bit short pattern, last 16-bits change based on TX an RX values
|
||||||
#define INV_PROVOICE_CONV_SHORT "3131311133313313"
|
#define INV_PROVOICE_CONV_SHORT "3131311133313313"
|
||||||
//In this pattern (inverted polarity, the norm for PV) 3 is bit 0, and 1 is bit 1 (2 level GFSK)
|
//In this pattern (inverted polarity, the norm for PV) 3 is bit 0, and 1 is bit 1 (2 level GFSK)
|
||||||
@@ -907,33 +860,19 @@ typedef struct
|
|||||||
void processdPMRvoice (dsd_opts * opts, dsd_state * state);
|
void processdPMRvoice (dsd_opts * opts, dsd_state * state);
|
||||||
void processAudio (dsd_opts * opts, dsd_state * state);
|
void processAudio (dsd_opts * opts, dsd_state * state);
|
||||||
void processAudioR (dsd_opts * opts, dsd_state * state);
|
void processAudioR (dsd_opts * opts, dsd_state * state);
|
||||||
void openPulseInput (dsd_opts * opts);
|
void openPulseInput (dsd_opts * opts); //not sure if we need to just pass opts, or opts and state yet
|
||||||
void openPulseOutput (dsd_opts * opts);
|
void openPulseOutput (dsd_opts * opts); //not sure if we need to just pass opts, or opts and state yet
|
||||||
void openOSSOutput (dsd_opts * opts);
|
|
||||||
void closePulseInput (dsd_opts * opts);
|
void closePulseInput (dsd_opts * opts);
|
||||||
void closePulseOutput (dsd_opts * opts);
|
void closePulseOutput (dsd_opts * opts);
|
||||||
void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
||||||
void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state);
|
void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state);
|
||||||
void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); //short mono output slot 1
|
void playSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
||||||
void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); //short mono output slot 2
|
void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state);
|
||||||
//new float stuff
|
|
||||||
void playSynthesizedVoiceFS (dsd_opts * opts, dsd_state * state); //float stereo mix
|
|
||||||
void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state); //float stereo mix 3v2 DMR
|
|
||||||
void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state); //float stereo mix 4v2 P25p2
|
|
||||||
void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state); //float mono
|
|
||||||
void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //float gain control
|
|
||||||
//new short stuff
|
|
||||||
void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix
|
|
||||||
void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR
|
|
||||||
void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2
|
|
||||||
void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short
|
|
||||||
//
|
|
||||||
void openAudioOutDevice (dsd_opts * opts, int speed);
|
void openAudioOutDevice (dsd_opts * opts, int speed);
|
||||||
void openAudioInDevice (dsd_opts * opts);
|
void openAudioInDevice (dsd_opts * opts);
|
||||||
|
|
||||||
int getDibit (dsd_opts * opts, dsd_state * state);
|
int getDibit (dsd_opts * opts, dsd_state * state);
|
||||||
int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal);
|
int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal);
|
||||||
int digitize (dsd_opts* opts, dsd_state* state, int symbol);
|
|
||||||
|
|
||||||
void skipDibit (dsd_opts * opts, dsd_state * state, int count);
|
void skipDibit (dsd_opts * opts, dsd_state * state, int count);
|
||||||
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||||
@@ -954,6 +893,7 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state);
|
|||||||
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state);
|
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state);
|
||||||
void openSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
void openSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
|
void writeSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample);
|
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample);
|
||||||
void closeWavOutFile (dsd_opts * opts, dsd_state * state);
|
void closeWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
void closeWavOutFileL (dsd_opts * opts, dsd_state * state);
|
void closeWavOutFileL (dsd_opts * opts, dsd_state * state);
|
||||||
@@ -970,6 +910,7 @@ void initState (dsd_state * state);
|
|||||||
void usage ();
|
void usage ();
|
||||||
void liveScanner (dsd_opts * opts, dsd_state * state);
|
void liveScanner (dsd_opts * opts, dsd_state * state);
|
||||||
void cleanupAndExit (dsd_opts * opts, dsd_state * state);
|
void cleanupAndExit (dsd_opts * opts, dsd_state * state);
|
||||||
|
// void sigfun (int sig); //not necesary
|
||||||
int main (int argc, char **argv);
|
int main (int argc, char **argv);
|
||||||
void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv);
|
void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv);
|
||||||
void processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]);
|
void processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]);
|
||||||
@@ -979,16 +920,8 @@ int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync);
|
|||||||
void upsample (dsd_state * state, float invalue);
|
void upsample (dsd_state * state, float invalue);
|
||||||
void processDSTAR (dsd_opts * opts, dsd_state * state);
|
void processDSTAR (dsd_opts * opts, dsd_state * state);
|
||||||
|
|
||||||
//new cleaner, sleaker, nicer mbe handler...maybe -- wrap around ifdef later on with cmake options
|
|
||||||
void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]);
|
|
||||||
void soft_tonef (float samp[160], int n, int ID, int AD);
|
|
||||||
|
|
||||||
//new p25lcw
|
//new p25lcw
|
||||||
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors);
|
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors);
|
||||||
//new p25 1/2 rate decoder
|
|
||||||
int p25_12(uint8_t * input, uint8_t treturn[12]);
|
|
||||||
//new p25 lsd fec function
|
|
||||||
int p25p1_lsd_fec(uint8_t * input);
|
|
||||||
|
|
||||||
void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo);
|
void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo);
|
||||||
void processHDU (dsd_opts * opts, dsd_state * state);
|
void processHDU (dsd_opts * opts, dsd_state * state);
|
||||||
@@ -999,8 +932,7 @@ void processTDULC (dsd_opts * opts, dsd_state * state);
|
|||||||
void processProVoice (dsd_opts * opts, dsd_state * state);
|
void processProVoice (dsd_opts * opts, dsd_state * state);
|
||||||
void processX2TDMAdata (dsd_opts * opts, dsd_state * state);
|
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); //DSTAR Header
|
void processDSTAR_HD (dsd_opts * opts, dsd_state * state);
|
||||||
void processDSTAR_SD (dsd_opts * opts, dsd_state * state, uint8_t * sd); //DSTAR Slow Data
|
|
||||||
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 processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR)
|
||||||
void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF)
|
void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF)
|
||||||
@@ -1012,6 +944,7 @@ short nxdn_filter(short sample);
|
|||||||
short dpmr_filter(short sample);
|
short dpmr_filter(short sample);
|
||||||
short m17_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);
|
||||||
@@ -1032,23 +965,20 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
//end
|
//end
|
||||||
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
|
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
|
||||||
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
|
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
|
||||||
//Osmocom OP25 12 Rate Trellis Decoder (for NXDN, M17, YSF, etc)
|
|
||||||
void trellis_decode(uint8_t result[], const uint8_t source[], int result_len);
|
|
||||||
|
|
||||||
//OP25 NXDN CRC functions
|
//OP25 NXDN CRC functions
|
||||||
int load_i(const uint8_t val[], int len);
|
static inline int load_i(const uint8_t val[], int len);
|
||||||
uint8_t crc6(const uint8_t buf[], int len);
|
static uint8_t crc6(const uint8_t buf[], int len);
|
||||||
uint16_t crc12f(const uint8_t buf[], int len);
|
static uint16_t crc12f(const uint8_t buf[], int len);
|
||||||
uint16_t crc15(const uint8_t buf[], int len);
|
static uint16_t crc15(const uint8_t buf[], int len);
|
||||||
uint16_t crc16cac(const uint8_t buf[], int len);
|
static uint16_t crc16cac(const uint8_t buf[], int len);
|
||||||
uint8_t crc7_scch(uint8_t bits[], int len); //converted from op25 crc6
|
static uint8_t crc7_scch(uint8_t bits[], int len); //converted from op25 crc6
|
||||||
|
|
||||||
/* NXDN Convolution functions */
|
/* NXDN Convolution functions */
|
||||||
void CNXDNConvolution_start(void);
|
void CNXDNConvolution_start(void);
|
||||||
void CNXDNConvolution_decode(uint8_t s0, uint8_t s1);
|
void CNXDNConvolution_decode(uint8_t s0, uint8_t s1);
|
||||||
void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits);
|
void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits);
|
||||||
void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsigned int nBits);
|
void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsigned int nBits);
|
||||||
void CNXDNConvolution_init();
|
|
||||||
|
|
||||||
//keeping these
|
//keeping these
|
||||||
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state);
|
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1107,19 +1037,11 @@ 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 lr); //the tone beeper function
|
|
||||||
void dmr_gateway_identifier (uint32_t source, uint32_t target); //translate special addresses
|
|
||||||
|
|
||||||
//Embedded Alias and GPS reports
|
//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[]);
|
||||||
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||||
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||||
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
|
||||||
void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input);
|
|
||||||
void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int type);
|
|
||||||
void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int slot);
|
|
||||||
void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input);
|
|
||||||
|
|
||||||
//"DMR STEREO"
|
//"DMR STEREO"
|
||||||
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state);
|
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1135,15 +1057,12 @@ void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR
|
|||||||
void dmr_reset_blocks (dsd_opts * opts, dsd_state * state);
|
void dmr_reset_blocks (dsd_opts * opts, dsd_state * state);
|
||||||
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
||||||
void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
||||||
char * getTimeL(void);
|
|
||||||
char * getDateL(void);
|
|
||||||
|
|
||||||
//dmr alg stuff
|
//dmr alg stuff
|
||||||
void dmr_alg_reset (dsd_opts * opts, dsd_state * state);
|
void dmr_alg_reset (dsd_opts * opts, dsd_state * state);
|
||||||
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state);
|
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state);
|
||||||
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, uint8_t ambe_fr[4][24], uint8_t ambe_fr2[4][24], uint8_t ambe_fr3[4][24]);
|
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, char ambe_fr[4][24], char ambe_fr2[4][24], char ambe_fr3[4][24]);
|
||||||
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state);
|
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state);
|
||||||
void dmr_decode_syscode(dsd_opts * opts, dsd_state * state, uint8_t * cs_pdu_bits, int csbk_fid, int type);
|
|
||||||
|
|
||||||
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
|
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
|
||||||
void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power);
|
void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power);
|
||||||
@@ -1154,8 +1073,7 @@ 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);
|
||||||
@@ -1215,10 +1133,6 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
//P25 Channel to Frequency
|
//P25 Channel to Frequency
|
||||||
long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channel);
|
long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channel);
|
||||||
|
|
||||||
//P25 CRC Functions
|
|
||||||
int crc16_lb_bridge (int payload[190], int len);
|
|
||||||
int crc12_xb_bridge (int payload[190], int len);
|
|
||||||
|
|
||||||
//NXDN Channel to Frequency, Courtesy of IcomIcR20 on RR Forums
|
//NXDN Channel to Frequency, Courtesy of IcomIcR20 on RR Forums
|
||||||
long int nxdn_channel_to_frequency (dsd_opts * opts, dsd_state * state, uint16_t channel);
|
long int nxdn_channel_to_frequency (dsd_opts * opts, dsd_state * state, uint16_t channel);
|
||||||
|
|
||||||
@@ -1246,8 +1160,7 @@ int UDPBind (char *hostname, int portno);
|
|||||||
|
|
||||||
//EDACS
|
//EDACS
|
||||||
void edacs(dsd_opts * opts, dsd_state * state);
|
void edacs(dsd_opts * opts, dsd_state * state);
|
||||||
unsigned long long int edacs_bch (unsigned long long int message);
|
unsigned long long int edacs_bch (unsigned long long int message);
|
||||||
void eot_cc(dsd_opts * opts, dsd_state * state); //end of TX return to CC
|
|
||||||
|
|
||||||
//csv imports
|
//csv imports
|
||||||
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1256,10 +1169,6 @@ int csvChanImport(dsd_opts * opts, dsd_state * state);
|
|||||||
int csvKeyImportDec(dsd_opts * opts, dsd_state * state);
|
int csvKeyImportDec(dsd_opts * opts, dsd_state * state);
|
||||||
int csvKeyImportHex(dsd_opts * opts, dsd_state * state);
|
int csvKeyImportHex(dsd_opts * opts, dsd_state * state);
|
||||||
|
|
||||||
//UDP Socket Connect and UDP Socket Blaster (audio output)
|
|
||||||
int udp_socket_connect(dsd_opts * opts, dsd_state * state);
|
|
||||||
int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -1267,19 +1176,30 @@ extern "C" {
|
|||||||
#ifdef USE_RTLSDR
|
#ifdef USE_RTLSDR
|
||||||
void open_rtlsdr_stream(dsd_opts *opts);
|
void open_rtlsdr_stream(dsd_opts *opts);
|
||||||
void cleanup_rtlsdr_stream();
|
void cleanup_rtlsdr_stream();
|
||||||
int 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);
|
||||||
long int rtl_return_rms();
|
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 RS/FEC 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 (uint64_t isch); //isch map lookup
|
int isch_lookup (unsigned long long int isch); //isch map lookup
|
||||||
|
int bd_bridge (int payload[196], uint8_t decoded[12]); //bridge to Michael Ossmann Block De-interleaver and 1/2 rate trellis decoder
|
||||||
|
int crc16_lb_bridge (int payload[190], int len);
|
||||||
|
int crc12_xb_bridge (int payload[190], int len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ for (loop=0; loop < size; loop++) {
|
|||||||
|
|
||||||
m_crc = (m_crc >> 8) ^ ccittTab[tmp];
|
m_crc = (m_crc >> 8) ^ ccittTab[tmp];
|
||||||
|
|
||||||
} // end for
|
}; // end for
|
||||||
|
|
||||||
// calculate and save crc-value in fields 54 and 55 of dvframe
|
// calculate and save crc-value in fields 54 and 55 of dvframe
|
||||||
m_crc = ~m_crc;
|
m_crc = ~m_crc;
|
||||||
|
|||||||
1448
include/fec.h
Normal file
1448
include/fec.h
Normal file
File diff suppressed because it is too large
Load Diff
12
install.sh
12
install.sh
@@ -1,8 +1,12 @@
|
|||||||
#!/bin/bash
|
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
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
make -j $(nproc)
|
make -j `nproc`
|
||||||
sudo make install
|
sudo make install
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
diff --git a/src/dmr_block.c b/src/dmr_block.c
|
|
||||||
index 893b0e8..e7f9de7 100644
|
|
||||||
--- a/src/dmr_block.c
|
|
||||||
+++ b/src/dmr_block.c
|
|
||||||
@@ -783,6 +783,6 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
|
||||||
//reset some strings -- resetting call string here causes random blink on ncurses terminal (cap+)
|
|
||||||
// sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
// sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
- sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
|
||||||
- sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
|
||||||
+ // sprintf (state->dmr_lrrp_gps[0], "%s", ""); //disabled for dmr data call persistence #174
|
|
||||||
+ // sprintf (state->dmr_lrrp_gps[1], "%s", ""); //disabled for dmr data call persistence #174
|
|
||||||
}
|
|
||||||
\ No newline at end of file
|
|
||||||
diff --git a/src/dmr_data.c b/src/dmr_data.c
|
|
||||||
index 3541152..3cae906 100644
|
|
||||||
--- a/src/dmr_data.c
|
|
||||||
+++ b/src/dmr_data.c
|
|
||||||
@@ -267,7 +267,20 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
|
||||||
state->color_code_ok = SlotTypeOk;
|
|
||||||
|
|
||||||
//not sure why I still have two variables for this, need to look and see what state->color_code still ties into
|
|
||||||
- if (SlotTypeOk == 1) state->dmr_color_code = state->color_code;
|
|
||||||
+ if (SlotTypeOk == 1)
|
|
||||||
+ {
|
|
||||||
+ if (state->dmr_color_code != state->color_code)
|
|
||||||
+ {
|
|
||||||
+ //Zero out values on color code change #174
|
|
||||||
+ state->lasttg = 0;
|
|
||||||
+ state->lasttgR =0;
|
|
||||||
+ state->lastsrc = 0;
|
|
||||||
+ state->lastsrcR = 0;
|
|
||||||
+ sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
|
||||||
+ sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
|
||||||
+ state->dmr_color_code = state->color_code;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* Reconstitute the burst type */
|
|
||||||
burst = (uint8_t)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 5531ef3..5598793 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -257,10 +257,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
//zero out right away if not trunking
|
|
||||||
if (opts->p25_trunk == 0)
|
|
||||||
{
|
|
||||||
- state->lasttg = 0;
|
|
||||||
- state->lastsrc = 0;
|
|
||||||
- state->lasttgR = 0;
|
|
||||||
- state->lastsrcR = 0;
|
|
||||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
|
|
||||||
//zero out vc frequencies?
|
|
||||||
state->p25_vc_freq[0] = 0;
|
|
||||||
@@ -290,10 +290,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
//mainly bugfix for ncurses and per call wavs (edacs) and also signal fade, etc
|
|
||||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && time(NULL) - state->last_cc_sync_time > opts->trunk_hangtime)
|
|
||||||
{
|
|
||||||
- state->lasttg = 0;
|
|
||||||
- state->lastsrc = 0;
|
|
||||||
- state->lasttgR = 0;
|
|
||||||
- state->lastsrcR = 0;
|
|
||||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -431,7 +431,7 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
memset(state->dmr_alias_len, 0, sizeof(state->dmr_alias_len));
|
|
||||||
memset(state->dmr_alias_block_segment, 0, sizeof(state->dmr_alias_block_segment));
|
|
||||||
memset(state->dmr_embedded_gps, 0, sizeof(state->dmr_embedded_gps));
|
|
||||||
- memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
|
||||||
+ // memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
|
||||||
|
|
||||||
// memset(state->active_channel, 0, sizeof(state->active_channel));
|
|
||||||
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..e9ecab1 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -3104,7 +3104,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
//LRRP
|
|
||||||
- if(state->dmrburstL != 16) //only during data and no trunking
|
|
||||||
+ // if(state->dmrburstL != 16) //only during data and no trunking //disabled for dmr data call persistence #174
|
|
||||||
{
|
|
||||||
attron(COLOR_PAIR(4));
|
|
||||||
printw ("%s", state->dmr_lrrp_gps[0]);
|
|
||||||
@@ -3298,7 +3298,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
//LRRP
|
|
||||||
- if(state->dmrburstR != 16) //only during data and no trunking
|
|
||||||
+ // if(state->dmrburstR != 16) //only during data and no trunking //disabled for dmr data call persistence #174
|
|
||||||
{
|
|
||||||
attron(COLOR_PAIR(4));
|
|
||||||
printw ("%s", state->dmr_lrrp_gps[1]);
|
|
||||||
@@ -3978,10 +3978,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
dmr_reset_blocks (opts, state);
|
|
||||||
|
|
||||||
//zero out additional items
|
|
||||||
- state->lasttg = 0;
|
|
||||||
- state->lasttgR = 0;
|
|
||||||
- state->lastsrc = 0;
|
|
||||||
- state->lastsrcR = 0;
|
|
||||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c
|
|
||||||
index 5155bd7..3cf0480 100644
|
|
||||||
--- a/src/p25p2_vpdu.c
|
|
||||||
+++ b/src/p25p2_vpdu.c
|
|
||||||
@@ -155,16 +155,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -255,16 +255,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -386,16 +386,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -511,16 +511,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -642,16 +642,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -748,16 +748,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -918,16 +918,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1109,16 +1109,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1245,16 +1245,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1374,16 +1374,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channelt & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channelt & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,319 +0,0 @@
|
|||||||
diff --git a/src/p25p1_mdpu.c b/src/p25p1_mdpu.c
|
|
||||||
index 7d29860..00c1828 100644
|
|
||||||
--- a/src/p25p1_mdpu.c
|
|
||||||
+++ b/src/p25p1_mdpu.c
|
|
||||||
@@ -527,13 +527,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -644,13 +644,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -753,13 +753,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -876,13 +876,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/p25p1_tsbk.c b/src/p25p1_tsbk.c
|
|
||||||
index c801b7f..345335a 100644
|
|
||||||
--- a/src/p25p1_tsbk.c
|
|
||||||
+++ b/src/p25p1_tsbk.c
|
|
||||||
@@ -294,13 +294,13 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c
|
|
||||||
index 468b71a..1b14d71 100644
|
|
||||||
--- a/src/p25p2_vpdu.c
|
|
||||||
+++ b/src/p25p2_vpdu.c
|
|
||||||
@@ -75,8 +75,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//Temp Fix: Disable Slot Playback when MAC_SIGNAL present (good CRC),
|
|
||||||
//during trunking, will re-enable when call grant is received, prevent lagging:
|
|
||||||
- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot1_on = 0;
|
|
||||||
- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot2_on = 0;
|
|
||||||
|
|
||||||
//TODO: Iron out issues with audio playing in every non SACCH slot when no voice present
|
|
||||||
//without it stuttering during actual voice
|
|
||||||
@@ -156,13 +154,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -256,13 +254,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -387,13 +385,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -512,13 +510,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -643,13 +641,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -749,13 +747,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -919,13 +917,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1110,13 +1108,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1246,13 +1244,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1375,13 +1373,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1498,13 +1496,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1516,9 +1514,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
state->samplesPerSymbol = 10;
|
|
||||||
state->symbolCenter = 4;
|
|
||||||
opts->frame_p25p1 = 1; //enable, just in case it isn't already
|
|
||||||
-
|
|
||||||
- //enable voice on slot 1 (just in case they start talking too, but probably won't)
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,461 +0,0 @@
|
|||||||
diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c
|
|
||||||
index 129a087..0b7f4e2 100644
|
|
||||||
--- a/src/dmr_csbk.c
|
|
||||||
+++ b/src/dmr_csbk.c
|
|
||||||
@@ -424,6 +424,25 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
+ if (state->currentslot == 0)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ else if (state->currentslot == 1)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//Guess I forgot to add this condition here
|
|
||||||
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency
|
|
||||||
@@ -443,6 +462,26 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
+
|
|
||||||
+ if (state->currentslot == 0)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ else if (state->currentslot == 1)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//Guess I forgot to add this condition here
|
|
||||||
uint32_t tempf = (uint32_t)state->p25_cc_freq;
|
|
||||||
if (opts->rtlsdr_center_freq != tempf)
|
|
||||||
diff --git a/src/dmr_flco.c b/src/dmr_flco.c
|
|
||||||
index 828de02..916eb62 100644
|
|
||||||
--- a/src/dmr_flco.c
|
|
||||||
+++ b/src/dmr_flco.c
|
|
||||||
@@ -10,6 +10,38 @@
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
+//I really just need to make ONE consolidated date and time function that works correctly
|
|
||||||
+char * getDateFLC(void) {
|
|
||||||
+ #ifdef AERO_BUILD
|
|
||||||
+ char datename[80];
|
|
||||||
+ #else
|
|
||||||
+ char datename[99];
|
|
||||||
+ #endif
|
|
||||||
+ char * curr2;
|
|
||||||
+ struct tm * to;
|
|
||||||
+ time_t t;
|
|
||||||
+ t = time(NULL);
|
|
||||||
+ to = localtime( & t);
|
|
||||||
+ strftime(datename, sizeof(datename), "%Y%m%d", to);
|
|
||||||
+ curr2 = strtok(datename, " ");
|
|
||||||
+ return curr2;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b
|
|
||||||
+char * getTimeFLC(void) //get pretty hhmmss timestamp
|
|
||||||
+{
|
|
||||||
+ char * curr = (char *) malloc(9);
|
|
||||||
+ time_t t = time(NULL);
|
|
||||||
+ struct tm * ptm = localtime(& t);
|
|
||||||
+ sprintf(
|
|
||||||
+ curr,
|
|
||||||
+ "%02d%02d%02d",
|
|
||||||
+ ptm->tm_hour,
|
|
||||||
+ ptm->tm_min,
|
|
||||||
+ ptm->tm_sec
|
|
||||||
+ );
|
|
||||||
+ return curr;
|
|
||||||
+}
|
|
||||||
|
|
||||||
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
|
||||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type)
|
|
||||||
@@ -304,6 +336,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
state->dmr_so = so;
|
|
||||||
state->lasttg = target;
|
|
||||||
state->lastsrc = source;
|
|
||||||
+ char * timestr;
|
|
||||||
+ timestr = getTimeFLC();
|
|
||||||
+ //open wav file here if not already opened
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f == NULL)
|
|
||||||
+ {
|
|
||||||
+ sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source);
|
|
||||||
+ openWavOutFileL (opts, state);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
if (state->currentslot == 1)
|
|
||||||
{
|
|
||||||
@@ -311,6 +351,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
state->dmr_soR = so;
|
|
||||||
state->lasttgR = target;
|
|
||||||
state->lastsrcR = source;
|
|
||||||
+ char * timestr;
|
|
||||||
+ timestr = getTimeFLC();
|
|
||||||
+ //open wav file here if not already opened
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR == NULL)
|
|
||||||
+ {
|
|
||||||
+ sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source);
|
|
||||||
+ openWavOutFileR (opts, state);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
|
||||||
@@ -337,6 +385,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
if (state->currentslot == 1)
|
|
||||||
{
|
|
||||||
@@ -350,6 +404,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gainR = opts->audio_gain;
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/dsd_file.c b/src/dsd_file.c
|
|
||||||
index 8e9094c..e8441ec 100644
|
|
||||||
--- a/src/dsd_file.c
|
|
||||||
+++ b/src/dsd_file.c
|
|
||||||
@@ -366,7 +366,7 @@ void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
|
||||||
fclose (opts->mbe_out_f);
|
|
||||||
opts->mbe_out_f = NULL;
|
|
||||||
opts->mbe_out = 0;
|
|
||||||
- fprintf (stderr, "\nClosing MBE out file 1.\n");
|
|
||||||
+ // fprintf (stderr, "\nClosing MBE out file 1.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -385,7 +385,7 @@ void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
fclose (opts->mbe_out_fR);
|
|
||||||
opts->mbe_out_fR = NULL;
|
|
||||||
opts->mbe_outR = 0;
|
|
||||||
- fprintf (stderr, "\nClosing MBE out file 2.\n");
|
|
||||||
+ // fprintf (stderr, "\nClosing MBE out file 2.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -420,7 +420,7 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
state->tgcount = 0;
|
|
||||||
-
|
|
||||||
+ //TODO: Change the date/time functions here to operate without using colons
|
|
||||||
sprintf (opts->mbe_out_file, "%s %s S1%s", getDateF(), getTimeF(), ext);
|
|
||||||
|
|
||||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
|
|
||||||
@@ -467,7 +467,7 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
state->tgcount = 0;
|
|
||||||
-
|
|
||||||
+ //TODO: Change the date/time functions here to operate without using colons
|
|
||||||
sprintf (opts->mbe_out_fileR, "%s %s S2%s", getDateF(), getTimeF(), ext);
|
|
||||||
|
|
||||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_fileR);
|
|
||||||
@@ -557,6 +557,19 @@ void closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_f);
|
|
||||||
+ char shell[2065], newfilename[1032];
|
|
||||||
+ int result;
|
|
||||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
|
||||||
+#ifdef AERO_BUILD
|
|
||||||
+ result = rename (opts->wav_out_file, newfilename);
|
|
||||||
+ UNUSED(shell);
|
|
||||||
+#else
|
|
||||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename);
|
|
||||||
+ result = system (shell);
|
|
||||||
+#endif
|
|
||||||
+ // fprintf (stderr, "\n Close WAV FileF %s; Result: %d \n", newfilename, result);
|
|
||||||
+ UNUSED(result);
|
|
||||||
+
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
|
||||||
@@ -564,6 +577,19 @@ void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_f);
|
|
||||||
+ char shell[2065], newfilename[1032];
|
|
||||||
+ int result;
|
|
||||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
|
||||||
+#ifdef AERO_BUILD
|
|
||||||
+ result = rename (opts->wav_out_file, newfilename);
|
|
||||||
+ UNUSED(shell);
|
|
||||||
+#else
|
|
||||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename);
|
|
||||||
+ result = system (shell);
|
|
||||||
+#endif
|
|
||||||
+ // fprintf (stderr, "\n Close WAV FileL %s; Result: %d \n", newfilename, result);
|
|
||||||
+ UNUSED(result);
|
|
||||||
+
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
@@ -571,6 +597,18 @@ void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_fR);
|
|
||||||
+ char shell[2065], newfilename[1032];
|
|
||||||
+ int result;
|
|
||||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_fileR);
|
|
||||||
+#ifdef AERO_BUILD
|
|
||||||
+ result = rename (opts->wav_out_fileR, newfilename);
|
|
||||||
+ UNUSED(shell);
|
|
||||||
+#else
|
|
||||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_fileR, newfilename);
|
|
||||||
+ result = system (shell);
|
|
||||||
+#endif
|
|
||||||
+ // fprintf (stderr, "\n Close WAV FileR %s; Result: %d \n", newfilename, result);
|
|
||||||
+ UNUSED(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 1d2616b..c3a216d 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -107,6 +107,19 @@ void
|
|
||||||
noCarrier (dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
+ //end perCall wav file close
|
|
||||||
+
|
|
||||||
#ifdef AERO_BUILD
|
|
||||||
//TODO: Investigate why getSymbol needs to be run first in this context...truly confused here
|
|
||||||
if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
@@ -1568,9 +1581,9 @@ main (int argc, char **argv)
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef AERO_BUILD
|
|
||||||
- fprintf (stderr, "Build Version: AW (20231015) \n");
|
|
||||||
+ fprintf (stderr, "Build Version: AW (20231214) G Build\n");
|
|
||||||
#else
|
|
||||||
- fprintf (stderr, "Build Version: AW %s \n", GIT_TAG);
|
|
||||||
+ fprintf (stderr, "Build Version: AW %s G Build\n", GIT_TAG);
|
|
||||||
#endif
|
|
||||||
fprintf (stderr,"MBElib Version: %s\n", versionstr);
|
|
||||||
|
|
||||||
diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c
|
|
||||||
index 9f609ca..f23209c 100644
|
|
||||||
--- a/src/dsd_mbe.c
|
|
||||||
+++ b/src/dsd_mbe.c
|
|
||||||
@@ -1191,7 +1191,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|
||||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
|
||||||
{
|
|
||||||
//write wav to per call on left channel Slot 1
|
|
||||||
- writeSynthesizedVoice (opts, state);
|
|
||||||
+ if (opts->wav_out_f != NULL)
|
|
||||||
+ writeSynthesizedVoice (opts, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1201,7 +1202,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|
||||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
|
||||||
{
|
|
||||||
//write wav to per call on right channel Slot 2
|
|
||||||
- writeSynthesizedVoiceR (opts, state);
|
|
||||||
+ if (opts->wav_out_fR != NULL)
|
|
||||||
+ writeSynthesizedVoiceR (opts, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..ab5497e 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -999,7 +999,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (choicec == 12)
|
|
||||||
{
|
|
||||||
//flesh out all closewavs and sprint "" wav filenames
|
|
||||||
- closeWavOutFile (opts, state);
|
|
||||||
+ // closeWavOutFile (opts, state);
|
|
||||||
closeWavOutFileL (opts, state);
|
|
||||||
closeWavOutFileR (opts, state);
|
|
||||||
//closeWavOutFileRaw (opts, state);
|
|
||||||
@@ -2063,6 +2063,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (opts->dmr_stereo_wav == 1 && src != 0 ) //&& tgn != 0, some TG can be 0 on NXDN
|
|
||||||
{
|
|
||||||
//close old first, assign name based on time and radio, open wav file
|
|
||||||
+ if (opts->wav_out_f != NULL)
|
|
||||||
closeWavOutFileL (opts, state);
|
|
||||||
sprintf (opts->wav_out_file, "./%s/%s %s NXDN - RAN %d - TGT %d - SRC %d.wav", opts->wav_out_dir, getDateN(), timestr, rn, tgn, src);
|
|
||||||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
@@ -2105,13 +2106,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
call_matrix[9][5] = time(NULL);
|
|
||||||
|
|
||||||
//open wav file if enabled and both rd and tg are not 0
|
|
||||||
- if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
- {
|
|
||||||
- //close old first, assign name based on time and radio, open wav file
|
|
||||||
- closeWavOutFileL (opts, state);
|
|
||||||
- sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
- openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
- }
|
|
||||||
+ // if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //close old first, assign name based on time and radio, open wav file
|
|
||||||
+ // if (opts->wav_out_f != NULL)
|
|
||||||
+ // closeWavOutFileL (opts, state);
|
|
||||||
+ // sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
+ // openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
|
||||||
{
|
|
||||||
@@ -2126,7 +2128,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
//DMR BS Slot 1 - matrix 0-4
|
|
||||||
- if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) )
|
|
||||||
+ if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 ) ) //|| lls == 35 || lls == 36
|
|
||||||
{
|
|
||||||
|
|
||||||
for (short int k = 0; k < 4; k++)
|
|
||||||
@@ -2147,14 +2149,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
call_matrix[4][5] = time(NULL);
|
|
||||||
|
|
||||||
//open wav file if enabled and both rd and tg are not 0
|
|
||||||
- if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
- {
|
|
||||||
- //close old first, assign name based on time and radio, open wav file
|
|
||||||
- closeWavOutFileL (opts, state);
|
|
||||||
-
|
|
||||||
- sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
- openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
- }
|
|
||||||
+ // if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //close old first, assign name based on time and radio, open wav file
|
|
||||||
+ // if (opts->wav_out_f != NULL)
|
|
||||||
+ // closeWavOutFileL (opts, state);
|
|
||||||
+ // sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
+ // openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
|
||||||
{
|
|
||||||
@@ -2190,20 +2192,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
call_matrix[9][5] = time(NULL);
|
|
||||||
|
|
||||||
//open wav file if enabled and both rdR and tgR are not 0
|
|
||||||
- if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
|
||||||
- {
|
|
||||||
- //close old first, assign name based on time and radio, open wav file
|
|
||||||
- closeWavOutFileR (opts, state);
|
|
||||||
- sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tgR, rdR);
|
|
||||||
- openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
|
||||||
- }
|
|
||||||
+ // if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //close old first, assign name based on time and radio, open wav file
|
|
||||||
+ // if (opts->wav_out_fR != NULL)
|
|
||||||
+ // closeWavOutFileR (opts, state);
|
|
||||||
+ // sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateN(), timestr, dcc, tgR, rdR);
|
|
||||||
+ // openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
- if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
|
||||||
- {
|
|
||||||
- //fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
|
||||||
- beeper (opts, state, 1);
|
|
||||||
- state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
|
||||||
- }
|
|
||||||
+ // if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
|
||||||
+ // beeper (opts, state, 1);
|
|
||||||
+ // state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
memset(state->dmr_alias_block_segment[1], 0, sizeof(state->dmr_alias_block_segment[1]));
|
|
||||||
sprintf (state->dmr_embedded_gps[1], "%s", "");
|
|
||||||
@@ -2275,7 +2278,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (opts->ncurses_compact == 1)
|
|
||||||
{
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
- printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231015)");
|
|
||||||
+ printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231214)");
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
}
|
|
||||||
#elif LIMAZULUTWEAKS
|
|
||||||
@@ -2313,13 +2316,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2");
|
|
||||||
#endif
|
|
||||||
#ifdef AERO_BUILD
|
|
||||||
- if (i == 5) printw (" %s ", "Aero Build");
|
|
||||||
- if (i == 6) printw (" AW (20231015) \n");
|
|
||||||
+ if (i == 5) printw (" %s ", "G Build");
|
|
||||||
+ if (i == 6) printw (" AW (20231214) \n");
|
|
||||||
#elif ZDEV_BUILD
|
|
||||||
- if (i == 5) printw (" %s ", "AW ");
|
|
||||||
+ if (i == 5) printw (" %s ", "AW G Build");
|
|
||||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
|
||||||
#else
|
|
||||||
- if (i == 5) printw (" %s ", "AW ");
|
|
||||||
+ if (i == 5) printw (" %s ", "AW G Build");
|
|
||||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
|
||||||
#endif
|
|
||||||
else printw ("\n");
|
|
||||||
@@ -3913,7 +3916,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (c == 112) //'p' key - stop all per call wav files
|
|
||||||
{
|
|
||||||
//hope this one doesn't cause random crashing or garbage writing
|
|
||||||
- closeWavOutFile (opts, state);
|
|
||||||
+ // closeWavOutFile (opts, state);
|
|
||||||
closeWavOutFileL (opts, state);
|
|
||||||
closeWavOutFileR (opts, state);
|
|
||||||
sprintf (opts->wav_out_file, "%s", "");
|
|
||||||
@@ -1,769 +0,0 @@
|
|||||||
diff --git a/include/dsd.h b/include/dsd.h
|
|
||||||
index 0b47dee..f459528 100644
|
|
||||||
--- a/include/dsd.h
|
|
||||||
+++ b/include/dsd.h
|
|
||||||
@@ -437,8 +437,8 @@ typedef struct
|
|
||||||
//new stereo short sample storage
|
|
||||||
short s_l[160]; //single sample left
|
|
||||||
short s_r[160]; //single sample right
|
|
||||||
- short s_l4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
- short s_r4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
+ short s_l4[36][160]; //quad sample for up to a P25p2 4V
|
|
||||||
+ short s_r4[36][160]; //quad sample for up to a P25p2 4V
|
|
||||||
//new stereo short sample storage tapped from 48_k internal upsampling
|
|
||||||
short s_lu[160*6]; //single sample left
|
|
||||||
short s_ru[160*6]; //single sample right
|
|
||||||
@@ -654,6 +654,7 @@ typedef struct
|
|
||||||
int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS)
|
|
||||||
int ess_b[2][96]; //external storage for ESS_B fragments
|
|
||||||
int fourv_counter[2]; //external reference counter for ESS_B fragment collection
|
|
||||||
+ int voice_counter[2]; //external reference counter for 18V x 2 P25p2 Superframe
|
|
||||||
int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch
|
|
||||||
|
|
||||||
//iden freq storage for frequency calculations
|
|
||||||
@@ -926,6 +927,7 @@ void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //floa
|
|
||||||
void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix
|
|
||||||
void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR
|
|
||||||
void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2
|
|
||||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state); //short stereo mix 18V Superframe
|
|
||||||
void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short
|
|
||||||
//
|
|
||||||
void openAudioOutDevice (dsd_opts * opts, int speed);
|
|
||||||
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
|
|
||||||
index a836afc..5eaf3c4 100644
|
|
||||||
--- a/src/dsd_audio2.c
|
|
||||||
+++ b/src/dsd_audio2.c
|
|
||||||
@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+//short stereo mix 18v superframe
|
|
||||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
|
|
||||||
+{
|
|
||||||
+
|
|
||||||
+ //NOTE: This will run once every superframe during a sacch field
|
|
||||||
+ //exact implementation to be determined
|
|
||||||
+
|
|
||||||
+ int i, j;
|
|
||||||
+ uint8_t encL, encR;
|
|
||||||
+
|
|
||||||
+ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe
|
|
||||||
+ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short)
|
|
||||||
+ memset (stereo_sf, 1, sizeof(stereo_sf));
|
|
||||||
+
|
|
||||||
+ short empty[320];
|
|
||||||
+ memset (empty, 1, sizeof(empty));
|
|
||||||
+
|
|
||||||
+ //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
|
||||||
+ encL = encR = 1;
|
|
||||||
+ if (state->payload_algid == 0 || state->payload_algid == 0x80)
|
|
||||||
+ encL = 0;
|
|
||||||
+ if (state->payload_algidR == 0 || state->payload_algidR == 0x80)
|
|
||||||
+ encR = 0;
|
|
||||||
+
|
|
||||||
+ //checkdown to see if we can lift the 'mute' if a key is available
|
|
||||||
+ if (encL)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algid == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->R != 0)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (encR)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algidR == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->RR != 0)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ //TODO: add option to bypass enc with a toggle as well
|
|
||||||
+
|
|
||||||
+ //CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
+ //as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
+ //its not really 'disabled', we just aren't playing it
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //WIP: Mute if on B list (or not W list)
|
|
||||||
+ char modeL[8];
|
|
||||||
+ sprintf (modeL, "%s", "");
|
|
||||||
+ char modeR[8];
|
|
||||||
+ sprintf (modeR, "%s", "");
|
|
||||||
+
|
|
||||||
+ int TGL = state->lasttg;
|
|
||||||
+ int TGR = state->lasttgR;
|
|
||||||
+
|
|
||||||
+ //if we are using allow/whitelist mode, then write 'B' to mode for block
|
|
||||||
+ //comparison below will look for an 'A' to write to mode if it is allowed
|
|
||||||
+ if (opts->trunk_use_allow_list == 1)
|
|
||||||
+ {
|
|
||||||
+ sprintf (modeL, "%s", "B");
|
|
||||||
+ sprintf (modeR, "%s", "B");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < state->group_tally; i++)
|
|
||||||
+ {
|
|
||||||
+ if (state->group_array[i].groupNumber == TGL)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeL, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ if (state->group_array[i].groupNumber == TGR)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeR, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //flag either left or right as 'enc' to mute if B
|
|
||||||
+ if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
+ if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //if TG Hold in place, mute anything but that TG #132
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions
|
|
||||||
+ if (encL && encR)
|
|
||||||
+ goto SS18_END;
|
|
||||||
+
|
|
||||||
+ //interleave left and right channels from the short storage area
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ for (i = 0; i < 160; i++)
|
|
||||||
+ {
|
|
||||||
+ if (!encL)
|
|
||||||
+ stereo_sf[j][i*2+0] = state->s_l4[j][i];
|
|
||||||
+ if (!encR)
|
|
||||||
+ stereo_sf[j][i*2+1] = state->s_r4[j][i];
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 0) //Pulse Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 8) //UDP Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ write (opts->audio_out_fd, stereo_sf[j], 320*2);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ SS18_END:
|
|
||||||
+
|
|
||||||
+ //run cleanup since we pulled stuff from processAudio
|
|
||||||
+ state->audio_out_idx = 0;
|
|
||||||
+ state->audio_out_idxR = 0;
|
|
||||||
+
|
|
||||||
+ //set float temp buffer to baseline
|
|
||||||
+ memset (state->s_l4, 1, sizeof(state->s_l4));
|
|
||||||
+ memset (state->s_r4, 1, sizeof(state->s_r4));
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2 >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
+ state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
+ memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2 = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2R >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
+ state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
+ memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2R = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
//largely borrowed from Boatbod OP25 (simplified single tone ID version)
|
|
||||||
void soft_tonef (float samp[160], int n, int ID, int AD)
|
|
||||||
{
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 1d2616b..02590a6 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -382,6 +382,8 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
}
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
//values displayed in ncurses terminal
|
|
||||||
// state->p25_vc_freq[0] = 0;
|
|
||||||
@@ -745,7 +747,7 @@ initOpts (dsd_opts * opts)
|
|
||||||
//slot preference is used during OSS audio playback to
|
|
||||||
//prefer one tdma voice slot over another when both are playing back
|
|
||||||
//this is a fix to OSS 48k/1 output
|
|
||||||
- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
+ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
|
|
||||||
//hardset slots to synthesize
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
@@ -941,6 +943,8 @@ initState (dsd_state * state)
|
|
||||||
}
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
state->K = 0;
|
|
||||||
state->R = 0;
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..fc3f28b 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2);
|
|
||||||
if (opts->slot1_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot1_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R);
|
|
||||||
if (opts->slot2_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot2_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
}
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot1_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot_preference = 1; //slot 2
|
|
||||||
+ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 1; //slot 2
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot2_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- opts->slot_preference = 0; //slot 1
|
|
||||||
+ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 0; //slot 1
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (c == 51) //'3' key, cycle slot preferences
|
|
||||||
+ {
|
|
||||||
+ if (opts->slot_preference < 2)
|
|
||||||
+ opts->slot_preference++;
|
|
||||||
+ else opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (c == 43) //+ key, increment audio_gain
|
|
||||||
{
|
|
||||||
|
|
||||||
diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c
|
|
||||||
index c391eba..99a4840 100644
|
|
||||||
--- a/src/p25p2_frame.c
|
|
||||||
+++ b/src/p25p2_frame.c
|
|
||||||
@@ -490,18 +490,27 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
// else state->dmrburstR = 21;
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
+
|
|
||||||
+ //unsure of the best location for these counter resets
|
|
||||||
+ if (state->voice_counter[0] >= 18)
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+
|
|
||||||
+ if (state->voice_counter[1] >= 18)
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -509,13 +518,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -523,13 +534,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -537,13 +550,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[3], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[3], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[3], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[3], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -709,17 +724,26 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
+ //unsure of the best location for these counter resets
|
|
||||||
+ if (state->voice_counter[0] >= 18)
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+
|
|
||||||
+ if (state->voice_counter[1] >= 18)
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
+
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -727,17 +751,19 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
-
|
|
||||||
+ // if (state->currentslot == 0) state->voice_counter[0] = 0; if (state->currentslot == 1) state->voice_counter[1] = 0;
|
|
||||||
process_ESS(opts, state);
|
|
||||||
|
|
||||||
//reset drop bytes after a 2V
|
|
||||||
@@ -930,6 +956,8 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|
||||||
state->p2_is_lcch = 0;
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
goto END;
|
|
||||||
}
|
|
||||||
@@ -949,8 +977,32 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceFS4 (opts, state);
|
|
||||||
|
|
||||||
- if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
- playSynthesizedVoiceSS4 (opts, state);
|
|
||||||
+ // if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
+ // playSynthesizedVoiceSS4 (opts, state);
|
|
||||||
+
|
|
||||||
+ // fprintf (stderr, " VCH0: %d;", state->voice_counter[0]); //debug
|
|
||||||
+ // fprintf (stderr, " VCH1: %d;", state->voice_counter[1]); //debug
|
|
||||||
+
|
|
||||||
+ //this works, but may still have an element of 'dual voice stutter' which was my initial complaint, but shouldn't 'lag' during trunking operations (hopefully)
|
|
||||||
+ if ( (state->voice_counter[0] >= 18 || state->voice_counter[1] >= 18 ) && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
|
||||||
+ {
|
|
||||||
+ playSynthesizedVoiceSS18 (opts, state);
|
|
||||||
+ state->voice_counter[0] = 0; //reset
|
|
||||||
+ state->voice_counter[1] = 0; //reset
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //these two will work, but NOT at the same time on dual voice
|
|
||||||
+ // if (state->voice_counter[0] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
|
||||||
+ // {
|
|
||||||
+ // playSynthesizedVoiceSS18 (opts, state);
|
|
||||||
+ // state->voice_counter[0] = 0; //reset
|
|
||||||
+ // }
|
|
||||||
+
|
|
||||||
+ // if (state->voice_counter[1] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
|
||||||
+ // {
|
|
||||||
+ // playSynthesizedVoiceSS18 (opts, state);
|
|
||||||
+ // state->voice_counter[1] = 0; //reset
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
//debug: fix burst indicator for ncurses if marginal signal
|
|
||||||
// if (voice)
|
|
||||||
diff --git a/src/p25p2_xcch.c b/src/p25p2_xcch.c
|
|
||||||
index 101d1e4..847fe71 100644
|
|
||||||
--- a/src/p25p2_xcch.c
|
|
||||||
+++ b/src/p25p2_xcch.c
|
|
||||||
@@ -122,6 +122,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
|
|
||||||
state->dmrburstL = 20;
|
|
||||||
@@ -171,6 +172,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
state->payload_algidR = 0; //zero this out as well
|
|
||||||
|
|
||||||
@@ -230,6 +232,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
state->dmrburstL = 23;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
@@ -258,6 +261,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
state->dmrburstR = 23;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
@@ -498,6 +502,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
|
|
||||||
state->dmrburstL = 20;
|
|
||||||
@@ -538,6 +543,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
|
|
||||||
state->dmrburstR = 20;
|
|
||||||
@@ -594,6 +600,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
state->dmrburstL = 23;
|
|
||||||
state->payload_algid = 0; //zero this out as well
|
|
||||||
@@ -622,6 +629,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
state->dmrburstR = 23;
|
|
||||||
state->payload_algidR = 0; //zero this out as well
|
|
||||||
@@ -723,6 +731,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->dmrburstL = 24;
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->lasttg = 0;
|
|
||||||
|
|
||||||
@@ -733,6 +742,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
state->payload_keyidR = 0;
|
|
||||||
state->dmrburstR = 24;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->lastsrcR = 0;
|
|
||||||
state->lasttgR = 0;
|
|
||||||
|
|
||||||
@@ -1,452 +0,0 @@
|
|||||||
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
|
|
||||||
index a836afc..5eaf3c4 100644
|
|
||||||
--- a/src/dsd_audio2.c
|
|
||||||
+++ b/src/dsd_audio2.c
|
|
||||||
@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+//short stereo mix 18v superframe
|
|
||||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
|
|
||||||
+{
|
|
||||||
+
|
|
||||||
+ //NOTE: This will run once every superframe during a sacch field
|
|
||||||
+ //exact implementation to be determined
|
|
||||||
+
|
|
||||||
+ int i, j;
|
|
||||||
+ uint8_t encL, encR;
|
|
||||||
+
|
|
||||||
+ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe
|
|
||||||
+ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short)
|
|
||||||
+ memset (stereo_sf, 1, sizeof(stereo_sf));
|
|
||||||
+
|
|
||||||
+ short empty[320];
|
|
||||||
+ memset (empty, 1, sizeof(empty));
|
|
||||||
+
|
|
||||||
+ //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
|
||||||
+ encL = encR = 1;
|
|
||||||
+ if (state->payload_algid == 0 || state->payload_algid == 0x80)
|
|
||||||
+ encL = 0;
|
|
||||||
+ if (state->payload_algidR == 0 || state->payload_algidR == 0x80)
|
|
||||||
+ encR = 0;
|
|
||||||
+
|
|
||||||
+ //checkdown to see if we can lift the 'mute' if a key is available
|
|
||||||
+ if (encL)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algid == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->R != 0)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (encR)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algidR == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->RR != 0)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ //TODO: add option to bypass enc with a toggle as well
|
|
||||||
+
|
|
||||||
+ //CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
+ //as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
+ //its not really 'disabled', we just aren't playing it
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //WIP: Mute if on B list (or not W list)
|
|
||||||
+ char modeL[8];
|
|
||||||
+ sprintf (modeL, "%s", "");
|
|
||||||
+ char modeR[8];
|
|
||||||
+ sprintf (modeR, "%s", "");
|
|
||||||
+
|
|
||||||
+ int TGL = state->lasttg;
|
|
||||||
+ int TGR = state->lasttgR;
|
|
||||||
+
|
|
||||||
+ //if we are using allow/whitelist mode, then write 'B' to mode for block
|
|
||||||
+ //comparison below will look for an 'A' to write to mode if it is allowed
|
|
||||||
+ if (opts->trunk_use_allow_list == 1)
|
|
||||||
+ {
|
|
||||||
+ sprintf (modeL, "%s", "B");
|
|
||||||
+ sprintf (modeR, "%s", "B");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < state->group_tally; i++)
|
|
||||||
+ {
|
|
||||||
+ if (state->group_array[i].groupNumber == TGL)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeL, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ if (state->group_array[i].groupNumber == TGR)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeR, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //flag either left or right as 'enc' to mute if B
|
|
||||||
+ if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
+ if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //if TG Hold in place, mute anything but that TG #132
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions
|
|
||||||
+ if (encL && encR)
|
|
||||||
+ goto SS18_END;
|
|
||||||
+
|
|
||||||
+ //interleave left and right channels from the short storage area
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ for (i = 0; i < 160; i++)
|
|
||||||
+ {
|
|
||||||
+ if (!encL)
|
|
||||||
+ stereo_sf[j][i*2+0] = state->s_l4[j][i];
|
|
||||||
+ if (!encR)
|
|
||||||
+ stereo_sf[j][i*2+1] = state->s_r4[j][i];
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 0) //Pulse Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 8) //UDP Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ write (opts->audio_out_fd, stereo_sf[j], 320*2);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ SS18_END:
|
|
||||||
+
|
|
||||||
+ //run cleanup since we pulled stuff from processAudio
|
|
||||||
+ state->audio_out_idx = 0;
|
|
||||||
+ state->audio_out_idxR = 0;
|
|
||||||
+
|
|
||||||
+ //set float temp buffer to baseline
|
|
||||||
+ memset (state->s_l4, 1, sizeof(state->s_l4));
|
|
||||||
+ memset (state->s_r4, 1, sizeof(state->s_r4));
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2 >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
+ state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
+ memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2 = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2R >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
+ state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
+ memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2R = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
//largely borrowed from Boatbod OP25 (simplified single tone ID version)
|
|
||||||
void soft_tonef (float samp[160], int n, int ID, int AD)
|
|
||||||
{
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 1d2616b..924bf00 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -745,7 +745,7 @@ initOpts (dsd_opts * opts)
|
|
||||||
//slot preference is used during OSS audio playback to
|
|
||||||
//prefer one tdma voice slot over another when both are playing back
|
|
||||||
//this is a fix to OSS 48k/1 output
|
|
||||||
- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
+ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
|
|
||||||
//hardset slots to synthesize
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..fc3f28b 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2);
|
|
||||||
if (opts->slot1_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot1_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R);
|
|
||||||
if (opts->slot2_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot2_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
}
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot1_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot_preference = 1; //slot 2
|
|
||||||
+ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 1; //slot 2
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot2_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- opts->slot_preference = 0; //slot 1
|
|
||||||
+ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 0; //slot 1
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (c == 51) //'3' key, cycle slot preferences
|
|
||||||
+ {
|
|
||||||
+ if (opts->slot_preference < 2)
|
|
||||||
+ opts->slot_preference++;
|
|
||||||
+ else opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (c == 43) //+ key, increment audio_gain
|
|
||||||
{
|
|
||||||
|
|
||||||
11
rebuild.sh
11
rebuild.sh
@@ -1,8 +1,8 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
#
|
|
||||||
clear
|
clear
|
||||||
printf "DSD-FME Digital Speech Decoder - Florida Man Edition
|
echo DSD-FME Digital Speech Decoder - Florida Man Edition
|
||||||
Automatic Git Pull and Rebuild\n\n"
|
echo Automatic Git Pull and Rebuild
|
||||||
|
echo
|
||||||
sleep 1
|
sleep 1
|
||||||
##Open your clone folder##
|
##Open your clone folder##
|
||||||
git pull
|
git pull
|
||||||
@@ -10,6 +10,7 @@ sleep 2
|
|||||||
##cd into your build folder##
|
##cd into your build folder##
|
||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
make -j $(nproc)
|
make -j `nproc`
|
||||||
sudo make install
|
sudo make install
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
|
|
||||||
|
|||||||
7
src/1.c
7
src/1.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 1.c
|
|
||||||
* Placeholder File 1 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
7
src/2.c
7
src/2.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 2.c
|
|
||||||
* Placeholder File 2 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
87
src/3.c
87
src/3.c
@@ -1,87 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 3.c
|
|
||||||
* Placeholder File 3 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
* A 1/2 Rate Convolutional Decoder for NXDN/M17/YSF
|
|
||||||
* Used as a secondary decoder in case convolutional decoder fails (second opinion)
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
|
|
||||||
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};
|
|
||||||
|
|
||||||
// trellis_1_2 encode: source is in bits, result in bits
|
|
||||||
void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg)
|
|
||||||
{
|
|
||||||
for (int i=0; i<result_len; i+=2) {
|
|
||||||
reg = (reg << 1) | source[i>>1];
|
|
||||||
result[i] = PARITY[reg & 0x19];
|
|
||||||
result[i+1] = PARITY[reg & 0x17];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// simplified trellis 2:1 decode; source and result in bits
|
|
||||||
// assumes that encoding was done with NTEST trailing zero bits
|
|
||||||
// result_len should be set to the actual number of data bits
|
|
||||||
// in the original unencoded message (excl. these trailing bits)
|
|
||||||
void trellis_decode(uint8_t result[], const uint8_t source[], int result_len)
|
|
||||||
{
|
|
||||||
int reg = 0;
|
|
||||||
int min_d;
|
|
||||||
int min_bt;
|
|
||||||
static const int NTEST = 4;
|
|
||||||
static const int NTESTC = 1 << NTEST;
|
|
||||||
uint8_t bt[NTEST];
|
|
||||||
uint8_t tt[NTEST*2];
|
|
||||||
int dstats[4];
|
|
||||||
int sum;
|
|
||||||
for (int p=0; p < 4; p++)
|
|
||||||
dstats[p] = 0;
|
|
||||||
for (int p=0; p < result_len; p++) {
|
|
||||||
for (int i=0; i<NTESTC; i++) {
|
|
||||||
bt[0] = (i&8)>>3;
|
|
||||||
bt[1] = (i&4)>>2;
|
|
||||||
bt[2] = (i&2)>>1;
|
|
||||||
bt[3] = (i&1);
|
|
||||||
trellis_encode(tt, bt, NTEST*2, reg);
|
|
||||||
sum=0;
|
|
||||||
for (int j=0; j<NTEST*2; j++) {
|
|
||||||
sum += tt[j] ^ source[p*2+j];
|
|
||||||
}
|
|
||||||
if (i == 0 || sum < min_d) {
|
|
||||||
min_d = sum;
|
|
||||||
min_bt = bt[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result[p] = min_bt;
|
|
||||||
reg = (reg << 1) | min_bt;
|
|
||||||
dstats[(min_d > 3) ? 3 : min_d] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug output
|
|
||||||
// fprintf (stderr, "\n stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Original Copyright/License
|
|
||||||
|
|
||||||
/* -*- c++ -*- */
|
|
||||||
/*
|
|
||||||
* NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI
|
|
||||||
*
|
|
||||||
* This file is part of OP25
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
7
src/4.c
7
src/4.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 4.c
|
|
||||||
* Placeholder File 4 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
7
src/5.c
7
src/5.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 5.c
|
|
||||||
* Placeholder File 5 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
214
src/dmr_34.c
214
src/dmr_34.c
@@ -1,214 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* dmr_34.c
|
|
||||||
* DMR (and P25) 3/4 Rate Simple Trellis Decoder
|
|
||||||
*
|
|
||||||
* LWVMOBILE
|
|
||||||
* 2023-12 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 constellation 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};
|
|
||||||
|
|
||||||
//attempt to find the surviving path, or the 'best' path available (most positions gained)
|
|
||||||
uint8_t fix_34(uint8_t * p, uint8_t state, int position)
|
|
||||||
{
|
|
||||||
int i, j, k, counter, best_p, best_v, survivors;
|
|
||||||
uint8_t temp_s, tri, t;
|
|
||||||
|
|
||||||
//status of surviving paths -- debug
|
|
||||||
int s[8];
|
|
||||||
memset (s, 0, 8*sizeof(int));
|
|
||||||
|
|
||||||
//assign all potentially correct points to temporary storage
|
|
||||||
uint8_t temp_p[8];
|
|
||||||
temp_p[0] = (p[position] ^ 1) & 0xF;
|
|
||||||
temp_p[1] = (p[position] ^ 3) & 0xF;
|
|
||||||
temp_p[2] = (p[position] ^ 5) & 0xF;
|
|
||||||
temp_p[3] = (p[position] ^ 7) & 0xF;
|
|
||||||
temp_p[4] = (p[position] ^ 9) & 0xF;
|
|
||||||
temp_p[5] = (p[position] ^ 11) & 0xF;
|
|
||||||
temp_p[6] = (p[position] ^ 13) & 0xF;
|
|
||||||
temp_p[7] = (p[position] ^ 15) & 0xF;
|
|
||||||
|
|
||||||
best_p = 0; //best position
|
|
||||||
best_v = 0; //best path value
|
|
||||||
|
|
||||||
for (k = 0; k < 8; k++)
|
|
||||||
{
|
|
||||||
temp_s = state;
|
|
||||||
counter = 0;
|
|
||||||
tri = 0;
|
|
||||||
for (i = position; i < 49; i++)
|
|
||||||
{
|
|
||||||
//assign temp t either as our temp_p, or next point of i
|
|
||||||
if (i == position) t = temp_p[k];
|
|
||||||
else t = p[i];
|
|
||||||
|
|
||||||
if (tri != 0xFF) //while the path survives
|
|
||||||
{
|
|
||||||
tri = 0xFF;
|
|
||||||
for (j = 0; j < 8; j++)
|
|
||||||
{
|
|
||||||
if ( fsm[(temp_s*8)+j] == t )
|
|
||||||
{
|
|
||||||
//return our tribit value and state for the next point
|
|
||||||
tri = temp_s = (uint8_t)j;
|
|
||||||
counter++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (counter > best_p)
|
|
||||||
{
|
|
||||||
best_p = counter;
|
|
||||||
best_v = k; //if we make it further on current path, assign as best path
|
|
||||||
}
|
|
||||||
|
|
||||||
// surviving path -- made it to 49
|
|
||||||
if (i == 48) s[k] = 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOTE: If there are no surviving paths, then that means there is another bit/point err
|
|
||||||
//Ideally, at the end of a single or multiple fixes, there should only be one survivor, but in practice,
|
|
||||||
//I've seen up to 4 surviving paths and somehow, get a good CRC and a good LRRP or LOCN decode
|
|
||||||
//multiple survivors seems common when the starting err position is very close to 49
|
|
||||||
|
|
||||||
//tally number of surviving paths
|
|
||||||
survivors = 0;
|
|
||||||
for (k = 0; k < 8; k++)
|
|
||||||
{
|
|
||||||
if (s[k] == 1) survivors++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, "START: %d; BEST_P: %d; BEST_V: %d; Survivors: %d; Point: %d; ", position, best_p, best_v, survivors, temp_p[best_v]);
|
|
||||||
|
|
||||||
return temp_p[best_v]; //return the point value of the best path's starting point value
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18])
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
uint32_t irr_err = 0; //irrecoverable errors
|
|
||||||
|
|
||||||
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
|
|
||||||
// fprintf (stderr, "\n P =");
|
|
||||||
// for (i = 0; i < 49; i++)
|
|
||||||
// fprintf (stderr, " %02d", point[i]);
|
|
||||||
|
|
||||||
//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 point, position of error, and state value
|
|
||||||
// fprintf (stderr, "\n P: %d, %d:%d; ", point[i], i, state);
|
|
||||||
|
|
||||||
//attempt to fix point by looking for the best path from here
|
|
||||||
point[i] = fix_34(point, state, i);
|
|
||||||
|
|
||||||
//Make a hard decision and flip point to fit in current state
|
|
||||||
// point[i] ^= 7; //lucky number 7 (0111) //fallback
|
|
||||||
|
|
||||||
//decrement one and resume decoding
|
|
||||||
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;
|
|
||||||
|
|
||||||
//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, " P_ERR = %d", irr_err);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
379
src/dmr_block.c
379
src/dmr_block.c
@@ -12,11 +12,11 @@
|
|||||||
void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i;
|
uint32_t i, j, k;
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
|
|
||||||
//clear out unified pdu 'superframe' slot
|
//clear out unified pdu 'superframe' slot
|
||||||
for (int i = 0; i < 24*127; i++) state->dmr_pdu_sf[slot][i] = 0;
|
for (short int i = 0; i < 288; i++) state->dmr_pdu_sf[slot][i] = 0;
|
||||||
|
|
||||||
//reset block counter to 1
|
//reset block counter to 1
|
||||||
state->data_block_counter[slot] = 1;
|
state->data_block_counter[slot] = 1;
|
||||||
@@ -29,10 +29,8 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
uint8_t ab = (uint8_t)ConvertBitIntoBytes(&dheader_bits[2], 2); //appended blocks
|
uint8_t ab = (uint8_t)ConvertBitIntoBytes(&dheader_bits[2], 2); //appended blocks
|
||||||
uint8_t dpf = (uint8_t)ConvertBitIntoBytes(&dheader_bits[4], 4); //data packet format
|
uint8_t dpf = (uint8_t)ConvertBitIntoBytes(&dheader_bits[4], 4); //data packet format
|
||||||
uint8_t sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 4); //service access point
|
uint8_t sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 4); //service access point
|
||||||
uint8_t mpoc = dheader_bits[3]; //most significant bit of the 5-bit Pad Octet Count
|
uint8_t poc = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 4); //padding octets
|
||||||
uint8_t poc = (uint8_t)ConvertBitIntoBytes(&dheader_bits[12], 4) + (mpoc << 4); //padding octets
|
|
||||||
UNUSED(ab);
|
|
||||||
|
|
||||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid
|
uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid
|
||||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid
|
uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid
|
||||||
|
|
||||||
@@ -119,21 +117,10 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
uint8_t udt_pf = dheader_bits[73];
|
uint8_t udt_pf = dheader_bits[73];
|
||||||
uint8_t udt_op = (uint8_t)ConvertBitIntoBytes(&dheader_bits[74], 6);
|
uint8_t udt_op = (uint8_t)ConvertBitIntoBytes(&dheader_bits[74], 6);
|
||||||
|
|
||||||
//ETSI TS 102 361-4 V1.12.1 (2023-07) p281
|
|
||||||
udt_uab += 1; //add 1 internally, up to 4 appended blocks are carried, min is 1
|
|
||||||
|
|
||||||
//NMEA Specific Fix for unspecified MFID format w/ 2 appended blocks (UAB 2) p291
|
|
||||||
if (udt_uab == 0x5 && udt_uab == 3)
|
|
||||||
udt_uab = 2; //set to two if long unspecified format
|
|
||||||
|
|
||||||
//Note: NMEA Reserved value UAB 3 is not referenced in ETSI, so unknown number of
|
|
||||||
//appended blocks but we will assume it is supposed to be 4 appended blocks
|
|
||||||
|
|
||||||
//p_head
|
//p_head
|
||||||
uint8_t p_sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[0], 4);
|
uint8_t p_sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[0], 4);
|
||||||
uint8_t p_mfid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8);
|
uint8_t p_mfid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8);
|
||||||
uint8_t p_pot = (uint8_t)ConvertBitIntoBytes(&dheader_bits[3], 5); //looking for LRRP pot_report
|
uint8_t p_pot = (uint8_t)ConvertBitIntoBytes(&dheader_bits[3], 5); //looking for LRRP pot_report
|
||||||
UNUSED(p_pot);
|
|
||||||
|
|
||||||
fprintf (stderr, "%s ", KGRN);
|
fprintf (stderr, "%s ", KGRN);
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
@@ -195,7 +182,6 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
else if (udt_format == 0x08) sprintf (udtf_string, "%s", "Manu Spec"); //Manufacturer Specific
|
else if (udt_format == 0x08) sprintf (udtf_string, "%s", "Manu Spec"); //Manufacturer Specific
|
||||||
else if (udt_format == 0x09) sprintf (udtf_string, "%s", "Manu Spec"); //Manufacturer Specific
|
else if (udt_format == 0x09) sprintf (udtf_string, "%s", "Manu Spec"); //Manufacturer Specific
|
||||||
else if (udt_format == 0x0A) sprintf (udtf_string, "%s", "Mixed UTF"); //Appended block contains addr and 16-bit UTF-16BE
|
else if (udt_format == 0x0A) sprintf (udtf_string, "%s", "Mixed UTF"); //Appended block contains addr and 16-bit UTF-16BE
|
||||||
else if (udt_format == 0x0B) sprintf (udtf_string, "%s", "LIP LOCN");
|
|
||||||
else sprintf (udtf_string, "%s", "Reserved");
|
else sprintf (udtf_string, "%s", "Reserved");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,9 +228,6 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
//set data header to valid
|
//set data header to valid
|
||||||
state->data_header_valid[slot] = 1;
|
state->data_header_valid[slot] = 1;
|
||||||
|
|
||||||
//reset block counter to zero
|
|
||||||
state->data_block_counter[slot] = 0;
|
|
||||||
|
|
||||||
//send to assembler as type 3, rearrange into CSBK type PDU (to verify), and send to dmr_cspdu
|
//send to assembler as type 3, rearrange into CSBK type PDU (to verify), and send to dmr_cspdu
|
||||||
dmr_block_assembler (opts, state, dheader, 12, 0x0B, 3);
|
dmr_block_assembler (opts, state, dheader, 12, 0x0B, 3);
|
||||||
|
|
||||||
@@ -315,46 +298,27 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
{
|
{
|
||||||
fprintf (stderr, " - P_SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string);
|
fprintf (stderr, " - P_SAP %02d [%s] - MFID %02X [%s]", p_sap, sap_string, p_mfid, mfid_string);
|
||||||
|
|
||||||
//p_sap 1 on mfid 10 (moto) is a pain, and doesn't assemble correctly for some reason
|
//look for LRRP potential report 0x1F (may be others as well)
|
||||||
//two extra duplicate blocks are transmitted at the end for some reason -- system unique error?
|
//this could just be a sap == 1, which is 'reserved', unsure (or maybe no actual correlation?)
|
||||||
if (p_sap != 1)
|
if (p_sap != 1) state->data_header_blocks[slot]--; //decrement the blocks to follow count in order to pass CRC32 and properly assemble blocks
|
||||||
|
else //add block to start of the dmr_pdu_sf since it probably contains vital LRRP data (0x1F report) -- won't pass CRC32 either way
|
||||||
{
|
{
|
||||||
//sanity check to prevent segfault (this happened when the regular header was not received beforehand)
|
|
||||||
if (state->data_header_blocks[slot] > 1)
|
|
||||||
state->data_header_blocks[slot]--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//this method will assemble with the duplicate blocks and include the header as well
|
|
||||||
// state->data_header_blocks[slot]++;
|
|
||||||
// state->data_header_blocks[slot]++;
|
|
||||||
// int blocks = state->data_header_blocks[slot]-1;
|
|
||||||
// if (blocks > 127) blocks = 127;
|
|
||||||
// if (blocks < 1) blocks = 4; //safety value
|
|
||||||
// for(i = 0; i < 12; i++)
|
|
||||||
// state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i];
|
|
||||||
// state->data_block_counter[slot]++;
|
|
||||||
|
|
||||||
//this method will just include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates
|
|
||||||
int blocks = state->data_header_blocks[slot]-1;
|
int blocks = state->data_header_blocks[slot]-1;
|
||||||
if (blocks > 127) blocks = 127;
|
if (blocks < 1) blocks = 4; //safety value
|
||||||
if (blocks < 1) blocks = 4;
|
if (blocks > 9) blocks = 9;
|
||||||
for(i = 0; i < 12; i++)
|
for(i = 0; i < 12; i++) state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i];
|
||||||
state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i];
|
|
||||||
state->data_block_counter[slot]++;
|
state->data_block_counter[slot]++;
|
||||||
|
//no matter how you assemble this, with or without the p_head block(s), there is ALWAYS a CRC32 Failure
|
||||||
//this method will NOT include the prop_pdu header as a data block and assemble the data blocks as a message, excluding duplicates
|
|
||||||
// state->data_header_blocks[slot]--; UNUSED(i);
|
|
||||||
|
|
||||||
//no matter how you assemble this, with or without the p_head block(s) or extra blocks, there is ALWAYS a CRC32 Failure
|
|
||||||
//even when it continues to pass on other SAP values, SAP 1 must have a different checksum?
|
//even when it continues to pass on other SAP values, SAP 1 must have a different checksum?
|
||||||
//Users trying to get this will want to enable -F to bypass the CRC32 failure
|
//Users trying to get this will want to enable -F to bypass the CRC32 failure
|
||||||
|
|
||||||
|
//a recent discovery on a few systems and samples show the existence of multiple Prop Head Packets (how does that work)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//block storage sanity
|
//block storage sanity
|
||||||
if (state->data_header_blocks[slot] > 127) state->data_header_blocks[slot] = 127;
|
if (state->data_header_blocks[slot] > 9) state->data_header_blocks[slot] = 9;
|
||||||
//assuming we didn't receive the initial data header block on a p_head and then decremented it
|
//assuming we didn't receive the initial data header block on a p_head and then decremented it
|
||||||
//3 or 4 seems to be the average safe value
|
//3 or 4 seems to be the average safe value
|
||||||
if (state->data_header_blocks[slot] < 1) state->data_header_blocks[slot] = 4;
|
if (state->data_header_blocks[slot] < 1) state->data_header_blocks[slot] = 4;
|
||||||
@@ -364,7 +328,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
//REMUS! Uncomment these lines if desired
|
//REMUS! Uncomment these lines if desired
|
||||||
if (dpf != 15 && dpf != 1)
|
if (dpf != 15 && dpf != 1)
|
||||||
{
|
{
|
||||||
sprintf (state->dmr_lrrp_gps[slot], "Data Call - %s TGT: %d SRC: %d ", sap_string, target, source);
|
sprintf (state->dmr_lrrp_gps[slot], "Data Call - %s SRC [%d] DST [%d] ", sap_string, source, target);
|
||||||
if (a == 1) strcat (state->dmr_lrrp_gps[slot], "- RSP REQ ");
|
if (a == 1) strcat (state->dmr_lrrp_gps[slot], "- RSP REQ ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,257 +364,46 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes, uint32_t CRCCorrect)
|
//convert UDT to a CSBK friendly PDU format
|
||||||
|
void dmr_udt_cspdu_converter (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||||
{
|
{
|
||||||
//TODO: double check end rep values to Text Format Modes vs padnibs/uab values
|
|
||||||
//TODO: Make Text Format Modes seperate function to be used more generically by other things
|
|
||||||
//TODO: LIP Format (make seperate functions, LIP also used by USBD)
|
|
||||||
int i, j;
|
int i, j;
|
||||||
UNUSED(CRCCorrect);
|
|
||||||
UNUSED(opts);
|
|
||||||
int slot = state->currentslot;
|
|
||||||
|
|
||||||
uint8_t cs_bits[8*12*5]; //maximum of 1 header and 4 blocks at 96 bits
|
//rearrange UDT data to a CSBK message format
|
||||||
UNUSED(cs_bits);
|
uint8_t cs_byte[48]; //12 x 4, 2 bit AB should mean only 3 total appended blocks, so 4 all together (minus rearrangement)
|
||||||
|
memset (cs_byte, 0, sizeof (cs_byte));
|
||||||
|
uint8_t cs_bits[48*8];
|
||||||
|
memset (cs_bits, 0, sizeof (cs_bits));
|
||||||
|
|
||||||
|
cs_byte[0] = (uint8_t)ConvertBitIntoBytes(&block_bits[73], 7); //lb, pf and opcode byte
|
||||||
|
uint8_t udt_opcode = (uint8_t)ConvertBitIntoBytes(&block_bits[74], 6); //for observation testing
|
||||||
|
cs_byte[1] = 0; //set mfid to zero for now (may use custom value if needed later)
|
||||||
|
uint8_t udt_mfid = 0; //setting to zero
|
||||||
|
|
||||||
|
//should be 34 total (maximum) after removing tailing CRC16 (initial and last block)
|
||||||
|
for (i = 0; i < 34; i++) cs_byte[2+i] = block_bytes[12+i];
|
||||||
|
|
||||||
//bytes to bits
|
//bytes to bits
|
||||||
for(i = 0, j = 0; i < 36; i++, j+=8)
|
for(i = 0, j = 0; i < 36; i++, j+=8) //4 blocks max?
|
||||||
{
|
{
|
||||||
cs_bits[j + 0] = (block_bytes[i] >> 7) & 0x01;
|
cs_bits[j + 0] = (cs_byte[i] >> 7) & 0x01;
|
||||||
cs_bits[j + 1] = (block_bytes[i] >> 6) & 0x01;
|
cs_bits[j + 1] = (cs_byte[i] >> 6) & 0x01;
|
||||||
cs_bits[j + 2] = (block_bytes[i] >> 5) & 0x01;
|
cs_bits[j + 2] = (cs_byte[i] >> 5) & 0x01;
|
||||||
cs_bits[j + 3] = (block_bytes[i] >> 4) & 0x01;
|
cs_bits[j + 3] = (cs_byte[i] >> 4) & 0x01;
|
||||||
cs_bits[j + 4] = (block_bytes[i] >> 3) & 0x01;
|
cs_bits[j + 4] = (cs_byte[i] >> 3) & 0x01;
|
||||||
cs_bits[j + 5] = (block_bytes[i] >> 2) & 0x01;
|
cs_bits[j + 5] = (cs_byte[i] >> 2) & 0x01;
|
||||||
cs_bits[j + 6] = (block_bytes[i] >> 1) & 0x01;
|
cs_bits[j + 6] = (cs_byte[i] >> 1) & 0x01;
|
||||||
cs_bits[j + 7] = (block_bytes[i] >> 0) & 0x01;
|
cs_bits[j + 7] = (cs_byte[i] >> 0) & 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Unified Data Transport (UDT) -- already checked, but may need a few of these here as well
|
dmr_cspdu (opts, state, cs_bits, cs_byte, CRCCorrect, IrrecoverableErrors);
|
||||||
uint8_t udt_ig = cs_bits[0]; //group or individual data
|
|
||||||
uint8_t udt_a = cs_bits[1]; //response required
|
|
||||||
uint8_t udt_res = (uint8_t)ConvertBitIntoBytes(&cs_bits[2], 2);
|
|
||||||
uint8_t udt_format1 = (uint8_t)ConvertBitIntoBytes(&cs_bits[4], 4); //header format of UDT
|
|
||||||
uint8_t udt_sap = (uint8_t)ConvertBitIntoBytes(&cs_bits[8], 4);
|
|
||||||
uint8_t udt_format2 = (uint8_t)ConvertBitIntoBytes(&cs_bits[12], 4); //UDT Format referenced below
|
|
||||||
uint32_t udt_target = (uint32_t)ConvertBitIntoBytes(&cs_bits[16], 24);
|
|
||||||
uint32_t udt_source = (uint32_t)ConvertBitIntoBytes(&cs_bits[40], 24);
|
|
||||||
uint8_t udt_padnib = (uint8_t)ConvertBitIntoBytes(&cs_bits[64], 5);
|
|
||||||
uint8_t udt_zero = cs_bits[69]; //should always be zero?
|
|
||||||
uint8_t udt_uab = (uint8_t)ConvertBitIntoBytes(&cs_bits[70], 2) + 1; //udt appended blocks
|
|
||||||
uint8_t udt_sf = cs_bits[72];
|
|
||||||
uint8_t udt_pf = cs_bits[73];
|
|
||||||
uint8_t udt_op = (uint8_t)ConvertBitIntoBytes(&cs_bits[74], 6);
|
|
||||||
UNUSED4(udt_ig, udt_a, udt_res, udt_format1);
|
|
||||||
UNUSED4(udt_sap, udt_format2, udt_target, udt_source);
|
|
||||||
UNUSED4(udt_padnib, udt_zero, udt_sf, udt_pf);
|
|
||||||
UNUSED(udt_op);
|
|
||||||
|
|
||||||
//number of repititions required in various bit grabs
|
|
||||||
int end = 3; UNUSED(end);
|
|
||||||
|
|
||||||
//char strings
|
|
||||||
uint8_t iso7c;
|
|
||||||
uint8_t iso8c;
|
|
||||||
uint16_t utf16c;
|
|
||||||
|
|
||||||
//appended addresses -- max is 15 across 4 blocks
|
|
||||||
uint32_t address[16]; memset (address, 0, sizeof(address)); UNUSED(address);
|
|
||||||
uint8_t add_res = (uint8_t)ConvertBitIntoBytes(&cs_bits[96], 7); UNUSED(add_res);
|
|
||||||
uint8_t add_ok = cs_bits[103];
|
|
||||||
|
|
||||||
//BCD Format (Dialer Digits) -- max is 92 digits
|
|
||||||
uint8_t bcd_digits[93]; memset (bcd_digits, 0, sizeof(bcd_digits)); UNUSED(bcd_digits);
|
|
||||||
|
|
||||||
//NMEA Debug Testing (need real world samples)
|
|
||||||
// udt_format2 = 0x5;
|
|
||||||
// for (int i = 0; i < 8; i++) cs_bits[184+i] = 0; //spare bits to zero
|
|
||||||
// cs_bits[96] = 0; //enc bit to zero
|
|
||||||
// uint8_t test[96*4]; memset (test, 1, sizeof(test)); // all ones test vector
|
|
||||||
// nmea_iec_61162_1 (opts, state, test, udt_source, 1);
|
|
||||||
// nmea_iec_61162_1 (opts, state, cs_bits+96, udt_source, 2);
|
|
||||||
|
|
||||||
//LIP Debug Testing (need real world samples)
|
|
||||||
// udt_format2 = 0x0B;
|
|
||||||
|
|
||||||
//initial linebreak
|
|
||||||
fprintf (stderr, "%s", KCYN);
|
|
||||||
fprintf (stderr, "\n ");
|
|
||||||
fprintf (stderr, "Slot %d - SRC: %d; TGT: %d; UDT ", slot+1, udt_source, udt_target);
|
|
||||||
|
|
||||||
if (udt_format2 == 0x00)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Binary Data;");
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x01) //appended addresses
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Appended Addressing;\n ");
|
|
||||||
if (udt_uab == 1) end = 3;
|
|
||||||
if (udt_uab == 2) end = 7;
|
|
||||||
if (udt_uab == 3) end = 11;
|
|
||||||
if (udt_uab == 4) end = 15;
|
|
||||||
if (add_res) fprintf (stderr, "RES: %d; ", add_res);
|
|
||||||
fprintf (stderr, "OK: %d; ", add_ok);
|
|
||||||
fprintf (stderr, "ADDR:");
|
|
||||||
for (i = 0; i < end; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " %d;", (uint32_t)ConvertBitIntoBytes(&cs_bits[(i*24)+104], 24));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x02) //BCD 4-bit Dialer Digits
|
|
||||||
{
|
|
||||||
if (udt_uab == 1) end = 20;
|
|
||||||
if (udt_uab == 2) end = 44;
|
|
||||||
if (udt_uab == 3) end = 95;
|
|
||||||
if (udt_uab == 4) end = 92;
|
|
||||||
end -= udt_padnib; //subtract padnib since its also 4 bits
|
|
||||||
|
|
||||||
fprintf (stderr, "Dialer BCD: ");
|
|
||||||
for (i = 0; i < end; i++)
|
|
||||||
{
|
|
||||||
//dialer digits 7.2.9
|
|
||||||
int digit = (int)ConvertBitIntoBytes(&cs_bits[(i*4)+96], 4);
|
|
||||||
if (digit < 10) fprintf (stderr, "%d", digit); //numbers 0-9
|
|
||||||
else if (digit == 10) fprintf (stderr, "*"); //asterisk/star
|
|
||||||
else if (digit == 11) fprintf (stderr, "#"); //pound/hash
|
|
||||||
else if (digit == 15) fprintf (stderr, " "); //null character
|
|
||||||
else fprintf (stderr, "R:%X", digit); //reserved values on 12,13, and 14
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x03) //ISO7 format
|
|
||||||
{
|
|
||||||
if (udt_uab == 1) end = 11;
|
|
||||||
if (udt_uab == 2) end = 25;
|
|
||||||
if (udt_uab == 3) end = 38;
|
|
||||||
if (udt_uab == 4) end = 52;
|
|
||||||
end -= udt_padnib/7; //is this correct?
|
|
||||||
fprintf (stderr, "ISO7 Text: " );
|
|
||||||
for (i = 0; i < end; i++) //max 368/7 = 52 character max?
|
|
||||||
{
|
|
||||||
iso7c = (uint8_t)ConvertBitIntoBytes(&cs_bits[(i*7)+96], 7);
|
|
||||||
if (iso7c >= 0x20 && iso7c <= 0x7E) //Standard ASCII Set
|
|
||||||
fprintf (stderr, "%c", iso7c);
|
|
||||||
else fprintf (stderr, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x04) //ISO8 format
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ISO8 Text: " );
|
|
||||||
if (udt_uab == 1) end = 10;
|
|
||||||
if (udt_uab == 2) end = 22;
|
|
||||||
if (udt_uab == 3) end = 34;
|
|
||||||
if (udt_uab == 4) end = 46;
|
|
||||||
end -= udt_padnib/8; //is this correct?
|
|
||||||
for (i = 0; i < end; i++)
|
|
||||||
{
|
|
||||||
iso8c = (uint8_t)ConvertBitIntoBytes(&cs_bits[(i*8)+96], 8);
|
|
||||||
if (iso8c >= 0x20 && iso8c <= 0x7E) //Standard ASCII Set
|
|
||||||
fprintf (stderr, "%c", iso8c);
|
|
||||||
// else if (iso8c >= 0x81 && iso8c <= 0xFE) //Extended ASCII Set
|
|
||||||
// fprintf (stderr, "%c", iso8c);
|
|
||||||
else fprintf (stderr, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x07) //UTF-16BE format
|
|
||||||
{
|
|
||||||
if (udt_uab == 1) end = 5;
|
|
||||||
if (udt_uab == 2) end = 11;
|
|
||||||
if (udt_uab == 3) end = 17;
|
|
||||||
if (udt_uab == 4) end = 23;
|
|
||||||
end -= udt_padnib/4; //example, 4 blocks sets 23 - (20nibs/4bits) = 18 chars, may need to check this again
|
|
||||||
fprintf (stderr, "UTF16 Text: " );
|
|
||||||
for (i = 0; i < end; i++) //368/16 = 23 character max?
|
|
||||||
{
|
|
||||||
utf16c = (uint16_t)ConvertBitIntoBytes(&cs_bits[(i*16)+96], 16);
|
|
||||||
if (utf16c >= 0x20 && utf16c != 0x7F) //avoid control chars
|
|
||||||
fprintf (stderr, "%lc", utf16c); //will using lc work here? May depend on console locale settings?
|
|
||||||
else fprintf (stderr, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x06) //IP
|
|
||||||
{
|
|
||||||
if (udt_uab == 1) //IP4
|
|
||||||
{
|
|
||||||
fprintf (stderr, "IP4: ");
|
|
||||||
fprintf (stderr, "%d.",(uint8_t)ConvertBitIntoBytes(&cs_bits[96+0], 8));
|
|
||||||
fprintf (stderr, "%d.",(uint8_t)ConvertBitIntoBytes(&cs_bits[96+8], 8));
|
|
||||||
fprintf (stderr, "%d.",(uint8_t)ConvertBitIntoBytes(&cs_bits[96+16], 8));
|
|
||||||
fprintf (stderr, "%d", (uint8_t)ConvertBitIntoBytes(&cs_bits[96+24], 8));
|
|
||||||
}
|
|
||||||
else //IP6
|
|
||||||
{
|
|
||||||
fprintf (stderr, "IP6: ");
|
|
||||||
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+0], 16));
|
|
||||||
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+16], 16));
|
|
||||||
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+32], 16));
|
|
||||||
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+48], 16));
|
|
||||||
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+56], 16));
|
|
||||||
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+72], 16));
|
|
||||||
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+88], 16));
|
|
||||||
fprintf (stderr, "%04X", (uint16_t)ConvertBitIntoBytes(&cs_bits[96+104], 16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x0A) //Mixed Address/UTF-16BE
|
|
||||||
{
|
|
||||||
if (udt_uab == 1) end = 3;
|
|
||||||
if (udt_uab == 2) end = 9;
|
|
||||||
if (udt_uab == 3) end = 15;
|
|
||||||
if (udt_uab == 4) end = 21;
|
|
||||||
end -= udt_padnib/4; //is this correct?
|
|
||||||
fprintf (stderr, "Address: %d", (uint32_t)ConvertBitIntoBytes(&cs_bits[96+8], 24));
|
|
||||||
fprintf (stderr, "Text: " );
|
|
||||||
for (i = 0; i < end; i++) //368/16 = 21 character max
|
|
||||||
{
|
|
||||||
utf16c = (uint16_t)ConvertBitIntoBytes(&cs_bits[(i*16)+96], 16);
|
|
||||||
if (utf16c >= 0x20 && utf16c != 0x7F) //avoid control chars
|
|
||||||
fprintf (stderr, "%lc", utf16c);
|
|
||||||
else fprintf (stderr, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x05)
|
|
||||||
{
|
|
||||||
//Would be nice to be able to test these all out to make sure the conditions are okay, etc
|
|
||||||
fprintf (stderr, "NMEA" );
|
|
||||||
if (cs_bits[96] == 1) //check if its encrypted first
|
|
||||||
fprintf (stderr, " Encrypted Format :(" ); //sad face
|
|
||||||
else if (udt_uab == 1)
|
|
||||||
nmea_iec_61162_1 (opts, state, cs_bits+96, udt_source, 1); //short format w/ 1 appended block
|
|
||||||
else if (udt_uab == 2)
|
|
||||||
nmea_iec_61162_1 (opts, state, cs_bits+96, udt_source, 2); //standard long format w/ 2 appended blocks
|
|
||||||
//check the 'spare' bits from 184 to 192 to see if this is a manufacturer specific nmea format
|
|
||||||
else if (udt_uab == 3) //mfid format w/ 2 appended blocks -- format unspecified
|
|
||||||
fprintf (stderr, " Unspecified MFID Format: %02X;", (uint8_t)ConvertBitIntoBytes(&cs_bits[184], 8));
|
|
||||||
else
|
|
||||||
fprintf (stderr, " Reserved Format; ");
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x0B)
|
|
||||||
{
|
|
||||||
//unsure of how this is structured for UDT Blocks, would assume one appended block of same format
|
|
||||||
//but could also be full blown LIP protocol that is also found in tetra that would require the PDU
|
|
||||||
//type bit to be read and then to decode accordingly, this assumes its the modified Short PDU that USBD uses
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
lip_protocol_decoder (opts, state, cs_bits+96); //start on first appended block, and not header
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (udt_format2 == 0x08 || udt_format2 == 0x09)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "MFID SPEC %02X: ", udt_format2);
|
|
||||||
//use -Z to expose this
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Reserved %02X: ", udt_format2);
|
|
||||||
//use -Z to expose this
|
|
||||||
}
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//assemble the blocks as they come in, shuffle them into the unified dmr_pdu_sf
|
//assemble the blocks as they come in, shuffle them into the unified dmr_pdu_sf
|
||||||
void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type)
|
void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type)
|
||||||
{
|
{
|
||||||
UNUSED(databurst);
|
int i, j, k;
|
||||||
|
|
||||||
int i, j;
|
|
||||||
uint8_t lb = 0; //mbc last block
|
uint8_t lb = 0; //mbc last block
|
||||||
uint8_t pf = 0; //mbc protect flag
|
uint8_t pf = 0; //mbc protect flag
|
||||||
|
|
||||||
@@ -664,7 +417,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
uint32_t CRCExtracted = 0;
|
uint32_t CRCExtracted = 0;
|
||||||
uint32_t IrrecoverableErrors = 0;
|
uint32_t IrrecoverableErrors = 0;
|
||||||
|
|
||||||
uint8_t dmr_pdu_sf_bits[8*24*129]; //give plenty of space so we don't go oob
|
uint8_t dmr_pdu_sf_bits[8*24*50]; //give plenty of space so we don't go oob
|
||||||
|
|
||||||
//MBC Header and Block CRC
|
//MBC Header and Block CRC
|
||||||
uint8_t mbc_crc_good[2]; //header and blocks crc pass/fail local storage
|
uint8_t mbc_crc_good[2]; //header and blocks crc pass/fail local storage
|
||||||
@@ -677,14 +430,14 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
uint8_t is_udt = 0;
|
uint8_t is_udt = 0;
|
||||||
if (type == 3)
|
if (type == 3)
|
||||||
{
|
{
|
||||||
blocks = state->data_header_blocks[slot];
|
blocks = state->data_block_counter[slot];
|
||||||
is_udt = 1;
|
is_udt = 1;
|
||||||
type = 2;
|
type = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//sanity check, setting block_len and block values to sane numbers in case of missing header, else could overload array (crash) or print out
|
//sanity check, setting block_len and block values to sane numbers in case of missing header, else could overload array (crash) or print out
|
||||||
if (blocks < 1) blocks = 1; //changed blocks from uint8_t to int
|
if (blocks < 1) blocks = 1; //changed blocks from uint8_t to int
|
||||||
if (blocks > 127) blocks = 127;
|
if (blocks > 9) blocks = 9;
|
||||||
if (block_len == 0) block_len = 18;
|
if (block_len == 0) block_len = 18;
|
||||||
if (block_len > 24) block_len = 24;
|
if (block_len > 24) block_len = 24;
|
||||||
|
|
||||||
@@ -791,8 +544,11 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
fprintf (stderr, "\n Slot %d - Multi Block PDU Message\n ", slot+1);
|
fprintf (stderr, "\n Slot %d - Multi Block PDU Message\n ", slot+1);
|
||||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||||
{
|
{
|
||||||
if ( (i != 0) && (i % 12 == 0) ) fprintf (stderr, "\n ");
|
|
||||||
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
|
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
|
||||||
|
if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71 || i == 83 || i == 95)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug print
|
//debug print
|
||||||
@@ -849,18 +605,15 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
|
|
||||||
if (is_udt)
|
if (is_udt)
|
||||||
{
|
{
|
||||||
lb = 0; //set to zero, data header may erroneously the lb flag check above (IG)
|
blocks = state->data_header_blocks[slot];
|
||||||
pf = 0; //set to zero, data header may erroneously the pf flag check above (A)
|
if (blocks == blockcounter) lb = 1; //double check
|
||||||
if (blocks == blockcounter) lb = 1; //seems to work now with the +1 on udt_uab
|
pf = 0; //flag off is set from bit in error
|
||||||
|
|
||||||
//debug -- evaluate current block count vs the number of expected blocks
|
|
||||||
// fprintf (stderr, " BL: %d; BC: %d; ", blocks, blockcounter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//last block arrived and we have a valid data header, time to send to cspdu decoder
|
//last block arrived and we have a valid data header, time to send to cspdu decoder
|
||||||
if (lb == 1 && state->data_header_valid[slot] == 1)
|
if (lb == 1 && state->data_header_valid[slot] == 1)
|
||||||
{
|
{
|
||||||
for(i = 0, j = 0; i < 12*6; i++, j+=8) //4 blocks max?
|
for(i = 0, j = 0; i < 12*4; i++, j+=8) //4 blocks max?
|
||||||
{
|
{
|
||||||
dmr_pdu_sf_bits[j + 0] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
|
dmr_pdu_sf_bits[j + 0] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
|
||||||
dmr_pdu_sf_bits[j + 1] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
|
dmr_pdu_sf_bits[j + 1] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
|
||||||
@@ -890,23 +643,14 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
CRCExtracted = CRCExtracted | (uint32_t)(dmr_pdu_sf_bits[i + 96*(1+blocks) - 16] & 1);
|
CRCExtracted = CRCExtracted | (uint32_t)(dmr_pdu_sf_bits[i + 96*(1+blocks) - 16] & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t mbc_block_bits[12*8*6]; //needed more room
|
uint8_t mbc_block_bits[12*8*3];
|
||||||
memset (mbc_block_bits, 0, sizeof(mbc_block_bits));
|
memset (mbc_block_bits, 0, sizeof(mbc_block_bits));
|
||||||
//shift continuation blocks and last block into seperate array for crc check
|
//shift continuation blocks and last block into seperate array for crc check
|
||||||
for (i = 0; i < 12*8*3; i++) //only doing 3 blocks (4 minus the header), probably need to re-evalutate this
|
for (i = 0; i < 12*8*3; i++) //only doing 3 blocks (4 minus the header)
|
||||||
{
|
{
|
||||||
mbc_block_bits[i] = dmr_pdu_sf_bits[i+96]; //skip mbc header
|
mbc_block_bits[i] = dmr_pdu_sf_bits[i+96]; //skip mbc header
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_udt)
|
|
||||||
{
|
|
||||||
memset (mbc_block_bits, 0, sizeof(mbc_block_bits));
|
|
||||||
for (i = 0; i < 12*8*blocks; i++)
|
|
||||||
{
|
|
||||||
mbc_block_bits[i] = dmr_pdu_sf_bits[i+96]; //skip udt header
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CRCComputed = ComputeCrcCCITT16d (mbc_block_bits, ((blocks+0)*96)-16 );
|
CRCComputed = ComputeCrcCCITT16d (mbc_block_bits, ((blocks+0)*96)-16 );
|
||||||
|
|
||||||
if (CRCComputed == CRCExtracted) mbc_crc_good[1] = 1;
|
if (CRCComputed == CRCExtracted) mbc_crc_good[1] = 1;
|
||||||
@@ -934,8 +678,8 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
//cspdu will only act on any fid/opcodes if good CRC to prevent falsing on control signalling
|
//cspdu will only act on any fid/opcodes if good CRC to prevent falsing on control signalling
|
||||||
if (!is_udt && !pf) dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors);
|
if (!is_udt && !pf) dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors);
|
||||||
|
|
||||||
//send to udt decoder for handling
|
//will need to reassemble partially before sending to dmr_pdu or dmr_cspdu for handling -- needs testing
|
||||||
if (is_udt && !pf) dmr_udt_decoder (opts, state, state->dmr_pdu_sf[slot], CRCCorrect);
|
if (is_udt && !pf) dmr_udt_cspdu_converter (opts, state, state->dmr_pdu_sf[slot], dmr_pdu_sf_bits, CRCCorrect, IrrecoverableErrors);
|
||||||
|
|
||||||
//Full Super Frame MBC/UDT - Debug Output
|
//Full Super Frame MBC/UDT - Debug Output
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
@@ -956,6 +700,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
if (pf) fprintf (stderr, "MBC/UDT Header/Blocks Protected ");
|
if (pf) fprintf (stderr, "MBC/UDT Header/Blocks Protected ");
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end last block flag on MBC
|
} //end last block flag on MBC
|
||||||
|
|
||||||
} //end type 2 (MBC Header and Continuation)
|
} //end type 2 (MBC Header and Continuation)
|
||||||
@@ -969,7 +714,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
{
|
{
|
||||||
|
|
||||||
//clear out unified pdu 'superframe' slot
|
//clear out unified pdu 'superframe' slot
|
||||||
for (int i = 0; i < 24*127; i++)
|
for (short int i = 0; i < 288; i++)
|
||||||
{
|
{
|
||||||
state->dmr_pdu_sf[slot][i] = 0;
|
state->dmr_pdu_sf[slot][i] = 0;
|
||||||
}
|
}
|
||||||
@@ -992,7 +737,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
{
|
{
|
||||||
|
|
||||||
//clear out unified pdu 'superframe' slot
|
//clear out unified pdu 'superframe' slot
|
||||||
for (int i = 0; i < 24*127; i++)
|
for (short int i = 0; i < 288; i++)
|
||||||
{
|
{
|
||||||
state->dmr_pdu_sf[slot][i] = 0;
|
state->dmr_pdu_sf[slot][i] = 0;
|
||||||
}
|
}
|
||||||
@@ -1019,8 +764,6 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
|||||||
//or tuning away and we can no longer verify accurate data block reporting
|
//or tuning away and we can no longer verify accurate data block reporting
|
||||||
void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
memset (state->data_p_head, 0, sizeof(state->data_p_head));
|
memset (state->data_p_head, 0, sizeof(state->data_p_head));
|
||||||
memset (state->data_conf_data, 0, sizeof(state->data_conf_data));
|
memset (state->data_conf_data, 0, sizeof(state->data_conf_data));
|
||||||
memset (state->dmr_pdu_sf, 0, sizeof(state->dmr_pdu_sf));
|
memset (state->dmr_pdu_sf, 0, sizeof(state->dmr_pdu_sf));
|
||||||
|
|||||||
146
src/dmr_bs.c
146
src/dmr_bs.c
@@ -13,7 +13,8 @@
|
|||||||
//processing voice and/or data on both BS slots (channels) simultaneously
|
//processing voice and/or data on both BS slots (channels) simultaneously
|
||||||
void dmrBS (dsd_opts * opts, dsd_state * state)
|
void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
int i, dibit;
|
int i, j, k, l, dibit;
|
||||||
|
int *dibit_p;
|
||||||
|
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
char ambe_fr2[4][24];
|
char ambe_fr2[4][24];
|
||||||
@@ -24,19 +25,18 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
char redundancyB[36];
|
char redundancyB[36];
|
||||||
|
|
||||||
//memcpy of ambe_fr for late entry
|
//memcpy of ambe_fr for late entry
|
||||||
uint8_t m1[4][24];
|
char m1[4][24];
|
||||||
uint8_t m2[4][24];
|
char m2[4][24];
|
||||||
uint8_t m3[4][24];
|
char m3[4][24];
|
||||||
|
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
char sync[25];
|
char sync[25];
|
||||||
char syncdata[48];
|
char syncdata[48];
|
||||||
unsigned char EmbeddedSignalling[16];
|
char EmbeddedSignalling[16];
|
||||||
|
|
||||||
uint8_t emb_ok = 0;
|
uint8_t emb_ok = 0;
|
||||||
uint8_t tact_okay = 0;
|
uint8_t tact_okay = 0;
|
||||||
uint8_t cach_err = 0;
|
uint8_t cach_err = 0;
|
||||||
UNUSED(cach_err);
|
|
||||||
|
|
||||||
uint8_t internalslot;
|
uint8_t internalslot;
|
||||||
uint8_t vc1;
|
uint8_t vc1;
|
||||||
@@ -46,13 +46,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t cc = 25;
|
uint8_t cc = 25;
|
||||||
uint8_t power = 9; //power and pre-emption indicator
|
uint8_t power = 9; //power and pre-emption indicator
|
||||||
uint8_t lcss = 9;
|
uint8_t lcss = 9;
|
||||||
UNUSED2(cc, lcss);
|
|
||||||
|
|
||||||
//would be ideal to grab all dibits and break them into bits to pass to new data handler?
|
//would be ideal to grab all dibits and break them into bits to pass to new data handler?
|
||||||
uint8_t dummy_bits[196];
|
uint8_t dummy_bits[196];
|
||||||
memset (dummy_bits, 0, sizeof(dummy_bits));
|
memset (dummy_bits, 0, sizeof(dummy_bits));
|
||||||
|
|
||||||
//add time to mirror printFrameSync
|
//add time to mirror printFrameSync
|
||||||
|
time_t now;
|
||||||
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);
|
||||||
@@ -82,7 +82,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
short int skipcount = 0;
|
short int skipcount = 0;
|
||||||
|
|
||||||
//cach
|
//cach
|
||||||
uint8_t cachdata[25];
|
char cachdata[25];
|
||||||
int cachInterleave[24] =
|
int cachInterleave[24] =
|
||||||
{0, 7, 8, 9, 1, 10,
|
{0, 7, 8, 9, 1, 10,
|
||||||
11, 12, 2, 13, 14,
|
11, 12, 2, 13, 14,
|
||||||
@@ -96,11 +96,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
//Run Loop while the getting is good
|
//Run Loop while the getting is good
|
||||||
while (loop == 1) {
|
while (loop == 1) {
|
||||||
|
|
||||||
if (exitflag == 1)
|
|
||||||
{
|
|
||||||
cleanupAndExit (opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||||
@@ -373,51 +368,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
if(internalslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
if(internalslot == 0)
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
|
||||||
if(internalslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
||||||
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
||||||
@@ -480,15 +432,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SKIP:
|
SKIP:
|
||||||
|
if (skipcount > 2) //after 2 consecutive data frames, drop back to getFrameSync and process with dmr_data_sync
|
||||||
//both working now, will need support added for ENC audio and no key
|
|
||||||
//NOTE: We want this to play regardless of whether the slot is voice or data, to play silence in one slot and voice in the second, or voices in both
|
|
||||||
if (internalslot == 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceFS3 (opts, state); //Float Stereo Mix 3v2
|
|
||||||
if (internalslot == 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceSS3 (opts, state); //Short Stereo Mix 3v2
|
|
||||||
|
|
||||||
if (skipcount > 3) //after 3 onsecutive data frames, drop back to getFrameSync and process with dmr_data_sync (need one more in order to push last voice on slot 2 only voice)
|
|
||||||
{
|
{
|
||||||
//set tests to all good so we don't get a bogus/redundant voice error
|
//set tests to all good so we don't get a bogus/redundant voice error
|
||||||
cach_err = 0;
|
cach_err = 0;
|
||||||
@@ -516,12 +460,6 @@ void dmrBS (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);
|
||||||
|
|
||||||
//clear out any stale audio storage buffers
|
|
||||||
memset (state->f_l4, 0.0f, sizeof(state->f_l4));
|
|
||||||
memset (state->f_r4, 0.0f, sizeof(state->f_r4));
|
|
||||||
memset (state->s_l4, 0, sizeof(state->s_l4));
|
|
||||||
memset (state->s_r4, 0, sizeof(state->s_r4));
|
|
||||||
|
|
||||||
//if we have a tact or emb err, then produce sync pattern/err message
|
//if we have a tact or emb err, then produce sync pattern/err message
|
||||||
if (tact_okay != 1 || emb_ok != 1)
|
if (tact_okay != 1 || emb_ok != 1)
|
||||||
{
|
{
|
||||||
@@ -554,7 +492,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
//Process buffered half frame and 2nd half and then jump to full BS decoding
|
//Process buffered half frame and 2nd half and then jump to full BS decoding
|
||||||
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
int i, dibit;
|
int i, j, k, l, dibit;
|
||||||
int *dibit_p;
|
int *dibit_p;
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
char ambe_fr2[4][24];
|
char ambe_fr2[4][24];
|
||||||
@@ -565,20 +503,19 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||||
|
|
||||||
//memcpy of ambe_fr for late entry
|
//memcpy of ambe_fr for late entry
|
||||||
uint8_t m1[4][24];
|
char m1[4][24];
|
||||||
uint8_t m2[4][24];
|
char m2[4][24];
|
||||||
uint8_t m3[4][24];
|
char m3[4][24];
|
||||||
|
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
char sync[25];
|
char sync[25];
|
||||||
uint8_t tact_okay = 0;
|
uint8_t tact_okay = 0;
|
||||||
uint8_t cach_err = 0;
|
uint8_t cach_err = 0;
|
||||||
uint8_t sync_okay = 1;
|
uint8_t sync_okay = 1;
|
||||||
UNUSED(cach_err);
|
|
||||||
|
|
||||||
uint8_t internalslot;
|
uint8_t internalslot;
|
||||||
|
|
||||||
uint8_t cachdata[25];
|
char cachdata[25];
|
||||||
int cachInterleave[24] =
|
int cachInterleave[24] =
|
||||||
{0, 7, 8, 9, 1, 10,
|
{0, 7, 8, 9, 1, 10,
|
||||||
11, 12, 2, 13, 14,
|
11, 12, 2, 13, 14,
|
||||||
@@ -586,6 +523,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
19, 5, 20, 21, 22, 6, 23
|
19, 5, 20, 21, 22, 6, 23
|
||||||
};
|
};
|
||||||
//add time to mirror printFrameSync
|
//add time to mirror printFrameSync
|
||||||
|
time_t now;
|
||||||
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);
|
||||||
@@ -779,55 +717,9 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||||
|
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
|
||||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
|
||||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
if(internalslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
if(internalslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
if(internalslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
//collect the mi fragment
|
//collect the mi fragment
|
||||||
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
||||||
@@ -838,12 +730,6 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
//update voice sync time for trunking purposes (particularly Con+)
|
//update voice sync time for trunking purposes (particularly Con+)
|
||||||
if (opts->p25_is_tuned == 1) state->last_vc_sync_time = time(NULL);
|
if (opts->p25_is_tuned == 1) state->last_vc_sync_time = time(NULL);
|
||||||
|
|
||||||
//NOTE: Only play on slot 1, if slot 0, then it'll play after the next TDMA frame in the BS loop instead
|
|
||||||
if (internalslot == 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceFS3 (opts, state); //Float Stereo Mix 3v2
|
|
||||||
if (internalslot == 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceSS3 (opts, state); //Short Stereo Mix 3v2
|
|
||||||
|
|
||||||
dmrBS (opts, state); //bootstrap into full TDMA frame for BS mode
|
dmrBS (opts, state); //bootstrap into full TDMA frame for BS mode
|
||||||
END:
|
END:
|
||||||
//if we have a tact err, then produce sync pattern/err message
|
//if we have a tact err, then produce sync pattern/err message
|
||||||
|
|||||||
1371
src/dmr_csbk.c
1371
src/dmr_csbk.c
File diff suppressed because it is too large
Load Diff
@@ -25,15 +25,14 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
|||||||
int *dibit_p;
|
int *dibit_p;
|
||||||
char sync[25];
|
char sync[25];
|
||||||
char syncdata[48];
|
char syncdata[48];
|
||||||
uint8_t cachdata[25];
|
char cachdata[25];
|
||||||
UNUSED(syncdata);
|
|
||||||
|
|
||||||
|
char bursttype[5];
|
||||||
uint8_t burst;
|
uint8_t burst;
|
||||||
char info[196];
|
char info[196];
|
||||||
unsigned char SlotType[20];
|
unsigned char SlotType[20];
|
||||||
unsigned int SlotTypeOk;
|
unsigned int SlotTypeOk;
|
||||||
uint8_t cach_err = 0;
|
uint8_t cach_err = 0;
|
||||||
UNUSED(cach_err);
|
|
||||||
|
|
||||||
int cachInterleave[24] =
|
int cachInterleave[24] =
|
||||||
{0, 7, 8, 9, 1, 10,
|
{0, 7, 8, 9, 1, 10,
|
||||||
@@ -326,25 +325,18 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
|||||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->is_con_plus == 1)
|
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->is_con_plus == 1)
|
||||||
{
|
{
|
||||||
//bug fixed that caused hopping from CC to VC; decreased to 2 seconds.
|
//bug fixed that caused hopping from CC to VC; decreased to 2 seconds.
|
||||||
time_t waitsec = 2;
|
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||||
if (opts->trunk_tune_data_calls == 1)
|
|
||||||
waitsec = 4; //increase time for a data call before hopping
|
|
||||||
if ( (time(NULL) - state->last_vc_sync_time > waitsec) )
|
|
||||||
{
|
{
|
||||||
if (opts->use_rigctl == 1) //rigctl tuning
|
if (opts->use_rigctl == 1) //rigctl tuning
|
||||||
{
|
{
|
||||||
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->p25_cc_freq);
|
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||||
//debug
|
|
||||||
fprintf (stderr, " Con+ Timeout; Return to CC;");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (opts->audio_in_type == 3) //rtl_fm tuning
|
else if (opts->audio_in_type == 3) //rtl_fm tuning
|
||||||
{
|
{
|
||||||
#ifdef USE_RTLSDR
|
#ifdef USE_RTLSDR
|
||||||
rtl_dev_tune(opts, state->p25_cc_freq);
|
rtl_dev_tune(opts, state->p25_cc_freq);
|
||||||
//debug
|
|
||||||
fprintf (stderr, " Con+ Timeout; Return to CC;");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
opts->p25_is_tuned = 0;
|
opts->p25_is_tuned = 0;
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
||||||
*
|
*
|
||||||
* LWVMOBILE
|
* LWVMOBILE
|
||||||
* 2023-12 DSD-FME Florida Man Edition
|
* 2022-12 DSD-FME Florida Man Edition
|
||||||
*-----------------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
//TODO: Test USBD LIP Decoder with Real World Samples (if/when available)
|
//WIP: Unified Single Block Data - USBD -- TODO: USBD LIP Protocol Handling
|
||||||
//TODO: Test UDT NMEA and LIP Decoders with Real World Samples (if/when available)
|
//WIP: UDT Header and Blocks (coded - need samples)
|
||||||
//WIP: Move all extra decoders for location, etc, to a new file and add prototypes to dsd.h
|
//WIP: CRC9/CRC32 on Rate 1 Data (need samples)
|
||||||
//TODO: Test CRC9/CRC32 on Rate 1 Data with Real World Samples (if/when available)
|
//WIP: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC (rc interleave) and when to run RC and not SB
|
||||||
//TODO: Address areas that require reading of ISO7, ISO8, and UTF-16 string formats
|
//WIP: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key
|
||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
@@ -26,13 +26,13 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
uint32_t CRCCorrect = 0;
|
uint32_t CRCCorrect = 0;
|
||||||
uint32_t IrrecoverableErrors = 0;
|
uint32_t IrrecoverableErrors = 0;
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
|
uint8_t block = state->data_block_counter[slot];
|
||||||
|
|
||||||
//confirmed data
|
//confirmed data
|
||||||
uint8_t dbsn = 0; //data block serial number for confirmed data blocks
|
uint8_t dbsn = 0; //data block serial number for confirmed data blocks
|
||||||
uint8_t blockcounter = 0; //local block count
|
uint8_t blockcounter = 0; //local block count
|
||||||
uint8_t confdatabits[250]; //array to reshuffle conf data block bits into sequence for crc9 check
|
uint8_t confdatabits[250]; //array to reshuffle conf data block bits into sequence for crc9 check
|
||||||
memset (confdatabits, 0, sizeof(confdatabits));
|
memset (confdatabits, 0, sizeof(confdatabits));
|
||||||
UNUSED(dbsn);
|
|
||||||
|
|
||||||
//BPTC 196x96 Specific
|
//BPTC 196x96 Specific
|
||||||
uint8_t BPTCDeInteleavedData[196];
|
uint8_t BPTCDeInteleavedData[196];
|
||||||
@@ -418,29 +418,34 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//the sexy one
|
//the ugly 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 dibits for the trellis decoder
|
//reconstitute info bits into reverse ordered 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];
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t TrellisReturn[18];
|
unsigned char TrellisReturn[18];
|
||||||
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
||||||
IrrecoverableErrors = dmr_34(tdibits, TrellisReturn);
|
|
||||||
|
|
||||||
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
|
trellis_good = CDMRTrellisDecode(tdibits, TrellisReturn);
|
||||||
//they may have been successfully corrected, the CRC will reveal as much
|
if (trellis_good == TRUE) IrrecoverableErrors = 0;
|
||||||
|
// else (fprintf (stderr, " Trellis Failure")); //debug print
|
||||||
|
|
||||||
for (i = 0; i < pdu_len; i++)
|
for (i = 0; i < pdu_len; i++) //18
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -466,6 +471,7 @@ 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];
|
||||||
|
|
||||||
@@ -476,8 +482,10 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,12 +511,14 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
CRCComputed = 0;
|
CRCComputed = 0;
|
||||||
IrrecoverableErrors = 0; //implicit, since there is no encoding
|
IrrecoverableErrors = 0; //implicit, since there is no encoding
|
||||||
|
|
||||||
for (i = 0; i < 12; i++)
|
for (i = 0; i < 24; i++)
|
||||||
|
{
|
||||||
DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&info[i*8], 8);
|
DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&info[i*8], 8);
|
||||||
|
}
|
||||||
//Skip Padding Bits (96,97,98,99)
|
//leftover 4 bits, manual doesn't say which 4 so assuming last 4
|
||||||
for (i = 0; i < 12; i++)
|
//pushing last 4 to 25 and shifting it
|
||||||
DMR_PDU[i+12] = (uint8_t)ConvertBitIntoBytes(&info[(i*8)+100], 8);
|
DMR_PDU[25] = (uint8_t)ConvertBitIntoBytes(&info[192], 4);
|
||||||
|
DMR_PDU[25] = DMR_PDU[25] << 4;
|
||||||
|
|
||||||
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
|
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
|
||||||
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
||||||
@@ -575,8 +585,8 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
//TODO: provide more robust handling at a later date -- ETSI TS 102 361-4 V1.11.1 (2021-01) 6.6.11.3
|
//TODO: provide more robust handling at a later date -- ETSI TS 102 361-4 V1.11.1 (2021-01) 6.6.11.3
|
||||||
usbd_st = (uint8_t)ConvertBitIntoBytes(&DMR_PDU_bits[0], 4);
|
usbd_st = (uint8_t)ConvertBitIntoBytes(&DMR_PDU_bits[0], 4);
|
||||||
fprintf (stderr, "%s\n", KYEL);
|
fprintf (stderr, "%s\n", KYEL);
|
||||||
fprintf (stderr, " USBD - ");
|
fprintf (stderr, " Unified Single Block Data - ");
|
||||||
if (usbd_st == 0) lip_protocol_decoder (opts, state, DMR_PDU_bits);
|
if (usbd_st == 0) fprintf (stderr, "Location Information Protocol");
|
||||||
else if (usbd_st > 8) fprintf (stderr, "Manufacturer Specific Service %d ", usbd_st);
|
else if (usbd_st > 8) fprintf (stderr, "Manufacturer Specific Service %d ", usbd_st);
|
||||||
else fprintf (stderr, "Reserved %d ", usbd_st);
|
else fprintf (stderr, "Reserved %d ", usbd_st);
|
||||||
}
|
}
|
||||||
@@ -585,7 +595,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
if (is_ras == 1) CRCCorrect = crc_original_validity;
|
if (is_ras == 1) CRCCorrect = crc_original_validity;
|
||||||
|
|
||||||
//start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c)
|
//start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c)
|
||||||
// if (IrrecoverableErrors == 0 && CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) fprintf(stderr, "(CRC OK)");
|
if (IrrecoverableErrors == 0 && CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) ; //fprintf(stderr, "(CRC OK)");
|
||||||
|
|
||||||
// if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
|
// if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
|
||||||
// {
|
// {
|
||||||
@@ -595,7 +605,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
|
if (IrrecoverableErrors != 0 && databurst != 0x09) //&& databurst != 0x05
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf(stderr, " (FEC ERR)");
|
fprintf(stderr, " (FEC ERR)");
|
||||||
|
|||||||
319
src/dmr_flco.c
319
src/dmr_flco.c
@@ -14,7 +14,6 @@
|
|||||||
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
||||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type)
|
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type)
|
||||||
{
|
{
|
||||||
UNUSED(CRCCorrect);
|
|
||||||
|
|
||||||
//force slot to 0 if using dmr mono handling
|
//force slot to 0 if using dmr mono handling
|
||||||
if (opts->dmr_mono == 1) state->currentslot = 0;
|
if (opts->dmr_mono == 1) state->currentslot = 0;
|
||||||
@@ -31,7 +30,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
int is_cap_plus = 0;
|
int is_cap_plus = 0;
|
||||||
int is_alias = 0;
|
int is_alias = 0;
|
||||||
int is_gps = 0;
|
int is_gps = 0;
|
||||||
UNUSED(capsite);
|
|
||||||
|
|
||||||
//XPT 'Things'
|
//XPT 'Things'
|
||||||
int is_xpt = 0;
|
int is_xpt = 0;
|
||||||
@@ -43,7 +41,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
uint8_t xpt_res_c = 0; //unknown values of other bits of the XPT LC
|
uint8_t xpt_res_c = 0; //unknown values of other bits of the XPT LC
|
||||||
uint8_t target_hash[24]; //for XPT (and others if desired, get the hash and compare against SLC or XPT Status CSBKs)
|
uint8_t target_hash[24]; //for XPT (and others if desired, get the hash and compare against SLC or XPT Status CSBKs)
|
||||||
uint8_t tg_hash = 0; //value of the hashed TG
|
uint8_t tg_hash = 0; //value of the hashed TG
|
||||||
UNUSED3(xpt_res_a, xpt_res_b, xpt_res_c);
|
|
||||||
|
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
uint8_t unk = 0; //flag for unknown FLCO + FID combo
|
uint8_t unk = 0; //flag for unknown FLCO + FID combo
|
||||||
@@ -334,9 +331,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
state->payload_algid = 0;
|
state->payload_algid = 0;
|
||||||
state->payload_mi = 0;
|
state->payload_mi = 0;
|
||||||
state->payload_keyid = 0;
|
state->payload_keyid = 0;
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
}
|
}
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
{
|
{
|
||||||
@@ -347,9 +341,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
state->payload_algidR = 0;
|
state->payload_algidR = 0;
|
||||||
state->payload_miR = 0;
|
state->payload_miR = 0;
|
||||||
state->payload_keyidR = 0;
|
state->payload_keyidR = 0;
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gainR = opts->audio_gain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -422,60 +413,21 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
// strcat (state->call_string[slot], " Encrypted");
|
// strcat (state->call_string[slot], " Encrypted");
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf(stderr, "Encrypted ");
|
fprintf(stderr, "Encrypted ");
|
||||||
|
|
||||||
//experimental TG LO/B if ENC trunked following disabled //DMR -- LO Trunked Enc Calls WIP; #121
|
|
||||||
if (opts->p25_trunk == 1 && opts->trunk_tune_enc_calls == 0) //&& type != 2
|
|
||||||
{
|
|
||||||
int i, lo = 0;
|
|
||||||
uint32_t t = 0; char gm[8]; char gn[50];
|
|
||||||
|
|
||||||
//check to see if this group already exists, or has already been locked out, or is allowed
|
|
||||||
for (i = 0; i <= state->group_tally; i++)
|
|
||||||
{
|
|
||||||
t = (uint32_t)state->group_array[i].groupNumber;
|
|
||||||
if (target == t && t != 0)
|
|
||||||
{
|
|
||||||
lo = 1;
|
|
||||||
//write current mode and name to temp strings
|
|
||||||
sprintf (gm, "%s", state->group_array[i].groupMode);
|
|
||||||
sprintf (gn, "%s", state->group_array[i].groupName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if group doesn't exist, or isn't locked out, then do so now.
|
|
||||||
if (lo == 0)
|
|
||||||
{
|
|
||||||
state->group_array[state->group_tally].groupNumber = target;
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
|
||||||
sprintf (state->group_array[state->group_tally].groupName, "%s", "ENC LO");
|
|
||||||
sprintf (gm, "%s", "DE");
|
|
||||||
sprintf (gn, "%s", "ENC LO");
|
|
||||||
state->group_tally++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Craft a fake CSBK pdu send it to run as a p_clear to return to CC if available
|
|
||||||
uint8_t dummy[12]; uint8_t* dbits; memset (dummy, 0, sizeof(dummy)); dummy[0] = 46; dummy[1] = 255;
|
|
||||||
if ( (strcmp(gm, "DE") == 0) && (strcmp(gn, "ENC LO") == 0) ) //&& (opts->trunk_tune_data_calls == 0)
|
|
||||||
dmr_cspdu (opts, state, dbits, dummy, 1, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//REMUS! Uncomment Line Below if desired
|
//REMUS! Uncomment Line Below if desired
|
||||||
// else strcat (state->call_string[slot], " ");
|
// else strcat (state->call_string[slot], " ");
|
||||||
|
|
||||||
|
//Motorola FID 0x10 Only
|
||||||
if (1 == 1) //fid == 0x10
|
if (fid == 0x10)
|
||||||
{
|
{
|
||||||
/* Check the "Service Option" bits */
|
/* Check the "Service Option" bits */
|
||||||
if( (fid == 0x10) && (so & 0x20) ) //Motorola FID 0x10 Only
|
if(so & 0x20)
|
||||||
{
|
{
|
||||||
//REMUS! Uncomment Line Below if desired
|
//REMUS! Uncomment Line Below if desired
|
||||||
// strcat (state->call_string[slot], " TXI");
|
// strcat (state->call_string[slot], " TXI");
|
||||||
fprintf(stderr, "TXI ");
|
fprintf(stderr, "TXI ");
|
||||||
}
|
}
|
||||||
if ( (fid == 0x10) && (so & 0x10) ) //Motorola FID 0x10 Only
|
if (so & 0x10)
|
||||||
{
|
{
|
||||||
//REMUS! Uncomment Line Below if desired
|
//REMUS! Uncomment Line Below if desired
|
||||||
// strcat (state->call_string[slot], " RPT");
|
// strcat (state->call_string[slot], " RPT");
|
||||||
@@ -638,7 +590,7 @@ uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25])
|
|||||||
int i, j;
|
int i, j;
|
||||||
uint8_t err = 0;
|
uint8_t err = 0;
|
||||||
uint8_t tact_valid = 0;
|
uint8_t tact_valid = 0;
|
||||||
UNUSED(tact_valid);
|
uint8_t cach_valid = 0;
|
||||||
|
|
||||||
bool h1, h2, h3, crc;
|
bool h1, h2, h3, crc;
|
||||||
|
|
||||||
@@ -651,7 +603,6 @@ uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25])
|
|||||||
uint8_t at = 0; //access type, set to 1 during continuous transmission mode
|
uint8_t at = 0; //access type, set to 1 during continuous transmission mode
|
||||||
uint8_t slot = 2; //tdma time slot
|
uint8_t slot = 2; //tdma time slot
|
||||||
uint8_t lcss = 0; //link control start stop (9.3.3) NOTE: There is no Single fragment LC defined for CACH signalling
|
uint8_t lcss = 0; //link control start stop (9.3.3) NOTE: There is no Single fragment LC defined for CACH signalling
|
||||||
UNUSED2(at, slot);
|
|
||||||
|
|
||||||
//cach_bits are already de-interleaved upon initial collection (still needs secodary slco de-interleave)
|
//cach_bits are already de-interleaved upon initial collection (still needs secodary slco de-interleave)
|
||||||
for (i = 0; i < 7; i++)
|
for (i = 0; i < 7; i++)
|
||||||
@@ -787,17 +738,10 @@ uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25])
|
|||||||
if (h1 && h2 && h3 && crc) dmr_slco (opts, state, slco_bits);
|
if (h1 && h2 && h3 && crc) dmr_slco (opts, state, slco_bits);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//this line break issue is wracking on my OCD for clean line breaks
|
fprintf (stderr, "\n");
|
||||||
if (opts->payload == 1 && state->dmrburstL == 16 && state->currentslot == 0) ; //no line break if current slot is voice with payload enabled
|
|
||||||
else if (opts->payload == 1 && state->dmrburstR == 16 && state->currentslot == 1) ; //no line break if current slot is voice with payload enabled
|
|
||||||
else fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf (stderr, " SLCO CRC ERR");
|
fprintf (stderr, " SLCO CRC ERR");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
if (opts->payload == 1 && state->dmrburstL == 16 && state->currentslot == 0) //if current slot is voice with payload enabled
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
else if (opts->payload == 1 && state->dmrburstR == 16 && state->currentslot == 1) //if current slot is voice with payload enabled
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -820,8 +764,6 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
uint16_t netsite = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 12);
|
uint16_t netsite = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 12);
|
||||||
uint8_t reg = slco_bits[18]; //registration required/not required or normalchanneltype/composite cch
|
uint8_t reg = slco_bits[18]; //registration required/not required or normalchanneltype/composite cch
|
||||||
uint8_t csc = (uint16_t)ConvertBitIntoBytes(&slco_bits[19], 9); //common slot counter, 0-511
|
uint8_t csc = (uint16_t)ConvertBitIntoBytes(&slco_bits[19], 9); //common slot counter, 0-511
|
||||||
UNUSED(netsite);
|
|
||||||
|
|
||||||
uint16_t net = 0;
|
uint16_t net = 0;
|
||||||
uint16_t site = 0;
|
uint16_t site = 0;
|
||||||
char model_str[8];
|
char model_str[8];
|
||||||
@@ -832,32 +774,9 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
uint8_t ts1_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8); //ts1 address hash (crc8) //361-1 B.3.7
|
uint8_t ts1_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8); //ts1 address hash (crc8) //361-1 B.3.7
|
||||||
uint8_t ts2_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //ts2 address hash (crc8) //361-1 B.3.7
|
uint8_t ts2_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //ts2 address hash (crc8) //361-1 B.3.7
|
||||||
|
|
||||||
char ts1_str[25]; sprintf (ts1_str, "%s", "");
|
|
||||||
char ts2_str[25]; sprintf (ts2_str, "%s", "");
|
|
||||||
|
|
||||||
if (ts1_act == 0b0000) sprintf (ts1_str, "%s", "Idle");
|
|
||||||
else if (ts1_act == 0b0010) sprintf (ts1_str, "%s", "Group CSBK");
|
|
||||||
else if (ts1_act == 0b0011) sprintf (ts1_str, "%s", "Ind CSBK");
|
|
||||||
else if (ts1_act == 0b1000) sprintf (ts1_str, "%s", "Group Voice");
|
|
||||||
else if (ts1_act == 0b1001) sprintf (ts1_str, "%s", "Ind Voice");
|
|
||||||
else if (ts1_act == 0b1010) sprintf (ts1_str, "%s", "Ind Data");
|
|
||||||
else if (ts1_act == 0b1011) sprintf (ts1_str, "%s", "Group Data");
|
|
||||||
else if (ts1_act == 0b1100) sprintf (ts1_str, "%s", "Group Emergency");
|
|
||||||
else if (ts1_act == 0b1101) sprintf (ts1_str, "%s", "Ind Emergency");
|
|
||||||
else sprintf (ts1_str, "Res %X", ts1_act);
|
|
||||||
|
|
||||||
if (ts2_act == 0b0000) sprintf (ts2_str, "%s", "Idle");
|
|
||||||
else if (ts2_act == 0b0010) sprintf (ts2_str, "%s", "Group CSBK");
|
|
||||||
else if (ts2_act == 0b0011) sprintf (ts2_str, "%s", "Ind CSBK");
|
|
||||||
else if (ts2_act == 0b1000) sprintf (ts2_str, "%s", "Group Voice");
|
|
||||||
else if (ts2_act == 0b1001) sprintf (ts2_str, "%s", "Ind Voice");
|
|
||||||
else if (ts2_act == 0b1010) sprintf (ts2_str, "%s", "Ind Data");
|
|
||||||
else if (ts2_act == 0b1011) sprintf (ts2_str, "%s", "Group Data");
|
|
||||||
else if (ts2_act == 0b1100) sprintf (ts2_str, "%s", "Group Emergency");
|
|
||||||
else if (ts2_act == 0b1101) sprintf (ts2_str, "%s", "Ind Emergency");
|
|
||||||
else sprintf (ts2_str, "Res %X", ts1_act);
|
|
||||||
|
|
||||||
//DMR Location Area - DMRLA - should probably be state variables so we can use this in both slc and csbk
|
//DMR Location Area - DMRLA - should probably be state variables so we can use this in both slc and csbk
|
||||||
|
uint16_t sys_area = 0;
|
||||||
|
uint16_t sub_area = 0;
|
||||||
uint16_t sub_mask = 0x1;
|
uint16_t sub_mask = 0x1;
|
||||||
//tiny n 1-3; small 1-5; large 1-8; huge 1-10
|
//tiny n 1-3; small 1-5; large 1-8; huge 1-10
|
||||||
uint16_t n = 1; //The minimum value of DMRLA is normally ≥ 1, 0 is reserved
|
uint16_t n = 1; //The minimum value of DMRLA is normally ≥ 1, 0 is reserved
|
||||||
@@ -934,16 +853,12 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
|
|
||||||
if (slco == 0x2) //C_SYS_Parms
|
if (slco == 0x2) //C_SYS_Parms
|
||||||
{
|
{
|
||||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
if (n != 0) fprintf (stderr, " SLC_C_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Reg Req: %d - CSC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg, csc);
|
||||||
if (n != 0) fprintf (stderr, " SLC_C_SYS_PARMS: %s; Net ID: %d; Site ID: %d.%d; Reg Req: %d; CSC: %d;", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg, csc);
|
else fprintf (stderr, " SLC_C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - Capacity Max ", model_str, net, site, reg);
|
||||||
else fprintf (stderr, " SLC_C_SYS_PARMS: %s; Net ID: %d; Site ID: %d; Reg Req: %d;", model_str, net, site, reg);
|
|
||||||
fprintf (stderr, " SYS: %04X;", syscode); //#192
|
|
||||||
|
|
||||||
//add string for ncurses terminal display
|
//add string for ncurses terminal display
|
||||||
// if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d; SYS: %04X; ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, syscode );
|
if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
|
||||||
// else sprintf (state->dmr_site_parms, "TIII - %s %d-%d; SYS: %04X; ", model_str, net, site, syscode);
|
else sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||||
if (n != 0) sprintf (state->dmr_site_parms, "TIII %s:%d-%d.%d;%04X; ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, syscode );
|
|
||||||
else sprintf (state->dmr_site_parms, "TIII %s:%d-%d;%04X; ", model_str, net, site, syscode);
|
|
||||||
|
|
||||||
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
|
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
|
||||||
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
|
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
|
||||||
@@ -952,31 +867,34 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//debug print
|
||||||
|
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
||||||
|
//fprintf (stderr, "\n SYSCODE: %014b", syscode);
|
||||||
|
//fprintf (stderr, "\n SYSCODE: %02b.%b.%b", model, net, site); //won't show leading zeroes, but may not be required
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (slco == 0x3) //P_SYS_Parms
|
else if (slco == 0x3) //P_SYS_Parms
|
||||||
{
|
{
|
||||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
if (n != 0) fprintf (stderr, " SLC_P_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Comp CC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg);
|
||||||
if (n != 0) fprintf (stderr, " SLC_P_SYS_PARMS: %s; Net ID: %d; Site ID: %d.%d; Comp CC: %d;", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg);
|
else fprintf (stderr, " SLC_P_SYS_PARMS - %s - Net ID: %d Site ID: %d - Capacity Max", model_str, net, site);
|
||||||
else fprintf (stderr, " SLC_P_SYS_PARMS: %s; Net ID: %d; Site ID: %d;", model_str, net, site);
|
|
||||||
fprintf (stderr, " SYS: %04X;", syscode); //#192
|
|
||||||
|
|
||||||
//add string for ncurses terminal display
|
//add string for ncurses terminal display
|
||||||
// if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d; SYS: %04X; ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, syscode );
|
if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
|
||||||
// else sprintf (state->dmr_site_parms, "TIII - %s %d-%d; SYS: %04X; ", model_str, net, site, syscode);
|
else sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||||
if (n != 0) sprintf (state->dmr_site_parms, "TIII %s:%d-%d.%d;%04X; ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, syscode );
|
|
||||||
else sprintf (state->dmr_site_parms, "TIII %s:%d-%d;%04X; ", model_str, net, site, syscode);
|
//debug print
|
||||||
|
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
||||||
|
//fprintf (stderr, "\n SYSCODE: %014b", syscode);
|
||||||
|
//fprintf (stderr, "\n SYSCODE: %02b.%b.%b", model, net, site); //won't show leading zeroes, but may not be required
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (slco == 0x0) //null
|
else if (slco == 0x0) //null
|
||||||
fprintf (stderr, " SLCO NULL ");
|
fprintf (stderr, " SLCO NULL ");
|
||||||
else if (slco == 0x1)
|
else if (slco == 0x1)
|
||||||
{
|
fprintf (stderr, " SLCO Activity Update TS1: %X Hash: %02X TS2: %X Hash: %02X", ts1_act, ts1_hash, ts2_act, ts2_hash); //102 361-2 7.1.3.2
|
||||||
fprintf (stderr, " Activity Update"); //102 361-2 7.1.3.2
|
|
||||||
fprintf (stderr, " TS1: %s; Hash: %d;", ts1_str, ts1_hash);
|
|
||||||
fprintf (stderr, " TS2: %s; Hash: %d;", ts2_str, ts2_hash);
|
|
||||||
}
|
|
||||||
else if (slco == 0x9)
|
else if (slco == 0x9)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " SLCO Connect Plus Traffic Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
fprintf (stderr, " SLCO Connect Plus Voice Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
||||||
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,64 +909,17 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if using rtl input, we can ask for the current frequency tuned
|
|
||||||
if (opts->audio_in_type == 3 && opts->p25_is_tuned == 0)
|
|
||||||
{
|
|
||||||
ccfreq = (long int)opts->rtlsdr_center_freq;
|
|
||||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (slco == 0xF)
|
else if (slco == 0xF)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest LSN: %d - RS: %02X", capsite, restchannel, cap_reserved);
|
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest Channel %d - RS: %02X", capsite, restchannel, cap_reserved);
|
||||||
//assign to cc freq if available
|
//assign to cc freq if available
|
||||||
if (state->trunk_chan_map[restchannel] != 0)
|
if (state->trunk_chan_map[restchannel] != 0)
|
||||||
{
|
{
|
||||||
state->p25_cc_freq = state->trunk_chan_map[restchannel];
|
state->p25_cc_freq = state->trunk_chan_map[restchannel];
|
||||||
}
|
}
|
||||||
|
|
||||||
//extra handling for TG hold while trunking enabled
|
|
||||||
if (state->tg_hold != 0 && opts->p25_trunk == 1)
|
|
||||||
{
|
|
||||||
//if both slots are voice,
|
|
||||||
if (state->dmrburstL == 16 && state->dmrburstR == 16)
|
|
||||||
{
|
|
||||||
//but nether is the TG on hold
|
|
||||||
if ( (state->tg_hold != state->lasttg) && (state->tg_hold != state->lasttgR) )
|
|
||||||
{
|
|
||||||
//tune to the current rest channel so we can observe its channel status csbks for the TG on hold
|
|
||||||
if (state->p25_cc_freq != 0)
|
|
||||||
{
|
|
||||||
//RIGCTL
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
|
||||||
}
|
|
||||||
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (slco == 0x08)
|
else if (slco == 0x08)
|
||||||
{
|
{
|
||||||
@@ -1060,60 +931,6 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
|
|
||||||
//add string for ncurses terminal display
|
//add string for ncurses terminal display
|
||||||
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
|
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
|
||||||
|
|
||||||
//extra handling for TG hold while trunking enabled
|
|
||||||
if (state->tg_hold != 0 && opts->p25_trunk == 1)
|
|
||||||
{
|
|
||||||
//if both slots are voice,
|
|
||||||
if (state->dmrburstL == 16 && state->dmrburstR == 16)
|
|
||||||
{
|
|
||||||
//but nether is the TG on hold
|
|
||||||
if ( (state->tg_hold != state->lasttg) && (state->tg_hold != state->lasttgR) )
|
|
||||||
{
|
|
||||||
//convert xpt_free from lcn to lsn -- up to 8 voice repeaters
|
|
||||||
if (xpt_free == 2) xpt_free = 3;
|
|
||||||
else if (xpt_free == 3) xpt_free = 5;
|
|
||||||
else if (xpt_free == 4) xpt_free = 7;
|
|
||||||
else if (xpt_free == 5) xpt_free = 9;
|
|
||||||
else if (xpt_free == 6) xpt_free = 11;
|
|
||||||
else if (xpt_free == 7) xpt_free = 13;
|
|
||||||
else if (xpt_free == 8) xpt_free = 15;
|
|
||||||
|
|
||||||
//check to see if the XPT free channel converted to lsn is available in the map
|
|
||||||
if (state->trunk_chan_map[xpt_free] != 0)
|
|
||||||
{
|
|
||||||
state->p25_cc_freq = state->trunk_chan_map[xpt_free];
|
|
||||||
}
|
|
||||||
|
|
||||||
//tune to the current rest channel so we can observe its channel status csbks for the TG on hold
|
|
||||||
if (state->p25_cc_freq != 0)
|
|
||||||
{
|
|
||||||
//RIGCTL
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
|
||||||
}
|
|
||||||
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else fprintf (stderr, " SLCO Unknown - %d ", slco);
|
else fprintf (stderr, " SLCO Unknown - %d ", slco);
|
||||||
@@ -1135,9 +952,10 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
//externalize embedded alias to keep the flco function relatively clean
|
//externalize embedded alias to keep the flco function relatively clean
|
||||||
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[])
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
|
uint8_t pf;
|
||||||
|
uint8_t res;
|
||||||
uint8_t format = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 2);
|
uint8_t format = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 2);
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
|
|
||||||
@@ -1157,8 +975,6 @@ void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_b
|
|||||||
|
|
||||||
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Embedded Alias: ");
|
fprintf (stderr, " Embedded Alias: ");
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
@@ -1166,7 +982,6 @@ void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_b
|
|||||||
uint8_t format = state->dmr_alias_format[slot]; //0=7-bit; 1=ISO8; 2=UTF-8; 3=UTF16BE
|
uint8_t format = state->dmr_alias_format[slot]; //0=7-bit; 1=ISO8; 2=UTF-8; 3=UTF16BE
|
||||||
uint8_t len = state->dmr_alias_len[slot];
|
uint8_t len = state->dmr_alias_len[slot];
|
||||||
uint8_t start; //starting position depends on context of block and format
|
uint8_t start; //starting position depends on context of block and format
|
||||||
UNUSED(format);
|
|
||||||
|
|
||||||
//Cap Max Variation
|
//Cap Max Variation
|
||||||
uint8_t fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8);
|
uint8_t fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8);
|
||||||
@@ -1223,3 +1038,73 @@ void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_b
|
|||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//externalize embedded GPS - Needs samples to test/fix function
|
||||||
|
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Embedded GPS:");
|
||||||
|
uint8_t slot = state->currentslot;
|
||||||
|
uint8_t pf = lc_bits[0];
|
||||||
|
uint8_t res_a = lc_bits[1];
|
||||||
|
uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4);
|
||||||
|
uint8_t pos_err = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 3);
|
||||||
|
|
||||||
|
uint32_t lon_sign = lc_bits[23];
|
||||||
|
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24);
|
||||||
|
uint32_t lat_sign = lc_bits[48];
|
||||||
|
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
|
||||||
|
|
||||||
|
double lat_unit = (double)180/ pow (2.0, 24); //180 divided by 2^24
|
||||||
|
double lon_unit = (double)360/ pow (2.0, 25); //360 divided by 2^25
|
||||||
|
|
||||||
|
char latstr[3];
|
||||||
|
char lonstr[3];
|
||||||
|
sprintf (latstr, "%s", "N");
|
||||||
|
sprintf (lonstr, "%s", "E");
|
||||||
|
|
||||||
|
//run calculations and print (still cannot verify as accurate)
|
||||||
|
//7.2.16 and 7.2.17 (two's compliment)
|
||||||
|
|
||||||
|
double latitude = 0;
|
||||||
|
double longitude = 0;
|
||||||
|
|
||||||
|
if (pf) fprintf (stderr, " Protected");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lat_sign)
|
||||||
|
{
|
||||||
|
lat = 0x800001 - lat;
|
||||||
|
sprintf (latstr, "%s", "S");
|
||||||
|
}
|
||||||
|
latitude = ((double)lat * lat_unit);
|
||||||
|
|
||||||
|
if (lon_sign)
|
||||||
|
{
|
||||||
|
lon = 0x1000001 - lon;
|
||||||
|
sprintf (lonstr, "%s", "W");
|
||||||
|
}
|
||||||
|
longitude = ((double)lon * lon_unit);
|
||||||
|
|
||||||
|
//sanity check
|
||||||
|
if (abs (latitude) < 90 && abs(longitude) < 180)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Lat: %.5lf %s Lon: %.5lf %s", latitude, latstr, longitude, lonstr);
|
||||||
|
|
||||||
|
//7.2.15 Position Error
|
||||||
|
uint16_t position_error = 2 * pow(10, pos_err); //2 * 10^pos_err
|
||||||
|
if (pos_err == 0x7 ) fprintf (stderr, " Position Error: Unknown or Invalid");
|
||||||
|
else fprintf (stderr, " Position Error: Less than %dm", position_error);
|
||||||
|
|
||||||
|
//save to array for ncurses
|
||||||
|
if (pos_err != 0x7)
|
||||||
|
{
|
||||||
|
sprintf (state->dmr_embedded_gps[slot], "E-GPS (%lf %s %lf %s) Err: %dm", latitude, latstr, longitude, lonstr, position_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
}
|
||||||
|
|||||||
125
src/dmr_le.c
125
src/dmr_le.c
@@ -9,7 +9,7 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
//gather ambe_fr mi fragments for processing
|
//gather ambe_fr mi fragments for processing
|
||||||
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, uint8_t ambe_fr[4][24], uint8_t ambe_fr2[4][24], uint8_t ambe_fr3[4][24])
|
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, char ambe_fr[4][24], char ambe_fr2[4][24], char ambe_fr3[4][24])
|
||||||
{
|
{
|
||||||
|
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
@@ -42,8 +42,6 @@ void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc,
|
|||||||
|
|
||||||
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
int i, j;
|
int i, j;
|
||||||
int g[3];
|
int g[3];
|
||||||
@@ -53,12 +51,6 @@ 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) |
|
||||||
@@ -85,22 +77,12 @@ 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)
|
||||||
@@ -108,11 +90,8 @@ 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 ", state->payload_mi, mi_final);
|
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_mi, mi_final);
|
||||||
if (mi_crc_ok == 1) 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
|
||||||
@@ -127,11 +106,8 @@ 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 ", state->payload_miR, mi_final);
|
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_miR, mi_final);
|
||||||
if (mi_crc_ok == 1) 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
|
||||||
@@ -148,8 +124,6 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
state->dropL = 256;
|
state->dropL = 256;
|
||||||
@@ -189,8 +163,6 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
|
void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
state->dropL = 256;
|
state->dropL = 256;
|
||||||
state->dropR = 256;
|
state->dropR = 256;
|
||||||
state->DMRvcL = 0;
|
state->DMRvcL = 0;
|
||||||
@@ -217,7 +189,6 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
uint8_t crc7_okay = 0; //RC
|
uint8_t crc7_okay = 0; //RC
|
||||||
uint8_t crc3_okay = 0; //TXI
|
uint8_t crc3_okay = 0; //TXI
|
||||||
uint8_t txi = 0; //SEE: https://patents.google.com/patent/US8271009B2
|
uint8_t txi = 0; //SEE: https://patents.google.com/patent/US8271009B2
|
||||||
UNUSED(txi);
|
|
||||||
|
|
||||||
//NOTE: Any previous mentions to Cap+ in this area may have been in error,
|
//NOTE: Any previous mentions to Cap+ in this area may have been in error,
|
||||||
//The signalling observed here was actually TXI information, not Cap+ Specifically
|
//The signalling observed here was actually TXI information, not Cap+ Specifically
|
||||||
@@ -297,7 +268,7 @@ 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; //SEE: https://patents.google.com/patent/EP2347540B1/en
|
uint8_t alg = sbrc_hex & 0x7;
|
||||||
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
|
||||||
|
|
||||||
@@ -307,20 +278,9 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
//NOTE: on above, I belive that we need to check by opcode as well, as a CRC3 can have multiple collisions
|
//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?)
|
//so we need to exclude op/alg 0 and 3 from the check (does algID 0x03/0x23 even exist?)
|
||||||
|
|
||||||
if (opts->dmr_le == 1)
|
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)
|
if (irr_err != 0) fprintf (stderr, "\n%s SLOT %d SB/RC (FEC ERR) %d %s \n", KRED, slot, irr_err, KNRM);
|
||||||
{
|
|
||||||
uint32_t sbrcpl = 0;
|
|
||||||
for(i = 0; i < 32; i++)
|
|
||||||
{
|
|
||||||
sbrcpl = sbrcpl << 1;
|
|
||||||
sbrcpl |= sbrc_interleaved[i] & 1;
|
|
||||||
}
|
|
||||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s SLOT %d SB/RC (FEC ERR) E:%d; I:%08X D:%03X; %s ", KRED, slot+1, irr_err, sbrcpl, sbrc_hex, KNRM);
|
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
|
||||||
}
|
|
||||||
if (irr_err == 0)
|
if (irr_err == 0)
|
||||||
{
|
{
|
||||||
if (sbrc_hex == 0) ; //NULL, do nothing
|
if (sbrc_hex == 0) ; //NULL, do nothing
|
||||||
@@ -339,49 +299,40 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
else if (crc3_okay == 1 && (sbrc_opcode == 0 || sbrc_opcode == 3) )
|
else if (crc3_okay == 1 && (sbrc_opcode == 0 || sbrc_opcode == 3) )
|
||||||
{
|
{
|
||||||
//opcodes -- 0 (NULL), BR Delay (3)
|
//opcodes -- 0 (NULL), BR Delay (3)
|
||||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, " TXI Op: %X - ", sbrc_opcode);
|
||||||
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 if (sbrc_opcode != 0 && sbrc_opcode != 3) //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
|
||||||
{
|
{
|
||||||
if (state->dmr_so & 0x40 && key != 0 && alg != 0)
|
if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
|
||||||
{
|
{
|
||||||
//if we aren't forcing a particular alg or privacy key set
|
//if we aren't forcing a particular alg or privacy key set
|
||||||
if (state->M == 0)
|
if (state->M == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s ", KYEL);
|
||||||
fprintf (stderr, " Slot 1");
|
fprintf (stderr, " Slot 1");
|
||||||
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
|
||||||
if (state->payload_keyid != key)
|
state->payload_keyid = key;
|
||||||
state->payload_keyid = key;
|
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||||
if (state->payload_algid != alg)
|
|
||||||
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -389,21 +340,20 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
|
|
||||||
if (slot == 1) //may not need the state->errs anymore //&& state->errsR < 3
|
if (slot == 1) //may not need the state->errs anymore //&& state->errsR < 3
|
||||||
{
|
{
|
||||||
if (state->dmr_soR & 0x40 && key != 0 && alg != 0)
|
if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
|
||||||
{
|
{
|
||||||
//if we aren't forcing a particular alg or privacy key set
|
//if we aren't forcing a particular alg or privacy key set
|
||||||
if (state->M == 0)
|
if (state->M == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s ", KYEL);
|
||||||
fprintf (stderr, " Slot 2");
|
fprintf (stderr, " Slot 2");
|
||||||
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
|
||||||
if (state->payload_keyidR != key)
|
state->payload_keyidR = key;
|
||||||
state->payload_keyidR = key;
|
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||||
if (state->payload_algidR != alg)
|
|
||||||
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -458,26 +408,3 @@ 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
|
|
||||||
}
|
|
||||||
|
|||||||
124
src/dmr_ms.c
124
src/dmr_ms.c
@@ -13,31 +13,39 @@
|
|||||||
void dmrMS (dsd_opts * opts, dsd_state * state)
|
void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i, j, dibit;
|
int i, j, k, l, dibit;
|
||||||
|
int *dibit_p;
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
char ambe_fr2[4][24];
|
char ambe_fr2[4][24];
|
||||||
char ambe_fr3[4][24];
|
char ambe_fr3[4][24];
|
||||||
char ambe_fr4[4][24];
|
char ambe_fr4[4][24];
|
||||||
|
|
||||||
//memcpy of ambe_fr for late entry
|
//memcpy of ambe_fr for late entry
|
||||||
uint8_t m1[4][24];
|
char m1[4][24];
|
||||||
uint8_t m2[4][24];
|
char m2[4][24];
|
||||||
uint8_t m3[4][24];
|
char m3[4][24];
|
||||||
|
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
char sync[25];
|
char sync[25];
|
||||||
char syncdata[48];
|
char syncdata[48];
|
||||||
uint8_t EmbeddedSignalling[16];
|
char EmbeddedSignalling[16];
|
||||||
|
|
||||||
//cach
|
//cach
|
||||||
char cachdata[25];
|
char cachdata[25];
|
||||||
|
int cachInterleave[24] =
|
||||||
|
{0, 7, 8, 9, 1, 10,
|
||||||
|
11, 12, 2, 13, 14,
|
||||||
|
15, 3, 16, 4, 17, 18,
|
||||||
|
19, 5, 20, 21, 22, 6, 23
|
||||||
|
};
|
||||||
|
|
||||||
//cach tact bits
|
//cach tact bits
|
||||||
uint8_t tact_bits[7];
|
uint8_t tact_bits[7];
|
||||||
|
|
||||||
|
uint8_t emb_ok = 0;
|
||||||
uint8_t tact_okay = 0;
|
uint8_t tact_okay = 0;
|
||||||
|
uint8_t cach_err = 0;
|
||||||
uint8_t EmbeddedSignallingOk = 0;
|
uint8_t EmbeddedSignallingOk = 0;
|
||||||
UNUSED(EmbeddedSignallingOk);
|
|
||||||
|
|
||||||
uint8_t internalslot;
|
uint8_t internalslot;
|
||||||
uint8_t vc;
|
uint8_t vc;
|
||||||
@@ -46,13 +54,13 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t cc = 25;
|
uint8_t cc = 25;
|
||||||
uint8_t power = 9; //power and pre-emption indicator
|
uint8_t power = 9; //power and pre-emption indicator
|
||||||
uint8_t lcss = 9;
|
uint8_t lcss = 9;
|
||||||
UNUSED2(cc, lcss);
|
|
||||||
|
|
||||||
//dummy bits to pass to dburst for link control
|
//dummy bits to pass to dburst for link control
|
||||||
uint8_t dummy_bits[196];
|
uint8_t dummy_bits[196];
|
||||||
memset (dummy_bits, 0, sizeof (dummy_bits));
|
memset (dummy_bits, 0, sizeof (dummy_bits));
|
||||||
|
|
||||||
//add time to mirror printFrameSync
|
//add time to mirror printFrameSync
|
||||||
|
time_t now;
|
||||||
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);
|
||||||
@@ -70,6 +78,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
vc = 2;
|
vc = 2;
|
||||||
|
|
||||||
|
short int skipcount = 0;
|
||||||
|
|
||||||
//Hardset variables for MS/Mono
|
//Hardset variables for MS/Mono
|
||||||
state->currentslot = 0; //0
|
state->currentslot = 0; //0
|
||||||
|
|
||||||
@@ -280,50 +290,17 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->directmode == 0)
|
if (state->directmode == 0)
|
||||||
{
|
{
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
|
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Consider copying f_l to f_r for left and right channel saturation on MS mode
|
|
||||||
if (opts->floating_point == 0)
|
|
||||||
{
|
|
||||||
// memcpy (state->s_r4, state->s_l4, sizeof(state->s_l4));
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS3(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
{
|
|
||||||
// memcpy (state->f_r4, state->f_l4, sizeof(state->f_l4));
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS3(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vc == 6)
|
if (vc == 6)
|
||||||
{
|
{
|
||||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||||
@@ -391,7 +368,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
//collect buffered 1st half and get 2nd half voice payload and then jump to full MS Voice decoding.
|
//collect buffered 1st half and get 2nd half voice payload and then jump to full MS Voice decoding.
|
||||||
void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
int i, dibit;
|
int i, j, k, l, dibit;
|
||||||
int *dibit_p;
|
int *dibit_p;
|
||||||
|
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
@@ -404,17 +381,35 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||||
|
|
||||||
//memcpy of ambe_fr for late entry
|
//memcpy of ambe_fr for late entry
|
||||||
uint8_t m1[4][24];
|
char m1[4][24];
|
||||||
uint8_t m2[4][24];
|
char m2[4][24];
|
||||||
uint8_t m3[4][24];
|
char m3[4][24];
|
||||||
|
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
|
char sync[25];
|
||||||
|
char syncdata[48];
|
||||||
|
|
||||||
//cach
|
//cach
|
||||||
char cachdata[25];
|
char cachdata[25];
|
||||||
UNUSED(cachdata);
|
int cachInterleave[24] =
|
||||||
|
{0, 7, 8, 9, 1, 10,
|
||||||
|
11, 12, 2, 13, 14,
|
||||||
|
15, 3, 16, 4, 17, 18,
|
||||||
|
19, 5, 20, 21, 22, 6, 23
|
||||||
|
};
|
||||||
|
|
||||||
|
int mutecurrentslot;
|
||||||
|
int msMode;
|
||||||
|
char cc[4];
|
||||||
|
char EmbeddedSignalling[16];
|
||||||
|
|
||||||
|
uint8_t emb_ok = 0;
|
||||||
|
uint8_t tact_okay = 0;
|
||||||
|
uint8_t cach_err = 0;
|
||||||
|
uint8_t EmbeddedSignallingOk = 0;
|
||||||
|
|
||||||
//add time to mirror sync
|
//add time to mirror sync
|
||||||
|
time_t now;
|
||||||
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);
|
||||||
@@ -590,48 +585,14 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->directmode == 0)
|
if (state->directmode == 0)
|
||||||
{
|
{
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
|
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//TODO: Consider copying f_l to f_r for left and right channel saturation on MS mode
|
|
||||||
if (opts->floating_point == 0)
|
|
||||||
{
|
|
||||||
// memcpy (state->s_r4, state->s_l4, sizeof(state->s_l4));
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS3(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
{
|
|
||||||
// memcpy (state->f_r4, state->f_l4, sizeof(state->f_l4));
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS3(opts, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//collect the mi fragment
|
//collect the mi fragment
|
||||||
@@ -648,11 +609,12 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
//simplied to a simple data collector, and then passed on to dmr_data_sync for the usual processing
|
//simplied to a simple data collector, and then passed on to dmr_data_sync for the usual processing
|
||||||
void dmrMSData (dsd_opts * opts, dsd_state * state)
|
void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
int i;
|
int i, b, c;
|
||||||
int dibit;
|
int dibit;
|
||||||
int *dibit_p;
|
int *dibit_p;
|
||||||
|
|
||||||
//add time to mirror sync
|
//add time to mirror sync
|
||||||
|
time_t now;
|
||||||
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);
|
||||||
|
|||||||
@@ -38,7 +38,11 @@ char * getDateL(void) {
|
|||||||
void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
|
void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
uint8_t message_len = 0;
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
|
uint8_t blocks = state->data_header_blocks[slot];
|
||||||
|
uint8_t padding = state->data_header_padding[slot];
|
||||||
|
uint8_t lrrp_conf = 0;
|
||||||
|
|
||||||
//check for more available flag info, etc on these prior to running
|
//check for more available flag info, etc on these prior to running
|
||||||
if (DMR_PDU[0] == 0x01) dmr_locn (opts, state, block_len, DMR_PDU);
|
if (DMR_PDU[0] == 0x01) dmr_locn (opts, state, block_len, DMR_PDU);
|
||||||
@@ -55,7 +59,7 @@ void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR
|
|||||||
//this is by no means an extensive LRRP list and is prone to error (unless somebody has the manual or something)
|
//this is by no means an extensive LRRP list and is prone to error (unless somebody has the manual or something)
|
||||||
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
|
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
|
||||||
{
|
{
|
||||||
int i;
|
int i, j;
|
||||||
uint16_t message_len = 0;
|
uint16_t message_len = 0;
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
uint8_t blocks = state->data_header_blocks[slot];
|
uint8_t blocks = state->data_header_blocks[slot];
|
||||||
@@ -88,11 +92,10 @@ void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DM
|
|||||||
int lat_sign = 1; //positive 1, or negative 1
|
int lat_sign = 1; //positive 1, or negative 1
|
||||||
int lon_sign = 1; //positive 1, or negative 1
|
int lon_sign = 1; //positive 1, or negative 1
|
||||||
|
|
||||||
//speed -- NOTE: Velocity is Speed + Direction
|
//speed/velocity
|
||||||
uint16_t vel = 0;
|
uint16_t vel = 0;
|
||||||
double velocity = 0;
|
double velocity = 0;
|
||||||
uint8_t vel_set = 0;
|
uint8_t vel_set = 0;
|
||||||
UNUSED(vel);
|
|
||||||
|
|
||||||
//track, direction, degrees
|
//track, direction, degrees
|
||||||
uint8_t degrees = 0;
|
uint8_t degrees = 0;
|
||||||
@@ -237,8 +240,8 @@ void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DM
|
|||||||
case 0x6C: //speed-hor
|
case 0x6C: //speed-hor
|
||||||
if (message_len > 0 && vel_set == 0)
|
if (message_len > 0 && vel_set == 0)
|
||||||
{
|
{
|
||||||
vel = (DMR_PDU[i+1] << 8) + DMR_PDU[i+2]; //raw value
|
vel = (DMR_PDU[i+1] << 8) + DMR_PDU[i+2]; //don't think this is meant to be shifted, but doing it anyways for comparison
|
||||||
velocity = ( ((double)( (DMR_PDU[i+1] << 8) + DMR_PDU[i+2] )) / ( (double)255.0f)); //mps
|
velocity = ( ((double)( (DMR_PDU[i+1] ) + DMR_PDU[i+2] )) / ( (double)128));
|
||||||
vel_set = 1;
|
vel_set = 1;
|
||||||
i += 2;
|
i += 2;
|
||||||
lrrp_confidence++;
|
lrrp_confidence++;
|
||||||
@@ -346,20 +349,12 @@ void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DM
|
|||||||
fprintf (stderr, " Lon: %.5lf", lon_fin);
|
fprintf (stderr, " Lon: %.5lf", lon_fin);
|
||||||
fprintf (stderr, " (%.5lf, %.5lf)", lat_fin , lon_fin);
|
fprintf (stderr, " (%.5lf, %.5lf)", lat_fin , lon_fin);
|
||||||
|
|
||||||
// if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
// {
|
{
|
||||||
// fprintf (pFile, "%.5lf\t", lat_fin);
|
fprintf (pFile, "%.5lf\t", lat_fin);
|
||||||
// fprintf (pFile, "%.5lf\t", lon_fin);
|
fprintf (pFile, "%.5lf\t", lon_fin);
|
||||||
// }
|
}
|
||||||
|
|
||||||
}
|
|
||||||
//always print into the lrrp file, even if zeroes, keep alignment correct
|
|
||||||
if (opts->lrrp_file_output == 1)
|
|
||||||
{
|
|
||||||
fprintf (pFile, "%.5lf\t", lat_fin);
|
|
||||||
fprintf (pFile, "%.5lf\t", lon_fin);
|
|
||||||
//
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
if (rad)
|
if (rad)
|
||||||
{
|
{
|
||||||
@@ -374,19 +369,15 @@ void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DM
|
|||||||
if (vel_set)
|
if (vel_set)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, " LRRP - Speed: %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity));
|
fprintf (stderr, " LRRP - Velocity: %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity));
|
||||||
// if (opts->lrrp_file_output == 1) fprintf (pFile, "%.3lf\t ", (velocity * 3.6) );
|
if (opts->lrrp_file_output == 1) fprintf (pFile, "%.3lf\t ", (velocity * 3.6) );
|
||||||
}
|
}
|
||||||
//always print into the lrrp file, even if zeroes, keep alignment correct
|
|
||||||
if (opts->lrrp_file_output == 1) fprintf (pFile, "%.3lf\t ", (velocity * 3.6) );
|
|
||||||
if (deg_set)
|
if (deg_set)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, " LRRP - Track: %d%s", degrees, deg_glyph);
|
fprintf (stderr, " LRRP - Track: %d%s", degrees, deg_glyph);
|
||||||
// if (opts->lrrp_file_output == 1) fprintf (pFile, "%d\t",degrees);
|
if (opts->lrrp_file_output == 1) fprintf (pFile, "%d\t",degrees);
|
||||||
}
|
}
|
||||||
//always print into the lrrp file, even if zeroes, keep alignment correct
|
|
||||||
if (opts->lrrp_file_output == 1) fprintf (pFile, "%d\t",degrees);
|
|
||||||
|
|
||||||
//close open file
|
//close open file
|
||||||
if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
@@ -418,15 +409,15 @@ void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DM
|
|||||||
fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report);
|
fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRRP_END:
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
|
void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
int i, j;
|
||||||
|
|
||||||
int i;
|
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
uint8_t blocks = state->data_header_blocks[slot];
|
uint8_t blocks = state->data_header_blocks[slot];
|
||||||
uint8_t padding = state->data_header_padding[slot];
|
uint8_t padding = state->data_header_padding[slot];
|
||||||
@@ -476,7 +467,8 @@ void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DM
|
|||||||
//N is positive, E is positive?? Assuming its like a 2D plane
|
//N is positive, E is positive?? Assuming its like a 2D plane
|
||||||
int lat_sign = 1; //positive 1 or negative 1
|
int lat_sign = 1; //positive 1 or negative 1
|
||||||
int lon_sign = 1; //positive 1 or negative 1
|
int lon_sign = 1; //positive 1 or negative 1
|
||||||
UNUSED2(lat_sign, lon_sign);
|
double lat_fin = 0;
|
||||||
|
double lon_fin = 0;
|
||||||
|
|
||||||
//start looking for specific bytes corresponding to 'letters' A (time), NSEW (ordinal directions), etc
|
//start looking for specific bytes corresponding to 'letters' A (time), NSEW (ordinal directions), etc
|
||||||
for (i = 0; i < ( (blocks*block_len) - (padding+4) ); i++)
|
for (i = 0; i < ( (blocks*block_len) - (padding+4) ); i++)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||||
{
|
{
|
||||||
UNUSED2(opts, CRCCorrect);
|
|
||||||
|
|
||||||
if((IrrecoverableErrors == 0))
|
if((IrrecoverableErrors == 0))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,10 +53,15 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
|||||||
uint32_t CCH_EmergencyPriority[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
uint32_t CCH_EmergencyPriority[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
||||||
uint32_t CCH_Reserved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
uint32_t CCH_Reserved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
||||||
uint32_t CCH_SlowData[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
uint32_t CCH_SlowData[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
||||||
|
uint32_t *errs;
|
||||||
|
uint32_t *errs2;
|
||||||
|
uint8_t AmbeBitDescrambled[49] = {0};
|
||||||
|
uint32_t ScramblerKey = 0;
|
||||||
uint32_t PartOfSuperFrame = 0;
|
uint32_t PartOfSuperFrame = 0;
|
||||||
|
uint32_t VoiceFrameFlag = 1; /* We consider the current frame as a voice frame */
|
||||||
|
uint32_t AttachedDataFlag = 0;
|
||||||
uint8_t CalledID[8] = {0};
|
uint8_t CalledID[8] = {0};
|
||||||
uint8_t CallingID[8] = {0};
|
uint8_t CallingID[8] = {0};
|
||||||
UNUSED(PartOfSuperFrame);
|
|
||||||
|
|
||||||
/* First CCH (Control CHannel) - 72 bit */
|
/* First CCH (Control CHannel) - 72 bit */
|
||||||
k = 0;
|
k = 0;
|
||||||
@@ -477,10 +482,6 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
|||||||
for(i = start; i < end; i++)
|
for(i = start; i < end; i++)
|
||||||
{
|
{
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
|
||||||
if (opts->floating_point == 0)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//set the correct sync type again and flag off the cipher
|
//set the correct sync type again and flag off the cipher
|
||||||
|
|||||||
245
src/dsd_audio.c
245
src/dsd_audio.c
@@ -21,13 +21,14 @@ pa_sample_spec ss;
|
|||||||
pa_sample_spec tt;
|
pa_sample_spec tt;
|
||||||
pa_sample_spec zz;
|
pa_sample_spec zz;
|
||||||
pa_sample_spec cc;
|
pa_sample_spec cc;
|
||||||
pa_sample_spec ff; //float
|
|
||||||
|
|
||||||
void closePulseOutput (dsd_opts * opts)
|
void closePulseOutput (dsd_opts * opts)
|
||||||
{
|
{
|
||||||
pa_simple_free (opts->pulse_digi_dev_out);
|
pa_simple_free (opts->pulse_digi_dev_out);
|
||||||
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) //EDACS analog calls and/or monitoring source analog audio
|
if (opts->dmr_stereo == 1)
|
||||||
pa_simple_free (opts->pulse_raw_dev_out);
|
{
|
||||||
|
pa_simple_free (opts->pulse_digi_dev_outR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closePulseInput (dsd_opts * opts)
|
void closePulseInput (dsd_opts * opts)
|
||||||
@@ -39,29 +40,33 @@ void openPulseOutput(dsd_opts * opts)
|
|||||||
{
|
{
|
||||||
|
|
||||||
ss.format = PA_SAMPLE_S16NE;
|
ss.format = PA_SAMPLE_S16NE;
|
||||||
ss.channels = opts->pulse_raw_out_channels;
|
ss.channels = opts->pulse_raw_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
|
||||||
ss.rate = opts->pulse_raw_rate_out;
|
ss.rate = opts->pulse_raw_rate_out; //48000
|
||||||
|
|
||||||
tt.format = PA_SAMPLE_S16NE;
|
tt.format = PA_SAMPLE_S16NE;
|
||||||
tt.channels = opts->pulse_digi_out_channels;
|
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;
|
tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
|
||||||
|
|
||||||
ff.format = PA_SAMPLE_FLOAT32NE;
|
if (opts->monitor_input_audio == 1)
|
||||||
ff.channels = opts->pulse_digi_out_channels;
|
{
|
||||||
ff.rate = opts->pulse_digi_rate_out;
|
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
//reconfigured to open when using edacs or raw analog monitor so we can have a analog audio out that runs at 48k1 and not 8k1 float/short
|
//tt
|
||||||
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
|
pa_channel_map* left = 0; //NULL and 0 are same in this context
|
||||||
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Analog", &ss, 0, NULL, NULL);
|
pa_channel_map* right = 0; //NULL and 0 are same in this context
|
||||||
|
|
||||||
pa_channel_map* fl = 0; //NULL and 0 are same in this context
|
if (opts->dmr_stereo == 0)
|
||||||
pa_channel_map* ss = 0; //NULL and 0 are same in this context
|
{
|
||||||
|
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, left, NULL, NULL);
|
||||||
|
|
||||||
if (opts->floating_point == 0)
|
}
|
||||||
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, ss, NULL, NULL);
|
|
||||||
|
|
||||||
if (opts->floating_point == 1)
|
if (opts->dmr_stereo == 1)
|
||||||
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &ff, fl, NULL, NULL);
|
{
|
||||||
|
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME1", PA_STREAM_PLAYBACK, NULL, "XDMA SLOT 1", &tt, left, NULL, NULL);
|
||||||
|
opts->pulse_digi_dev_outR = pa_simple_new(NULL, "DSD-FME2", PA_STREAM_PLAYBACK, NULL, "XDMA SLOT 2", &tt, right, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,121 +81,6 @@ void openPulseInput(dsd_opts * opts)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void openOSSOutput (dsd_opts * opts)
|
|
||||||
{
|
|
||||||
int fmt;
|
|
||||||
int speed = 48000;
|
|
||||||
if (opts->audio_in_type == 5) //if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0)) or 'split' == 0
|
|
||||||
{
|
|
||||||
|
|
||||||
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "OSS Output %s.\n", opts->audio_out_dev);
|
|
||||||
opts->audio_out_fd = open (opts->audio_out_dev, O_RDWR);
|
|
||||||
if (opts->audio_out_fd == -1)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Error, couldn't open #1 %s\n", opts->audio_out_dev);
|
|
||||||
opts->audio_out = 0;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = 0;
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl reset error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = speed;
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl speed error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = 0; //this seems okay to be 1 or 0, not sure what the difference really is (works in stereo on 0)
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl stereo error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = AFMT_S16_LE;
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl setfmt error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
opts->audio_out_type = 5; //5 for 1 channel - 48k OSS 16-bit short output (matching with input)
|
|
||||||
opts->pulse_digi_rate_out = 48000; //this is used to force to upsample and also allow source audio monitor conditional check
|
|
||||||
opts->pulse_digi_out_channels = 1; //this is used to allow source audio monitor conditional check
|
|
||||||
opts->audio_gain = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->audio_in_type != 5) //split == 1
|
|
||||||
{
|
|
||||||
|
|
||||||
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "OSS Output %s.\n", opts->audio_out_dev);
|
|
||||||
opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY);
|
|
||||||
if (opts->audio_out_fd == -1)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Error, couldn't open %s\n", opts->audio_out_dev);
|
|
||||||
opts->audio_out = 0;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Setup the device. Note that it's important to set the sample format, number of channels and sample rate exactly in this order. Some devices depend on the order.
|
|
||||||
|
|
||||||
fmt = 0;
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl reset error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = AFMT_S16_LE; //Sample Format
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl setfmt error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt = opts->pulse_digi_out_channels; //number of channels //was 2
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_CHANNELS, &fmt) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl channel error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//if using split with OSS output, and using EDACS w/ Analog, we have to use 48k
|
|
||||||
if (opts->frame_provoice == 1)
|
|
||||||
opts->pulse_digi_rate_out = 48000;
|
|
||||||
|
|
||||||
speed = opts->pulse_digi_rate_out; //since we have split input/output, we want to mirror pulse rate out
|
|
||||||
fmt = speed; //output rate
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl speed error \n");
|
|
||||||
}
|
|
||||||
if (opts->pulse_digi_out_channels == 2)
|
|
||||||
fmt = 1;
|
|
||||||
else fmt = 0;
|
|
||||||
|
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ioctl stereo error \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Multiple output returns based on 8k/1, 8k/2, or maybe 48k/1? (2,3,5)??
|
|
||||||
if (opts->pulse_digi_out_channels == 2)
|
|
||||||
opts->audio_out_type = 2; //2 for 2 channel 8k OSS 16-bit short output
|
|
||||||
else if (opts->frame_m17 == 1)
|
|
||||||
opts->audio_out_type = 2;
|
|
||||||
else opts->audio_out_type = 5;
|
|
||||||
|
|
||||||
//debug
|
|
||||||
fprintf (stderr, "Using OSS Output with %dk/%d channel configuration.\n", opts->pulse_digi_rate_out, opts->pulse_digi_out_channels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
processAudio (dsd_opts * opts, dsd_state * state)
|
processAudio (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
@@ -282,7 +172,8 @@ processAudio (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
// copy audio data to output buffer and upsample if necessary
|
// copy audio data to output buffer and upsample if necessary
|
||||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||||
//we only want to upsample when using sample rates greater than 8k for output
|
//we only want to upsample when using sample rates greater than 8k for output,
|
||||||
|
//hard set to 8k for RTL mono and MBE playback, otherwise crackling may occur.
|
||||||
if (opts->pulse_digi_rate_out > 8000)
|
if (opts->pulse_digi_rate_out > 8000)
|
||||||
{
|
{
|
||||||
for (n = 0; n < 160; n++)
|
for (n = 0; n < 160; n++)
|
||||||
@@ -306,8 +197,6 @@ processAudio (dsd_opts * opts, dsd_state * state)
|
|||||||
*state->audio_out_float_buf_p = -32768.0F;
|
*state->audio_out_float_buf_p = -32768.0F;
|
||||||
}
|
}
|
||||||
*state->audio_out_buf_p = (short) *state->audio_out_float_buf_p;
|
*state->audio_out_buf_p = (short) *state->audio_out_float_buf_p;
|
||||||
//tap the pointer here and store the short upsample buffer samples
|
|
||||||
state->s_lu[n] = (short) *state->audio_out_float_buf_p;
|
|
||||||
state->audio_out_buf_p++;
|
state->audio_out_buf_p++;
|
||||||
state->audio_out_float_buf_p++;
|
state->audio_out_float_buf_p++;
|
||||||
}
|
}
|
||||||
@@ -326,10 +215,6 @@ processAudio (dsd_opts * opts, dsd_state * state)
|
|||||||
*state->audio_out_temp_buf_p = -32768.0F;
|
*state->audio_out_temp_buf_p = -32768.0F;
|
||||||
}
|
}
|
||||||
*state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p;
|
*state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p;
|
||||||
//tap the pointer here and store the short buffer samples
|
|
||||||
state->s_l[n] = (short) *state->audio_out_temp_buf_p;
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " %d", state->s_l[n]);
|
|
||||||
state->audio_out_buf_p++;
|
state->audio_out_buf_p++;
|
||||||
state->audio_out_temp_buf_p++;
|
state->audio_out_temp_buf_p++;
|
||||||
state->audio_out_idx++;
|
state->audio_out_idx++;
|
||||||
@@ -430,6 +315,7 @@ processAudioR (dsd_opts * opts, dsd_state * state)
|
|||||||
// copy audio data to output buffer and upsample if necessary
|
// copy audio data to output buffer and upsample if necessary
|
||||||
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
|
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
|
||||||
//we only want to upsample when using sample rates greater than 8k for output,
|
//we only want to upsample when using sample rates greater than 8k for output,
|
||||||
|
//hard set to 8k for RTL mono and MBE playback, otherwise crackling may occur.
|
||||||
if (opts->pulse_digi_rate_out > 8000)
|
if (opts->pulse_digi_rate_out > 8000)
|
||||||
{
|
{
|
||||||
for (n = 0; n < 160; n++)
|
for (n = 0; n < 160; n++)
|
||||||
@@ -453,8 +339,6 @@ processAudioR (dsd_opts * opts, dsd_state * state)
|
|||||||
*state->audio_out_float_buf_pR = -32768.0F;
|
*state->audio_out_float_buf_pR = -32768.0F;
|
||||||
}
|
}
|
||||||
*state->audio_out_buf_pR = (short) *state->audio_out_float_buf_pR;
|
*state->audio_out_buf_pR = (short) *state->audio_out_float_buf_pR;
|
||||||
//tap the pointer here and store the short upsample buffer samples
|
|
||||||
state->s_ru[n] = (short) *state->audio_out_float_buf_pR;
|
|
||||||
state->audio_out_buf_pR++;
|
state->audio_out_buf_pR++;
|
||||||
state->audio_out_float_buf_pR++;
|
state->audio_out_float_buf_pR++;
|
||||||
}
|
}
|
||||||
@@ -473,8 +357,6 @@ processAudioR (dsd_opts * opts, dsd_state * state)
|
|||||||
*state->audio_out_temp_buf_pR = -32768.0F;
|
*state->audio_out_temp_buf_pR = -32768.0F;
|
||||||
}
|
}
|
||||||
*state->audio_out_buf_pR = (short) *state->audio_out_temp_buf_pR;
|
*state->audio_out_buf_pR = (short) *state->audio_out_temp_buf_pR;
|
||||||
//tap the pointer here and store the short buffer samples
|
|
||||||
state->s_r[n] = (short) *state->audio_out_temp_buf_pR;
|
|
||||||
state->audio_out_buf_pR++;
|
state->audio_out_buf_pR++;
|
||||||
state->audio_out_temp_buf_pR++;
|
state->audio_out_temp_buf_pR++;
|
||||||
state->audio_out_idxR++;
|
state->audio_out_idxR++;
|
||||||
@@ -541,9 +423,10 @@ void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample)
|
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
int n;
|
||||||
|
short aout_buf[160];
|
||||||
|
short *aout_buf_p;
|
||||||
|
|
||||||
//short aout_buf[160];
|
|
||||||
//sf_write_short(opts->wav_out_raw, aout_buf, 160);
|
//sf_write_short(opts->wav_out_raw, aout_buf, 160);
|
||||||
|
|
||||||
//only write if actual audio, truncate silence
|
//only write if actual audio, truncate silence
|
||||||
@@ -558,26 +441,12 @@ void
|
|||||||
playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
UNUSED(result);
|
|
||||||
|
|
||||||
//don't synthesize voice if slot is turned off
|
|
||||||
if (opts->slot1_on == 0)
|
|
||||||
{
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
|
||||||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
|
||||||
state->audio_out_idx2 = 0;
|
|
||||||
state->audio_out_idx = 0;
|
|
||||||
goto end_psv;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->audio_out_idx > opts->delay)
|
if (state->audio_out_idx > opts->delay)
|
||||||
{
|
{
|
||||||
if (opts->audio_out_type == 5) //OSS
|
if (opts->audio_out_type == 5) //OSS
|
||||||
{
|
{
|
||||||
//OSS 48k/1
|
//OSS
|
||||||
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
||||||
state->audio_out_idx = 0;
|
state->audio_out_idx = 0;
|
||||||
}
|
}
|
||||||
@@ -586,18 +455,11 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
|||||||
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL);
|
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL);
|
||||||
state->audio_out_idx = 0;
|
state->audio_out_idx = 0;
|
||||||
}
|
}
|
||||||
else if (opts->audio_out_type == 8) //UDP Audio Out -- Forgot some things still use this for now
|
|
||||||
{
|
|
||||||
udp_socket_blaster (opts, state, (state->audio_out_idx * 2), (state->audio_out_buf_p - state->audio_out_idx));
|
|
||||||
state->audio_out_idx = 0;
|
|
||||||
}
|
|
||||||
else state->audio_out_idx = 0; //failsafe for audio_out == 0
|
else state->audio_out_idx = 0; //failsafe for audio_out == 0
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end_psv:
|
|
||||||
|
|
||||||
if (state->audio_out_idx2 >= 800000)
|
if (state->audio_out_idx2 >= 800000)
|
||||||
{
|
{
|
||||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||||
@@ -613,15 +475,14 @@ void
|
|||||||
playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
UNUSED(result);
|
|
||||||
|
|
||||||
if (state->audio_out_idxR > opts->delay)
|
if (state->audio_out_idxR > opts->delay)
|
||||||
{
|
{
|
||||||
// output synthesized speech to sound card
|
// output synthesized speech to sound card
|
||||||
if (opts->audio_out_type == 5) //OSS
|
if (opts->audio_out_type == 5) //OSS
|
||||||
{
|
{
|
||||||
//OSS 48k/1
|
//OSS
|
||||||
result = write (opts->audio_out_fd, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2));
|
result = write (opts->audio_out_fdR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2));
|
||||||
state->audio_out_idxR = 0;
|
state->audio_out_idxR = 0;
|
||||||
}
|
}
|
||||||
else if (opts->audio_out_type == 0)
|
else if (opts->audio_out_type == 0)
|
||||||
@@ -629,11 +490,6 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
|||||||
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL);
|
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL);
|
||||||
state->audio_out_idxR = 0;
|
state->audio_out_idxR = 0;
|
||||||
}
|
}
|
||||||
else if (opts->audio_out_type == 8) //UDP Audio Out -- Not sure how this would handle, but R never gets called anymore, so just here for symmetry
|
|
||||||
{
|
|
||||||
udp_socket_blaster (opts, state, (state->audio_out_idxR * 2), (state->audio_out_buf_pR - state->audio_out_idxR));
|
|
||||||
state->audio_out_idxR = 0;
|
|
||||||
}
|
|
||||||
else state->audio_out_idxR = 0; //failsafe for audio_out == 0
|
else state->audio_out_idxR = 0; //failsafe for audio_out == 0
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -651,8 +507,6 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
|||||||
void
|
void
|
||||||
openAudioOutDevice (dsd_opts * opts, int speed)
|
openAudioOutDevice (dsd_opts * opts, int speed)
|
||||||
{
|
{
|
||||||
UNUSED(speed);
|
|
||||||
|
|
||||||
//converted to handle any calls to use portaudio
|
//converted to handle any calls to use portaudio
|
||||||
if(strncmp(opts->audio_out_dev, "pa:", 3) == 0)
|
if(strncmp(opts->audio_out_dev, "pa:", 3) == 0)
|
||||||
{
|
{
|
||||||
@@ -667,7 +521,7 @@ openAudioOutDevice (dsd_opts * opts, int speed)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
// if(stat(opts->audio_out_dev, &stat_buf) != 0 && strncmp(opts->audio_out_dev, "pulse", 5 != 0)) //HERE
|
// if(stat(opts->audio_out_dev, &stat_buf) != 0 && strncmp(opts->audio_out_dev, "pulse", 5 != 0)) //HERE
|
||||||
// {
|
// {
|
||||||
// fprintf (stderr,"Error, couldn't open %s\n", opts->audio_out_dev);
|
// fprintf (stderr,"Error, couldn't open %s\n", opts->audio_out_dev);
|
||||||
@@ -728,23 +582,22 @@ openAudioInDevice (dsd_opts * opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// else if (strncmp(opts->audio_in_dev, "udp", 3) == 0)
|
else if (strncmp(opts->audio_in_dev, "udp", 3) == 0)
|
||||||
// {
|
{
|
||||||
// opts->audio_in_type = 6;
|
opts->audio_in_type = 6;
|
||||||
// opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
||||||
// opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
|
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
|
||||||
// opts->audio_in_file_info->channels=1;
|
opts->audio_in_file_info->channels=1;
|
||||||
// opts->audio_in_file_info->seekable=0;
|
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_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||||||
// opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||||
|
|
||||||
// if(opts->udp_file_in == NULL)
|
|
||||||
// {
|
|
||||||
// fprintf(stderr, "Error, couldn't open UDP with libsndfile: %s\n", sf_strerror(NULL));
|
|
||||||
// exit(1);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
if(opts->udp_file_in == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error, couldn't open UDP with libsndfile: %s\n", sf_strerror(NULL));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0)
|
else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0)
|
||||||
{
|
{
|
||||||
#ifdef USE_RTLSDR
|
#ifdef USE_RTLSDR
|
||||||
|
|||||||
1412
src/dsd_audio2.c
1412
src/dsd_audio2.c
File diff suppressed because it is too large
Load Diff
@@ -118,8 +118,6 @@ print_datascope(dsd_opts* opts, dsd_state* state, int* sbuf2)
|
|||||||
static void
|
static void
|
||||||
use_symbol (dsd_opts* opts, dsd_state* state, int symbol)
|
use_symbol (dsd_opts* opts, dsd_state* state, int symbol)
|
||||||
{
|
{
|
||||||
UNUSED(symbol);
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int sbuf2[128];
|
int sbuf2[128];
|
||||||
int lmin, lmax, lsum;
|
int lmin, lmax, lsum;
|
||||||
@@ -219,7 +217,8 @@ invert_dibit(int dibit)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||||
|
//int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||||
{
|
{
|
||||||
// determine dibit state
|
// determine dibit state
|
||||||
if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18) || (state->synctype == 37))
|
if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18) || (state->synctype == 37))
|
||||||
@@ -287,11 +286,8 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
|||||||
|
|
||||||
valid = 0;
|
valid = 0;
|
||||||
|
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
||||||
// if (state->synctype == 1 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
if (state->synctype == 1 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
||||||
if (state->synctype == 1 && opts->use_heuristics == 1)
|
|
||||||
{
|
{
|
||||||
// Use the P25p1 heuristics if available
|
// Use the P25p1 heuristics if available
|
||||||
valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
|
valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||||
@@ -357,8 +353,7 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
|||||||
valid = 0;
|
valid = 0;
|
||||||
|
|
||||||
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
||||||
// if (state->synctype == 0 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
if (state->synctype == 0 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
||||||
if (state->synctype == 0 && opts->use_heuristics == 1)
|
|
||||||
{
|
{
|
||||||
// Use the P25p1 heuristics if available
|
// Use the P25p1 heuristics if available
|
||||||
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
|
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||||
@@ -455,7 +450,7 @@ get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_s
|
|||||||
}
|
}
|
||||||
|
|
||||||
//symbol/dibit file capture/writing
|
//symbol/dibit file capture/writing
|
||||||
if (opts->symbol_out_f)
|
if (opts->symbol_out == 1)
|
||||||
{
|
{
|
||||||
//fprintf (stderr, "%d", dibit);
|
//fprintf (stderr, "%d", dibit);
|
||||||
fputc (dibit, opts->symbol_out_f);
|
fputc (dibit, opts->symbol_out_f);
|
||||||
@@ -492,7 +487,6 @@ skipDibit (dsd_opts * opts, dsd_state * state, int count)
|
|||||||
|
|
||||||
short sample;
|
short sample;
|
||||||
int i;
|
int i;
|
||||||
UNUSED(sample);
|
|
||||||
|
|
||||||
for (i = 0; i < (count); i++)
|
for (i = 0; i < (count); i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,34 +17,30 @@
|
|||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b
|
time_t nowF;
|
||||||
char * getTimeF(void) //get pretty hhmmss timestamp
|
char * getTimeF(void) //get pretty hh:mm:ss timestamp
|
||||||
{
|
{
|
||||||
char * curr = (char *) malloc(9);
|
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
struct tm * ptm = localtime(& t);
|
|
||||||
sprintf(
|
char * curr;
|
||||||
curr,
|
char * stamp = asctime(localtime( & t));
|
||||||
"%02d%02d%02d",
|
|
||||||
ptm->tm_hour,
|
curr = strtok(stamp, " ");
|
||||||
ptm->tm_min,
|
curr = strtok(NULL, " ");
|
||||||
ptm->tm_sec
|
curr = strtok(NULL, " ");
|
||||||
);
|
curr = strtok(NULL, " ");
|
||||||
|
|
||||||
return curr;
|
return curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * getDateF(void) {
|
char * getDateF(void) {
|
||||||
#ifdef AERO_BUILD
|
char datename[80]; //32-bit needs this to be 80
|
||||||
char datename[80];
|
|
||||||
#else
|
|
||||||
char datename[99];
|
|
||||||
#endif
|
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
time_t t;
|
time_t t;
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
to = localtime( & t);
|
to = localtime( & t);
|
||||||
strftime(datename, sizeof(datename), "%Y%m%d", to);
|
strftime(datename, sizeof(datename), "%Y-%m-%d", to);
|
||||||
curr2 = strtok(datename, " ");
|
curr2 = strtok(datename, " ");
|
||||||
return curr2;
|
return curr2;
|
||||||
}
|
}
|
||||||
@@ -131,7 +127,6 @@ void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P
|
|||||||
int i, j, k;
|
int i, j, k;
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
unsigned char err;
|
unsigned char err;
|
||||||
UNUSED(err);
|
|
||||||
|
|
||||||
err = (unsigned char) state->errs2;
|
err = (unsigned char) state->errs2;
|
||||||
k = 0;
|
k = 0;
|
||||||
@@ -167,7 +162,6 @@ void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
|||||||
int i, j, k;
|
int i, j, k;
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
unsigned char err;
|
unsigned char err;
|
||||||
UNUSED(err);
|
|
||||||
|
|
||||||
err = (unsigned char) state->errs2;
|
err = (unsigned char) state->errs2;
|
||||||
k = 0;
|
k = 0;
|
||||||
@@ -356,8 +350,6 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
|
|||||||
//slot 1
|
//slot 1
|
||||||
void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
if (opts->mbe_out == 1)
|
if (opts->mbe_out == 1)
|
||||||
{
|
{
|
||||||
if (opts->mbe_out_f != NULL)
|
if (opts->mbe_out_f != NULL)
|
||||||
@@ -375,8 +367,6 @@ void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
|||||||
//slot 2
|
//slot 2
|
||||||
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
if (opts->mbe_outR == 1)
|
if (opts->mbe_outR == 1)
|
||||||
{
|
{
|
||||||
if (opts->mbe_out_fR != NULL)
|
if (opts->mbe_out_fR != NULL)
|
||||||
@@ -487,7 +477,6 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void openWavOutFile (dsd_opts * opts, dsd_state * state)
|
void openWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
SF_INFO info;
|
SF_INFO info;
|
||||||
info.samplerate = 8000; //8000
|
info.samplerate = 8000; //8000
|
||||||
@@ -504,7 +493,6 @@ void openWavOutFile (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void openWavOutFileL (dsd_opts * opts, dsd_state * state)
|
void openWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
SF_INFO info;
|
SF_INFO info;
|
||||||
info.samplerate = 8000;
|
info.samplerate = 8000;
|
||||||
@@ -521,7 +509,6 @@ void openWavOutFileL (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void openWavOutFileR (dsd_opts * opts, dsd_state * state)
|
void openWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
SF_INFO info;
|
SF_INFO info;
|
||||||
info.samplerate = 8000; //8000
|
info.samplerate = 8000; //8000
|
||||||
@@ -538,13 +525,12 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
SF_INFO info;
|
SF_INFO info;
|
||||||
info.samplerate = 48000; //8000
|
info.samplerate = 48000; //8000
|
||||||
info.channels = 1;
|
info.channels = 1;
|
||||||
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||||
opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_WRITE, &info);
|
opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_RDWR, &info);
|
||||||
if (opts->wav_out_raw == NULL)
|
if (opts->wav_out_raw == NULL)
|
||||||
{
|
{
|
||||||
fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw);
|
fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw);
|
||||||
@@ -554,45 +540,48 @@ void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
void closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_f);
|
sf_close(opts->wav_out_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_f);
|
sf_close(opts->wav_out_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_fR);
|
sf_close(opts->wav_out_fR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_raw);
|
sf_close(opts->wav_out_raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void openSymbolOutFile (dsd_opts * opts, dsd_state * state)
|
void openSymbolOutFile (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
closeSymbolOutFile(opts, state);
|
//Do something
|
||||||
opts->symbol_out_f = fopen (opts->symbol_out_file, "w");
|
opts->symbol_out_f = fopen (opts->symbol_out_file, "w");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeSymbolOutFile (dsd_opts * opts, dsd_state * state)
|
||||||
|
{
|
||||||
|
//Do something
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state)
|
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
//Do something
|
||||||
|
if (opts->symbol_out == 1)
|
||||||
if (opts->symbol_out_f)
|
|
||||||
{
|
{
|
||||||
fclose(opts->symbol_out_f);
|
if (opts->symbol_out_file != NULL)
|
||||||
opts->symbol_out_f = NULL;
|
{
|
||||||
|
fclose(opts->symbol_out_f);
|
||||||
|
}
|
||||||
|
|
||||||
|
opts->symbol_out = 0; //set flag to 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ dmr_filter(short sample)
|
|||||||
short
|
short
|
||||||
nxdn_filter(short sample)
|
nxdn_filter(short sample)
|
||||||
{
|
{
|
||||||
return dsd_input_filter(sample, 4);
|
return dsd_input_filter(sample, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
short
|
short
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ printFrameInfo (dsd_opts * opts, dsd_state * state)
|
|||||||
level = (int) state->max / 164;
|
level = (int) state->max / 164;
|
||||||
if (opts->verbose > 0)
|
if (opts->verbose > 0)
|
||||||
{
|
{
|
||||||
// fprintf (stderr,"inlvl: %2i%% ", level);
|
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||||
UNUSED(level);
|
|
||||||
}
|
}
|
||||||
if (state->nac != 0)
|
if (state->nac != 0)
|
||||||
{
|
{
|
||||||
@@ -60,10 +59,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
char duid[3];
|
char duid[3];
|
||||||
char nac[13];
|
char nac[13];
|
||||||
int level;
|
int level;
|
||||||
UNUSED2(nac, level);
|
|
||||||
|
|
||||||
char status_0;
|
char status_0;
|
||||||
UNUSED(status_0);
|
|
||||||
char bch_code[63];
|
char bch_code[63];
|
||||||
int index_bch_code;
|
int index_bch_code;
|
||||||
unsigned char parity;
|
unsigned char parity;
|
||||||
@@ -94,24 +91,50 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
nxdn_frame (opts, state);
|
nxdn_frame (opts, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//DSTAR
|
|
||||||
else if ((state->synctype == 6) || (state->synctype == 7))
|
else if ((state->synctype == 6) || (state->synctype == 7))
|
||||||
{
|
{
|
||||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
state->nac = 0;
|
||||||
openMbeOutFile (opts, state);
|
state->lastsrc = 0;
|
||||||
sprintf (state->fsubtype, " VOICE ");
|
state->lasttg = 0;
|
||||||
processDSTAR (opts, state);
|
if (opts->errorbars == 1)
|
||||||
return;
|
{
|
||||||
}
|
if (opts->verbose > 0)
|
||||||
|
{
|
||||||
|
level = (int) state->max / 164;
|
||||||
|
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->nac = 0;
|
||||||
|
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||||
|
{
|
||||||
|
openMbeOutFile (opts, state); //dstar ambe files are read back incorrectly, need to change file extension to differentiate when doing a playback
|
||||||
|
}
|
||||||
|
sprintf (state->fsubtype, " VOICE ");
|
||||||
|
processDSTAR (opts, state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
else if ((state->synctype == 18) || (state->synctype == 19))
|
else if ((state->synctype == 18) || (state->synctype == 19))
|
||||||
{
|
{
|
||||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
state->nac = 0;
|
||||||
openMbeOutFile (opts, state);
|
state->lastsrc = 0;
|
||||||
sprintf (state->fsubtype, " DATA ");
|
state->lasttg = 0;
|
||||||
processDSTAR_HD (opts, state);
|
if (opts->errorbars == 1)
|
||||||
return;
|
{
|
||||||
}
|
if (opts->verbose > 0)
|
||||||
|
{
|
||||||
|
level = (int) state->max / 164;
|
||||||
|
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->nac = 0;
|
||||||
|
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||||
|
{
|
||||||
|
openMbeOutFile (opts, state); //dstar ambe files are read back incorrectly, need to change file extension to differentiate when doing a playback
|
||||||
|
}
|
||||||
|
sprintf (state->fsubtype, " DATA ");
|
||||||
|
processDSTAR_HD (opts, state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
//Start DMR Types
|
//Start DMR Types
|
||||||
else if ((state->synctype >= 10) && (state->synctype <= 13) || (state->synctype == 32) || (state->synctype == 33) || (state->synctype == 34) ) //32-34 DMR MS and RC
|
else if ((state->synctype >= 10) && (state->synctype <= 13) || (state->synctype == 32) || (state->synctype == 33) || (state->synctype == 34) ) //32-34 DMR MS and RC
|
||||||
{
|
{
|
||||||
@@ -154,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)
|
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
|
||||||
{
|
{
|
||||||
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);
|
||||||
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
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);
|
||||||
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
dmrMSBootstrap (opts, state);
|
||||||
}
|
}
|
||||||
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
||||||
{
|
{
|
||||||
@@ -175,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);
|
||||||
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
|
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
|
||||||
}
|
}
|
||||||
@@ -184,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);
|
||||||
if (opts->p25_trunk == 0) dmrMSData (opts, state);
|
dmrMSData (opts, state);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -196,6 +219,7 @@ 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
|
||||||
@@ -207,6 +231,7 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,7 +298,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) || (state->synctype == 99) || (state->synctype == 98))
|
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
|
if (state->synctype == 98 || state->synctype == 99) //preamble only
|
||||||
skipDibit(opts, state, 8); //skip dibits to prime the demodulator
|
skipDibit(opts, state, 184); //skip dibits to prime the demodulator
|
||||||
else if (state->synctype == 16 || state->synctype == 17)
|
else if (state->synctype == 16 || state->synctype == 17)
|
||||||
processM17STR(opts, state);
|
processM17STR(opts, state);
|
||||||
else
|
else
|
||||||
@@ -404,8 +429,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
if (new_nac != state->nac) {
|
if (new_nac != state->nac) {
|
||||||
// NAC fixed by error correction
|
// NAC fixed by error correction
|
||||||
state->nac = new_nac;
|
state->nac = new_nac;
|
||||||
//apparently, both 0 and 0xFFF can the BCH code on signal drop
|
if (state->p2_hardset == 0 && new_nac != 0)
|
||||||
if (state->p2_hardset == 0 && new_nac != 0 && new_nac != 0xFFF)
|
|
||||||
{
|
{
|
||||||
state->p2_cc = new_nac;
|
state->p2_cc = new_nac;
|
||||||
}
|
}
|
||||||
@@ -585,7 +609,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameInfo (opts, state);
|
printFrameInfo (opts, state);
|
||||||
fprintf (stderr," MPDU\n"); //multi block format PDU
|
fprintf (stderr," MBF\n"); //multi block format PDU
|
||||||
}
|
}
|
||||||
if (opts->mbe_out_dir[0] != 0)
|
if (opts->mbe_out_dir[0] != 0)
|
||||||
{
|
{
|
||||||
@@ -597,7 +621,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
resumeScan (opts, state);
|
resumeScan (opts, state);
|
||||||
}
|
}
|
||||||
state->lastp25type = 4;
|
state->lastp25type = 4;
|
||||||
sprintf (state->fsubtype, " MPDU ");
|
sprintf (state->fsubtype, " MBF ");
|
||||||
|
|
||||||
processMPDU(opts, state);
|
processMPDU(opts, state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,39 @@
|
|||||||
#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);
|
||||||
@@ -34,11 +67,7 @@ char * getTime(void) //get pretty hh:mm:ss timestamp
|
|||||||
}
|
}
|
||||||
|
|
||||||
char * getDate(void) {
|
char * getDate(void) {
|
||||||
#ifdef AERO_BUILD
|
char datename[32];
|
||||||
char datename[80];
|
|
||||||
#else
|
|
||||||
char datename[99];
|
|
||||||
#endif
|
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
time_t t;
|
time_t t;
|
||||||
@@ -52,7 +81,6 @@ char * getDate(void) {
|
|||||||
void
|
void
|
||||||
printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation)
|
printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation)
|
||||||
{
|
{
|
||||||
UNUSED3(state, offset, modulation);
|
|
||||||
|
|
||||||
if (opts->verbose > 0)
|
if (opts->verbose > 0)
|
||||||
{
|
{
|
||||||
@@ -125,14 +153,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->dmr_rest_channel == -1 && opts->p25_is_tuned == 0 && opts->p25_trunk == 1 && ( (time(NULL) - state->last_cc_sync_time) > (opts->trunk_hangtime + 0) ) ) //was 3, go to hangtime value
|
if (state->dmr_rest_channel == -1 && opts->p25_is_tuned == 0 && opts->p25_trunk == 1 && ( (time(NULL) - state->last_cc_sync_time) > (opts->trunk_hangtime + 0) ) ) //was 3, go to hangtime value
|
||||||
{
|
{
|
||||||
|
|
||||||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
//test to switch back to 10/4 P1 QPSK for P25 FDMA CC
|
||||||
if (state->p25_cc_is_tdma == 0)
|
if (opts->mod_qpsk == 1 && state->p25_cc_is_tdma == 0)
|
||||||
{
|
{
|
||||||
state->samplesPerSymbol = 10;
|
state->samplesPerSymbol = 10;
|
||||||
state->symbolCenter = 4;
|
state->symbolCenter = 4;
|
||||||
//re-enable both slots
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
opts->slot2_on = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//start going through the lcn/frequencies CC/signal hunting
|
//start going through the lcn/frequencies CC/signal hunting
|
||||||
@@ -180,10 +205,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->last_cc_sync_time = time(NULL); //set again to give another x seconds
|
state->last_cc_sync_time = time(NULL); //set again to give another x seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
int i, t, dibit, sync, symbol, synctest_pos, lastt;
|
int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt;
|
||||||
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
|
||||||
@@ -193,9 +219,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
char synctest16[17]; //M17 Preamble
|
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_p[10240]; //make this an array instead
|
||||||
char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere?
|
char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere?
|
||||||
int lmin, lmax, lidx;
|
int lmin, lmax, lidx;
|
||||||
UNUSED2(synctest18, synctest21);
|
|
||||||
|
|
||||||
//assign t_max value based on decoding type expected (all non-auto decodes first)
|
//assign t_max value based on decoding type expected (all non-auto decodes first)
|
||||||
int t_max; //maximum values allowed for t will depend on decoding type - NXDN will be 10, others will be more
|
int t_max; //maximum values allowed for t will depend on decoding type - NXDN will be 10, others will be more
|
||||||
@@ -223,8 +250,9 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
else t_max = 24; //24 for everything else
|
else t_max = 24; //24 for everything else
|
||||||
|
|
||||||
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 lbuf[t_max], lbuf2[t_max];
|
||||||
int lsum;
|
int lsum;
|
||||||
|
char spectrum[64];
|
||||||
//init the lbuf
|
//init the lbuf
|
||||||
memset (lbuf, 0, sizeof(lbuf));
|
memset (lbuf, 0, sizeof(lbuf));
|
||||||
memset (lbuf2, 0, sizeof(lbuf2));
|
memset (lbuf2, 0, sizeof(lbuf2));
|
||||||
@@ -334,7 +362,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
dibit = 51; // '3'
|
dibit = 51; // '3'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->symbol_out_f && dibit != 0)
|
if (opts->symbol_out == 1 && dibit != 0)
|
||||||
{
|
{
|
||||||
int csymbol = 0;
|
int csymbol = 0;
|
||||||
if (dibit == 49)
|
if (dibit == 49)
|
||||||
@@ -712,6 +740,10 @@ 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
|
||||||
}
|
}
|
||||||
@@ -747,6 +779,10 @@ 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
|
||||||
}
|
}
|
||||||
@@ -778,6 +814,10 @@ 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)
|
||||||
@@ -810,6 +850,10 @@ 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)
|
||||||
@@ -848,12 +892,20 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -880,6 +932,10 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -905,12 +961,20 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -933,6 +997,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -949,6 +1017,10 @@ 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
|
||||||
}
|
}
|
||||||
@@ -970,6 +1042,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -986,6 +1062,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -1007,6 +1087,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -1023,6 +1107,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -1048,6 +1136,10 @@ 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,6 +1153,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -1086,6 +1182,10 @@ 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
|
||||||
}
|
}
|
||||||
@@ -1122,6 +1222,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -1134,6 +1238,10 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -1144,65 +1252,56 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
//ProVoice and EDACS sync
|
//ProVoice and EDACS sync
|
||||||
if (opts->frame_provoice == 1)
|
if (opts->frame_provoice == 1)
|
||||||
{
|
|
||||||
strncpy (synctest32, (synctest_p - 31), 32);
|
|
||||||
strncpy (synctest48, (synctest_p - 47), 48);
|
|
||||||
if ((strcmp (synctest32, PROVOICE_SYNC) == 0) || (strcmp (synctest32, PROVOICE_EA_SYNC) == 0))
|
|
||||||
{
|
{
|
||||||
state->last_cc_sync_time = time(NULL);
|
strncpy (synctest32, (synctest_p - 31), 32);
|
||||||
state->carrier = 1;
|
strncpy (synctest48, (synctest_p - 47), 48);
|
||||||
state->offset = synctest_pos;
|
if ((strcmp (synctest32, PROVOICE_SYNC) == 0) || (strcmp (synctest32, PROVOICE_EA_SYNC) == 0))
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
sprintf (state->ftype, "ProVoice ");
|
|
||||||
if (opts->errorbars == 1)
|
|
||||||
printFrameSync (opts, state, "+PV ", synctest_pos + 1, modulation);
|
|
||||||
state->lastsynctype = 14;
|
|
||||||
return (14);
|
|
||||||
}
|
|
||||||
else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0))
|
|
||||||
{
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
sprintf (state->ftype, "ProVoice ");
|
|
||||||
printFrameSync (opts, state, "-PV ", synctest_pos + 1, modulation);
|
|
||||||
state->lastsynctype = 15;
|
|
||||||
return (15);
|
|
||||||
}
|
|
||||||
else if ( strcmp (synctest48, EDACS_SYNC) == 0)
|
|
||||||
{
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
printFrameSync (opts, state, "-EDACS", synctest_pos + 1, modulation);
|
|
||||||
state->lastsynctype = 38;
|
|
||||||
return (38);
|
|
||||||
}
|
|
||||||
else if ( strcmp (synctest48, INV_EDACS_SYNC) == 0)
|
|
||||||
{
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
printFrameSync (opts, state, "+EDACS", synctest_pos + 1, modulation);
|
|
||||||
state->lastsynctype = 37;
|
|
||||||
return (37);
|
|
||||||
}
|
|
||||||
else if ((strcmp (synctest48, DOTTING_SEQUENCE_A) == 0) || (strcmp (synctest48, DOTTING_SEQUENCE_B) == 0))
|
|
||||||
{
|
|
||||||
//only print and execute Dotting Sequence if Trunking and Tuned so we don't get multiple prints on this
|
|
||||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1)
|
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, " EDACS DOTTING SEQUENCE: ", synctest_pos + 1, modulation);
|
state->last_cc_sync_time = time(NULL);
|
||||||
eot_cc (opts, state);
|
state->carrier = 1;
|
||||||
|
state->offset = synctest_pos;
|
||||||
|
state->max = ((state->max) + lmax) / 2;
|
||||||
|
state->min = ((state->min) + lmin) / 2;
|
||||||
|
sprintf (state->ftype, "ProVoice ");
|
||||||
|
if (opts->errorbars == 1)
|
||||||
|
printFrameSync (opts, state, "+PV ", synctest_pos + 1, modulation);
|
||||||
|
state->lastsynctype = 14;
|
||||||
|
return (14);
|
||||||
|
}
|
||||||
|
else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0))
|
||||||
|
{
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
state->carrier = 1;
|
||||||
|
state->offset = synctest_pos;
|
||||||
|
state->max = ((state->max) + lmax) / 2;
|
||||||
|
state->min = ((state->min) + lmin) / 2;
|
||||||
|
sprintf (state->ftype, "ProVoice ");
|
||||||
|
printFrameSync (opts, state, "-PV ", synctest_pos + 1, modulation);
|
||||||
|
state->lastsynctype = 15;
|
||||||
|
return (15);
|
||||||
|
}
|
||||||
|
else if ( strcmp (synctest48, EDACS_SYNC) == 0)
|
||||||
|
{
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
state->carrier = 1;
|
||||||
|
state->offset = synctest_pos;
|
||||||
|
state->max = ((state->max) + lmax) / 2;
|
||||||
|
state->min = ((state->min) + lmin) / 2;
|
||||||
|
printFrameSync (opts, state, "-EDACS", synctest_pos + 1, modulation);
|
||||||
|
state->lastsynctype = 38;
|
||||||
|
return (38);
|
||||||
|
}
|
||||||
|
else if ( strcmp (synctest48, INV_EDACS_SYNC) == 0)
|
||||||
|
{
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
state->carrier = 1;
|
||||||
|
state->offset = synctest_pos;
|
||||||
|
state->max = ((state->max) + lmax) / 2;
|
||||||
|
state->min = ((state->min) + lmin) / 2;
|
||||||
|
printFrameSync (opts, state, "+EDACS", synctest_pos + 1, modulation);
|
||||||
|
state->lastsynctype = 37;
|
||||||
|
return (37);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1214,12 +1313,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
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;
|
||||||
sprintf (state->ftype, "DSTAR ");
|
sprintf (state->ftype, "D-STAR ");
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "+DSTAR VOICE ", 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)
|
||||||
@@ -1228,12 +1332,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
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;
|
||||||
sprintf (state->ftype, "DSTAR ");
|
sprintf (state->ftype, "D-STAR ");
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "-DSTAR VOICE ", 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)
|
||||||
@@ -1242,12 +1351,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
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;
|
||||||
sprintf (state->ftype, "DSTAR_HD ");
|
sprintf (state->ftype, "D-STAR_HD ");
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "+DSTAR HEADER", 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)
|
||||||
@@ -1256,37 +1370,178 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
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;
|
||||||
sprintf (state->ftype, " DSTAR_HD");
|
sprintf (state->ftype, " D-STAR_HD");
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "-DSTAR HEADER", 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NXDN
|
#ifdef NXDNOLDSYNC //Use FSW vs strncmperr method
|
||||||
|
|
||||||
|
//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
|
||||||
if (
|
strncpy (synctest19, (synctest_p - 18), 19); //Preamble + FSW
|
||||||
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|
|
||||||
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|
|
||||||
|| (strcmp (synctest10, "3131331111") == 0 )
|
|
||||||
|| (strcmp (synctest10, "3331331111") == 0 )
|
|
||||||
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
|
|
||||||
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
//Preamble plus FSW, proceed right away
|
||||||
|
if ( (strncmperr (synctest19, NXDN_PANDFSW, 19, 1) == 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->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)
|
if (state->lastsynctype == 28)
|
||||||
{
|
{
|
||||||
state->last_cc_sync_time = time(NULL);
|
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 (
|
||||||
|
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|
||||||
|
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|
||||||
|
|| (strcmp (synctest10, "3131331111") == 0 )
|
||||||
|
|| (strcmp (synctest10, "3331331111") == 0 )
|
||||||
|
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
|
||||||
|
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
// state->carrier = 1;
|
||||||
|
state->offset = synctest_pos;
|
||||||
|
state->max = ((state->max) + lmax) / 2;
|
||||||
|
state->min = ((state->min) + lmin) / 2;
|
||||||
|
// state->last_cc_sync_time = time(NULL);
|
||||||
|
|
||||||
|
if (state->lastsynctype == 28)
|
||||||
|
{
|
||||||
|
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;
|
||||||
@@ -1294,27 +1549,36 @@ 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)
|
||||||
|
|||||||
688
src/dsd_gps.c
688
src/dsd_gps.c
@@ -1,688 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* dsd_gps.c
|
|
||||||
* GPS Handling Functions for Various Protocols
|
|
||||||
*
|
|
||||||
* LWVMOBILE
|
|
||||||
* 2023-12 DSD-FME Florida Man Edition
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
|
|
||||||
void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
|
|
||||||
{
|
|
||||||
//NOTE: This is defined in ETSI TS 102 361-4 V1.12.1 (2023-07) p208
|
|
||||||
//6.6.11.3.2 USBD Polling Service Poll Response PDU for LIP (That's a mouthful)
|
|
||||||
|
|
||||||
int slot = state->currentslot;
|
|
||||||
|
|
||||||
//NOTE: This format is pretty much the same as DMR EMB GPS, but has a few extra elements,
|
|
||||||
//so I got lazy and just lifted most of the code from there, also assuming same lat/lon calcs
|
|
||||||
//since those have been tested to work in DMR EMB GPS and units are same in LIP
|
|
||||||
|
|
||||||
fprintf (stderr, "Location Information Protocol; ");
|
|
||||||
|
|
||||||
// uint8_t service_type = (uint8_t)ConvertBitIntoBytes(&input[0], 4); //checked before arrival here
|
|
||||||
uint8_t time_elapsed = (uint8_t)ConvertBitIntoBytes(&input[6], 2);
|
|
||||||
uint8_t lon_sign = input[8];
|
|
||||||
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&input[9], 24); //8, 25
|
|
||||||
uint8_t lat_sign = input[33];
|
|
||||||
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&input[34], 23); //33, 24
|
|
||||||
uint8_t pos_err = (uint8_t)ConvertBitIntoBytes(&input[57], 2);
|
|
||||||
uint8_t hor_vel = (uint8_t)ConvertBitIntoBytes(&input[59], 7);
|
|
||||||
uint8_t dir_tra = (uint8_t)ConvertBitIntoBytes(&input[66], 4);
|
|
||||||
uint8_t reason = (uint8_t)ConvertBitIntoBytes(&input[70], 3);
|
|
||||||
uint8_t add_hash = (uint8_t)ConvertBitIntoBytes(&input[73], 8); //MS Source Address Hash
|
|
||||||
|
|
||||||
//NOTE: May need to use double instead of float to avoid rounding errors
|
|
||||||
double latitude, longitude = 0.0f;
|
|
||||||
double lat_unit = (double)180/ pow (2.0, 24); //180 divided by 2^24 -- 6.3.30
|
|
||||||
double lon_unit = (double)360/ pow (2.0, 25); //360 divided by 2^25 -- 6.3.50
|
|
||||||
double lon_sf = 1.0f; //float value we can multiple longitude with
|
|
||||||
double lat_sf = 1.0f; //float value we can multiple latitude with
|
|
||||||
|
|
||||||
char latstr[3];
|
|
||||||
char lonstr[3];
|
|
||||||
sprintf (latstr, "%s", "N");
|
|
||||||
sprintf (lonstr, "%s", "E");
|
|
||||||
|
|
||||||
char deg_glyph[4];
|
|
||||||
sprintf (deg_glyph, "%s", "°");
|
|
||||||
|
|
||||||
//lat and lon calculations
|
|
||||||
if (lat_sign)
|
|
||||||
{
|
|
||||||
lat = 0x800001 - lat;
|
|
||||||
sprintf (latstr, "%s", "S");
|
|
||||||
lat_sf = -1.0f;
|
|
||||||
}
|
|
||||||
latitude = ((double)lat * lat_unit);
|
|
||||||
|
|
||||||
if (lon_sign)
|
|
||||||
{
|
|
||||||
lon = 0x1000001 - lon;
|
|
||||||
sprintf (lonstr, "%s", "W");
|
|
||||||
lon_sf = -1.0f;
|
|
||||||
}
|
|
||||||
longitude = ((double)lon * lon_unit);
|
|
||||||
|
|
||||||
//6.3.63 Position Error
|
|
||||||
//6.3.17 Horizontal velocity
|
|
||||||
/*
|
|
||||||
Horizontal velocity shall be encoded for speeds 0 km/h to 28 km/h in 1 km/h steps and
|
|
||||||
from 28 km/h onwards using equation: v = C × (1 + x)^(K-A) + B where:
|
|
||||||
*/
|
|
||||||
float v = 0.0f;
|
|
||||||
float C = 16.0f;
|
|
||||||
float x = 0.038f;
|
|
||||||
float A = 13.0f;
|
|
||||||
float K = (float)hor_vel;
|
|
||||||
float B = 0.0f;
|
|
||||||
|
|
||||||
if (hor_vel > 28)
|
|
||||||
v = C * (pow(1+x, K-A)) + B; //I think this pow function is set up correctly
|
|
||||||
else v = (float)hor_vel;
|
|
||||||
|
|
||||||
float dir = (((float)dir_tra + 11.25f)/22.5f); //page 68, Table 6.45
|
|
||||||
|
|
||||||
//truncated and rounded forms
|
|
||||||
int vt = (int)v;
|
|
||||||
int dt = (int)dir;
|
|
||||||
|
|
||||||
//sanity check
|
|
||||||
if (abs (latitude) < 90 && abs(longitude) < 180)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Src(Hash); %03d; Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf); Spd: %d km/h; Dir: %d%s",add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude, vt, dt, deg_glyph);
|
|
||||||
|
|
||||||
//6.3.63 Position Error
|
|
||||||
uint16_t position_error = 2 * pow(10, pos_err); //2 * 10^pos_err
|
|
||||||
if (pos_err == 0x7 ) fprintf (stderr, "\n Position Error: Unknown or Invalid;");
|
|
||||||
else fprintf (stderr, "\n Position Error: Less than %dm;", position_error);
|
|
||||||
|
|
||||||
//Reason For Sending 6.6.11.3.3 Table 6.80
|
|
||||||
if (reason) fprintf (stderr, " Reserved: %d;", reason);
|
|
||||||
else fprintf (stderr, " Request Response; ");
|
|
||||||
|
|
||||||
//6.3.78 Time elapsed
|
|
||||||
if (time_elapsed == 0) fprintf (stderr, " TE: < 5s;");
|
|
||||||
if (time_elapsed == 1) fprintf (stderr, " TE: < 5m;");
|
|
||||||
if (time_elapsed == 2) fprintf (stderr, " TE: < 30m;");
|
|
||||||
if (time_elapsed == 3) fprintf (stderr, " TE: NA or UNK;"); //not applicable or unknown
|
|
||||||
|
|
||||||
//save to array for ncurses
|
|
||||||
if (pos_err != 0x7)
|
|
||||||
{
|
|
||||||
sprintf (state->dmr_embedded_gps[slot], "%03d; LIP: %.5lf%s%s %.5lf%s%s; Err: %dm; Spd: %d km/h; Dir: %d%s", add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, position_error, vt, dt, deg_glyph);
|
|
||||||
}
|
|
||||||
else sprintf (state->dmr_embedded_gps[slot], "%03d; LIP: %.5lf%s%s %.5lf%s%s Unknown Pos Err; Spd: %d km/h; Dir %d%s", add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, vt, dt, deg_glyph);
|
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
|
||||||
FILE * pFile; //file pointer
|
|
||||||
if (opts->lrrp_file_output == 1)
|
|
||||||
{
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
|
||||||
fprintf (pFile, "%08d\t", add_hash);
|
|
||||||
fprintf (pFile, "%.5lf\t", latitude);
|
|
||||||
fprintf (pFile, "%.5lf\t", longitude);
|
|
||||||
fprintf (pFile, "%d\t", vt); //speed in km/h
|
|
||||||
fprintf (pFile, "%d\t", dt); //direction of travel
|
|
||||||
fprintf (pFile, "\n");
|
|
||||||
fclose (pFile);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else fprintf (stderr, " Position Calculation Error;");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int type)
|
|
||||||
{
|
|
||||||
int slot = state->currentslot;
|
|
||||||
|
|
||||||
//NOTE: The Only difference between Short (type == 1) and Long Format (type == 2)
|
|
||||||
//is the utc_ss3 on short vs utc_ss6 and inclusion of COG value on long
|
|
||||||
|
|
||||||
//NOTE: MFID Specific Formats are not handled here, unknown, could be added if worked out
|
|
||||||
//they could share most of the same elements and use the large spare bits in block 2 for extra
|
|
||||||
// uint8_t mfid = (uint8_t)ConvertBitIntoBytes(&input[88], 8); //on type 3, last octet of first block carries MFID
|
|
||||||
|
|
||||||
// uint8_t nmea_c = input[0]; //encrypted -- checked before we get here
|
|
||||||
uint8_t nmea_ns = input[1]; //north/south (lat sign)
|
|
||||||
uint8_t nmea_ew = input[2]; //east/west (lon sign)
|
|
||||||
uint8_t nmea_q = input[3]; //Quality Indicator (no fix or fix valid)
|
|
||||||
uint8_t nmea_speed = (uint8_t)ConvertBitIntoBytes(&input[4], 7); //speed in knots (127 = greater than 126 knots)
|
|
||||||
|
|
||||||
//Latitude Bits
|
|
||||||
uint8_t nmea_ndeg = (uint8_t)ConvertBitIntoBytes(&input[11], 7); //Latitude Degrees
|
|
||||||
uint8_t nmea_nmin = (uint8_t)ConvertBitIntoBytes(&input[18], 6); //Latitude Minutes
|
|
||||||
uint16_t nmea_nminf = (uint16_t)ConvertBitIntoBytes(&input[24], 14); //Latitude Fractions of Minutes
|
|
||||||
|
|
||||||
//Longitude Bits
|
|
||||||
uint8_t nmea_edeg = (uint8_t)ConvertBitIntoBytes(&input[38], 8); //Longitude Degrees
|
|
||||||
uint8_t nmea_emin = (uint8_t)ConvertBitIntoBytes(&input[46], 6); //Longitude Minutes
|
|
||||||
uint16_t nmea_eminf = (uint16_t)ConvertBitIntoBytes(&input[52], 14); //Longitude Fractions of Minutes
|
|
||||||
|
|
||||||
//UTC Time and COG
|
|
||||||
uint8_t nmea_utc_hh = (uint8_t)ConvertBitIntoBytes(&input[66], 5);
|
|
||||||
uint8_t nmea_utc_mm = (uint8_t)ConvertBitIntoBytes(&input[71], 6);
|
|
||||||
//seconds and the addition of COG is the difference between short and long formats
|
|
||||||
uint8_t nmea_utc_ss3 = (uint8_t)ConvertBitIntoBytes(&input[77], 3); //seconds in 10s
|
|
||||||
uint8_t nmea_utc_ss6 = (uint8_t)ConvertBitIntoBytes(&input[77], 6); //seconds in 1s
|
|
||||||
uint16_t nmea_cog = (uint16_t)ConvertBitIntoBytes(&input[103], 9); //course over ground in degrees
|
|
||||||
|
|
||||||
//lat and lon conversion
|
|
||||||
char deg_glyph[4];
|
|
||||||
sprintf (deg_glyph, "%s", "°");
|
|
||||||
float latitude = 0.0f;
|
|
||||||
float longitude = 0.0f;
|
|
||||||
// float m_unit = 1.0f / 60.0f; //unit to convert min into decimal value - (1/60)*60 minutes = 1 degree
|
|
||||||
// float mm_unit = 1.0f / 10000.0f; //unit to convert minf into decimal value - (0000 - 9999) 0.0001×9999 = .9999 minutes, so its sub 1 minute decimal
|
|
||||||
|
|
||||||
//testing w/ Harris NMEA like values (ran tests over there with this code, this seems to work on those values)
|
|
||||||
float m_unit = 1.0f / 60.0f; //unit to convert min into decimal value - (1/60)*60 minutes = 1 degree
|
|
||||||
float mm_unit = 1.0f / 600000.0f; //unit to convert minf into decimal value - (0000 - 9999) 0.0001×9999 = .9999 minutes, so its sub 1 minute decimal
|
|
||||||
|
|
||||||
//speed conversion
|
|
||||||
float fmps, fmph, fkph = 0.0f; //conversion of knots to mps, kph, and mph values
|
|
||||||
fmps = (float)nmea_speed * 0.514444; UNUSED(fmps);
|
|
||||||
fmph = (float)nmea_speed * 1.15078f; UNUSED(fmph);
|
|
||||||
fkph = (float)nmea_speed * 1.852f;
|
|
||||||
|
|
||||||
//calculate decimal representation of latidude and longitude (need some samples to test)
|
|
||||||
latitude = ( (float)nmea_ndeg + ((float)nmea_nmin*m_unit) + ((float)nmea_nminf*mm_unit) );
|
|
||||||
longitude = ( (float)nmea_edeg + ((float)nmea_emin*m_unit) + ((float)nmea_eminf*mm_unit) );
|
|
||||||
|
|
||||||
if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North
|
|
||||||
if (!nmea_ew) longitude *= -1.0f; //0 is West, 1 is East
|
|
||||||
|
|
||||||
fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph);
|
|
||||||
|
|
||||||
//Speed in Knots
|
|
||||||
if (nmea_speed > 126)
|
|
||||||
fprintf (stderr, " SPD > 126 knots or %f kph;", fkph);
|
|
||||||
else
|
|
||||||
fprintf (stderr, " SPD: %d knots; %f kph;", nmea_speed, fkph);
|
|
||||||
|
|
||||||
//Print UTC Time and COG according to Format Type
|
|
||||||
if (type == 1)
|
|
||||||
fprintf (stderr, " FIX: %d; %02d:%02d:%02d UTC; Short Format;", nmea_q, nmea_utc_hh, nmea_utc_mm, nmea_utc_ss3);
|
|
||||||
if (type == 2)
|
|
||||||
fprintf (stderr, " FIX: %d; %02d:%02d:%02d UTC; COG: %d%s; Long Format;", nmea_q, nmea_utc_hh, nmea_utc_mm, nmea_utc_ss6, nmea_cog, deg_glyph);
|
|
||||||
|
|
||||||
//save to ncurses string
|
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
|
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
|
||||||
FILE * pFile; //file pointer
|
|
||||||
if (opts->lrrp_file_output == 1)
|
|
||||||
{
|
|
||||||
int s = (int)fkph; //rounded interger format for the log report
|
|
||||||
int a = 0;
|
|
||||||
if (type == 2)
|
|
||||||
a = nmea_cog; //long format only
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
|
||||||
fprintf (pFile, "%s\t", getTimeL() ); //could switch to UTC time if desired, but would require local user offset
|
|
||||||
fprintf (pFile, "%08d\t", src);
|
|
||||||
fprintf (pFile, "%.6lf\t", latitude);
|
|
||||||
fprintf (pFile, "%.6lf\t", longitude);
|
|
||||||
fprintf (pFile, "%d\t ", s);
|
|
||||||
fprintf (pFile, "%d\t ", a);
|
|
||||||
fprintf (pFile, "\n");
|
|
||||||
fclose (pFile);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//restructured the Harris GPS to flow more like the DMR UDT NMEA Format when possible
|
|
||||||
void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int slot)
|
|
||||||
{
|
|
||||||
|
|
||||||
//GPS working, Time Working (old method), COG and Speed are logical on due west sample
|
|
||||||
//TODO: Fiddle/Test various ns and ew bits for proper signs in case its located elsewhere
|
|
||||||
//UPDATE: Found two contiguous bits that always work on all my accumulated samples
|
|
||||||
//the bits also place it with the 'lone' flagged bit observed prior
|
|
||||||
|
|
||||||
uint8_t nmea_ns = input[88]; //north/south (lat sign) //72 previously used bit
|
|
||||||
uint8_t nmea_ew = input[89]; //east/west (lon sign) //88 previously used bit
|
|
||||||
uint8_t nmea_q = input[147]; //Quality Indicator (last fix or current fix)
|
|
||||||
// uint8_t nmea_speed = (uint8_t)ConvertBitIntoBytes(&input[129], 7); //129,7
|
|
||||||
uint8_t nmea_speed = (uint8_t)ConvertBitIntoBytes(&input[129], 6); //this is one bit shorter than called for, but I believe it works
|
|
||||||
|
|
||||||
//Latitude Bits
|
|
||||||
uint8_t nmea_ndeg = (uint8_t)ConvertBitIntoBytes(&input[65], 7); //Latitude Degrees
|
|
||||||
uint8_t nmea_nmin = (uint8_t)ConvertBitIntoBytes(&input[58], 6); //Latitude Minutes
|
|
||||||
uint16_t nmea_nminf = (uint16_t)ConvertBitIntoBytes(&input[42], 14); //Latitude Fractions of Minutes
|
|
||||||
|
|
||||||
//Longitude Bits
|
|
||||||
uint8_t nmea_edeg = (uint8_t)ConvertBitIntoBytes(&input[96], 8); //Longitude Degrees
|
|
||||||
uint8_t nmea_emin = (uint8_t)ConvertBitIntoBytes(&input[90], 6); //Longitude Minutes
|
|
||||||
uint16_t nmea_eminf = (uint16_t)ConvertBitIntoBytes(&input[74], 14); //Longitude Fractions of Minutes
|
|
||||||
|
|
||||||
//NOTE: Removed UTC hh.mm.ss6 format found in DMR UDT, could not make it work
|
|
||||||
//with bits already established for time and it works extremely well as is
|
|
||||||
|
|
||||||
//Course Over Ground in Degrees (0-360)
|
|
||||||
uint16_t nmea_cog = (uint16_t)ConvertBitIntoBytes(&input[135], 9) % 360; //course over ground in degrees //working on due west sample without %360
|
|
||||||
|
|
||||||
//timestamp (16-bit value w/ appended 17th bit to MSB)
|
|
||||||
uint32_t rtime = (uint32_t)ConvertBitIntoBytes(&input[104], 16);
|
|
||||||
rtime |= input[144] << 16; //this bit is flagged on after 0xFFFF rollover in the late afternoon
|
|
||||||
uint32_t thour = rtime / 3600;
|
|
||||||
uint32_t tmin = (rtime % 3600) / 60;
|
|
||||||
uint32_t tsec = (rtime % 3600) % 60;
|
|
||||||
|
|
||||||
//lat and lon conversion
|
|
||||||
char deg_glyph[4];
|
|
||||||
sprintf (deg_glyph, "%s", "°");
|
|
||||||
float latitude = 0.0f;
|
|
||||||
float longitude = 0.0f;
|
|
||||||
float m_unit = 1.0f / 60.0f;
|
|
||||||
float mm_unit = 1.0f / 600000.0f;
|
|
||||||
|
|
||||||
//speed conversion
|
|
||||||
float fmps, fmph, fkph = 0.0f; //conversion of knots to mps, kph, and mph values
|
|
||||||
fmps = (float)nmea_speed * 0.514444; UNUSED(fmps);
|
|
||||||
fmph = (float)nmea_speed * 1.15078f; UNUSED(fmph);
|
|
||||||
fkph = (float)nmea_speed * 1.852f; UNUSED(fkph);
|
|
||||||
|
|
||||||
//calculate decimal representation of latidude and longitude (need some samples to test)
|
|
||||||
latitude = ( (float)nmea_ndeg + ((float)nmea_nmin*m_unit) + ((float)nmea_nminf*mm_unit) );
|
|
||||||
longitude = ( (float)nmea_edeg + ((float)nmea_emin*m_unit) + ((float)nmea_eminf*mm_unit) );
|
|
||||||
|
|
||||||
//This is opposite (seemingly) compared to the version specified by DMR UDT NMEA, could still be different bits involved (to be tested)
|
|
||||||
// if (nmea_ns) latitude *= -1.0f; //1 is South, 0 is North
|
|
||||||
// if (nmea_ew) longitude *= -1.0f; //1 is West, 0 is East
|
|
||||||
|
|
||||||
//DMR UDT NMEA original version (working now with new bit selection 88 and 89 like how DMR UDT NMEA format specifies)
|
|
||||||
if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North
|
|
||||||
if (!nmea_ew) longitude *= -1.0f; //0 is West, 1 is East
|
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
fprintf (stderr, " VCH: %d - SRC: %08d;", slot, src);
|
|
||||||
fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph);
|
|
||||||
|
|
||||||
//Speed in Knots (assuming in knots, and not in mps, or kph)
|
|
||||||
if (nmea_speed > 126)
|
|
||||||
fprintf (stderr, " SPD > 126 knots or %f MPH;", fmph); //using MPH here, its Harris, they're in the U.S.
|
|
||||||
else
|
|
||||||
fprintf (stderr, " SPD: %d knots; %f MPH;", nmea_speed, fmph);
|
|
||||||
|
|
||||||
//Course Over Ground (COG)
|
|
||||||
fprintf (stderr, " COG: %03d%s;", nmea_cog, deg_glyph); //%360
|
|
||||||
|
|
||||||
//debug speed
|
|
||||||
// fprintf (stderr, " RSPD: %02X;", nmea_speed);
|
|
||||||
|
|
||||||
//debug cog
|
|
||||||
// fprintf (stderr, " RCOG: %03X;", nmea_cog >> 0);
|
|
||||||
|
|
||||||
//UTC Time
|
|
||||||
fprintf (stderr, " T: %02d:%02d:%02d UTC;", thour, tmin, tsec);
|
|
||||||
|
|
||||||
//Fix Indicator
|
|
||||||
if (nmea_q) fprintf (stderr, " Current Fix;");
|
|
||||||
else fprintf (stderr, " Last Fix;");
|
|
||||||
|
|
||||||
//save to ncurses string
|
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
|
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
|
||||||
FILE * pFile; //file pointer
|
|
||||||
if (opts->lrrp_file_output == 1)
|
|
||||||
{
|
|
||||||
//rounded interger formats for the log report
|
|
||||||
int s = (int)fkph;
|
|
||||||
int a = nmea_cog;
|
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
|
||||||
fprintf (pFile, "%s\t", getTimeL() ); //could switch to UTC time on PDU if desired
|
|
||||||
fprintf (pFile, "%08d\t", src);
|
|
||||||
fprintf (pFile, "%.6lf\t", latitude);
|
|
||||||
fprintf (pFile, "%.6lf\t", longitude);
|
|
||||||
fprintf (pFile, "%d\t ", s);
|
|
||||||
fprintf (pFile, "%d\t ", a);
|
|
||||||
fprintf (pFile, "\n");
|
|
||||||
fclose (pFile);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOTE: There seems to be a few more octets left undecoded in this PDU
|
|
||||||
//not including the CRC obviously, unsure of their meaning, could relate
|
|
||||||
//to other GPS functions like precision, etc, unknown.
|
|
||||||
|
|
||||||
//NOTE2: All these values are just best effort based on observation and
|
|
||||||
//making map points match using logic and distance over time for speed and course
|
|
||||||
//without any documentation, any of these values may still be wrong
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//fallback version (if desired/required)
|
|
||||||
void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input)
|
|
||||||
{
|
|
||||||
|
|
||||||
uint8_t lat_sign, lat_deg, lat_min = 0;
|
|
||||||
uint8_t lon_sign, lon_deg, lon_min = 0;
|
|
||||||
uint16_t lat_mmin = 0;
|
|
||||||
uint16_t lon_mmin = 0;
|
|
||||||
|
|
||||||
//potentially in this PDU, but unverifiable without documentation or reasonable
|
|
||||||
//mathematical proof vs map points and direction of travel / distance over time (assuming the radio is facing that direction)
|
|
||||||
uint16_t rspeed = (uint16_t)ConvertBitIntoBytes(&input[136], 8); //MSB //136
|
|
||||||
rspeed = (rspeed << 8) + (uint16_t)ConvertBitIntoBytes(&input[128], 8); //LSB //128
|
|
||||||
|
|
||||||
//this works okay for example of driver driving due west at the speed limit of the road (fluke?)
|
|
||||||
uint16_t rangle = (uint16_t)ConvertBitIntoBytes(&input[120], 8); //120,8
|
|
||||||
float fspeed = (float)rspeed;
|
|
||||||
float fangle = (float)rangle;
|
|
||||||
|
|
||||||
fspeed /= 255.0f; //unit value of 1 bit
|
|
||||||
fspeed *= 1.56f; //this is based on an observation of a driver moving approx 210 meters in about 8 seconds and this makes it just under the speed limit on the road there
|
|
||||||
// fangle *= 360.0f/255.0f; //unit value of 1 bit
|
|
||||||
fangle *= 2.0f; //may exceed 360 degrees as is (use %)
|
|
||||||
|
|
||||||
int s, a = 0;
|
|
||||||
s = (int)fspeed * 3.6;
|
|
||||||
a = (int)fangle % 360;
|
|
||||||
|
|
||||||
//fix and quality indicators?
|
|
||||||
uint8_t fix = input[147]; UNUSED(fix);
|
|
||||||
uint8_t quality = (uint16_t)ConvertBitIntoBytes(&input[148], 3); UNUSED(quality);
|
|
||||||
|
|
||||||
//timestamp (16-bit value w/ appended 17th bit to MSB)
|
|
||||||
uint32_t rtime = (uint32_t)ConvertBitIntoBytes(&input[104], 16); //seconds since midnight since last GPS fix (whatever the radio has as internal time)
|
|
||||||
rtime |= input[144] << 16; //test appending this as bit 17 (observed this bit set after the afternoon 0xFFFF rollover)
|
|
||||||
uint32_t thour = rtime / 3600;
|
|
||||||
uint32_t tmin = (rtime % 3600) / 60;
|
|
||||||
uint32_t tsec = (rtime % 3600) % 60;
|
|
||||||
|
|
||||||
float lat_dec = 0.0f;
|
|
||||||
float lon_dec = 0.0f;
|
|
||||||
|
|
||||||
char deg_glyph[4];
|
|
||||||
sprintf (deg_glyph, "%s", "°");
|
|
||||||
|
|
||||||
//This appears to be similar to the NMEA GPGGA format (DDmm.mm) but
|
|
||||||
//octets are ordered in least significant to most significant value
|
|
||||||
lat_mmin = (uint16_t)ConvertBitIntoBytes(&input[40], 16); //? bits required, but grabbing two octets
|
|
||||||
lat_min = (uint8_t)ConvertBitIntoBytes(&input[58], 6); //6 bits required to get 60
|
|
||||||
lat_deg = (uint8_t)ConvertBitIntoBytes(&input[65], 7); //7 bits required to get 90
|
|
||||||
lat_sign = input[72]; //64
|
|
||||||
|
|
||||||
lon_mmin = (uint16_t)ConvertBitIntoBytes(&input[72], 16); //? bits required, but grabbing two octets
|
|
||||||
lon_min = (uint8_t)ConvertBitIntoBytes(&input[90], 6); //6 bits required to get 60
|
|
||||||
lon_deg = (uint8_t)ConvertBitIntoBytes(&input[96], 8); //8 bits required to get 180
|
|
||||||
lon_sign = input[88]; //88, unsure of a correct location, but on the sample with 0 minutes, this lonely bit was flagged on
|
|
||||||
|
|
||||||
int src = 0;
|
|
||||||
if (slot == 0) src = state->lastsrc;
|
|
||||||
if (slot == 1) src = state->lastsrcR;
|
|
||||||
|
|
||||||
//calculate decimal representation (was a pain to figure out the sub minute values)
|
|
||||||
lat_dec = ( (float)lat_deg + ((float)lat_min/60.0f) + ((float)lat_mmin/600000.0f) );
|
|
||||||
lon_dec = ( (float)lon_deg + ((float)lon_min/60.0f) + ((float)lon_mmin/600000.0f) );
|
|
||||||
|
|
||||||
if (lat_sign)
|
|
||||||
lat_dec *= -1.0f;
|
|
||||||
|
|
||||||
if (lon_sign)
|
|
||||||
lon_dec *= -1.0f;
|
|
||||||
|
|
||||||
//line break
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, " GPS: %f%s, %f%s;", lat_dec, deg_glyph, lon_dec, deg_glyph);
|
|
||||||
|
|
||||||
//gps fix time
|
|
||||||
// fprintf (stderr, " RT: %05X;", rtime); //debug
|
|
||||||
fprintf (stderr, " LTS: %02d:%02d:%02d UTC;", thour, tmin, tsec); //last time synced to GPS
|
|
||||||
|
|
||||||
//speed and direction
|
|
||||||
// fprintf (stderr, " RSPD: %04X;", rspeed); //debug
|
|
||||||
// fprintf (stderr, " RANG: %02X;", rangle); //debug
|
|
||||||
// fprintf (stderr, " MPS: %06.02f;", fspeed);
|
|
||||||
// fprintf (stderr, " KPH: %06.02f;", fspeed * 3.6f);
|
|
||||||
// fprintf (stderr, " MPH: %06.02f;", fspeed * 2.2369f);
|
|
||||||
fprintf (stderr, " DIR: %03d%s;", a, deg_glyph);
|
|
||||||
|
|
||||||
// fprintf (stderr, " FIX: %d", fix);
|
|
||||||
// fprintf (stderr, " QLT: %02d", quality);
|
|
||||||
|
|
||||||
// fprintf (stderr, " SRC: %08d;", src);
|
|
||||||
|
|
||||||
//save to array for ncurses
|
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", lat_dec, deg_glyph, lon_dec, deg_glyph);
|
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
|
||||||
FILE * pFile; //file pointer
|
|
||||||
if (opts->lrrp_file_output == 1)
|
|
||||||
{
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
|
||||||
fprintf (pFile, "%08d\t", src);
|
|
||||||
fprintf (pFile, "%.6lf\t", lat_dec);
|
|
||||||
fprintf (pFile, "%.6lf\t", lon_dec);
|
|
||||||
fprintf (pFile, "%d\t ", s);
|
|
||||||
fprintf (pFile, "%d\t ", a);
|
|
||||||
fprintf (pFile, "\n");
|
|
||||||
fclose (pFile);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOTE: Thanks to DSheirer (SDRTrunk) for helping me work out a few of the things in here
|
|
||||||
//not entirely convinced on some of these calcs (speed, angle, and TS) but sure these bits
|
|
||||||
//are actual speed/direction/timestamps judging from what the coordinates show on a map
|
|
||||||
}
|
|
||||||
|
|
||||||
//externalize embedded GPS - Confirmed working now on NE, NW, SE, and SW coordinates
|
|
||||||
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|
||||||
{
|
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KYEL);
|
|
||||||
fprintf (stderr, " Embedded GPS:");
|
|
||||||
uint8_t slot = state->currentslot;
|
|
||||||
uint8_t pf = lc_bits[0];
|
|
||||||
uint8_t res_a = lc_bits[1];
|
|
||||||
uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4);
|
|
||||||
uint8_t pos_err = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 3);
|
|
||||||
UNUSED2(res_a, res_b);
|
|
||||||
|
|
||||||
char deg_glyph[4];
|
|
||||||
sprintf (deg_glyph, "%s", "°");
|
|
||||||
|
|
||||||
uint32_t lon_sign = lc_bits[23];
|
|
||||||
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24);
|
|
||||||
uint32_t lat_sign = lc_bits[48];
|
|
||||||
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
|
|
||||||
double lon_sf = 1.0f; //float value we can multiple longitude with
|
|
||||||
double lat_sf = 1.0f; //float value we can multiple latitude with
|
|
||||||
|
|
||||||
double lat_unit = (double)180/ pow (2.0, 24); //180 divided by 2^24
|
|
||||||
double lon_unit = (double)360/ pow (2.0, 25); //360 divided by 2^25
|
|
||||||
|
|
||||||
char latstr[3];
|
|
||||||
char lonstr[3];
|
|
||||||
sprintf (latstr, "%s", "N");
|
|
||||||
sprintf (lonstr, "%s", "E");
|
|
||||||
|
|
||||||
//run calculations and print
|
|
||||||
//7.2.16 and 7.2.17 (two's compliment)
|
|
||||||
|
|
||||||
double latitude = 0;
|
|
||||||
double longitude = 0;
|
|
||||||
|
|
||||||
if (pf) fprintf (stderr, " Protected");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lat_sign)
|
|
||||||
{
|
|
||||||
lat = 0x800001 - lat;
|
|
||||||
sprintf (latstr, "%s", "S");
|
|
||||||
lat_sf = -1.0f;
|
|
||||||
}
|
|
||||||
latitude = ((double)lat * lat_unit);
|
|
||||||
|
|
||||||
if (lon_sign)
|
|
||||||
{
|
|
||||||
lon = 0x1000001 - lon;
|
|
||||||
sprintf (lonstr, "%s", "W");
|
|
||||||
lon_sf = -1.0f;
|
|
||||||
}
|
|
||||||
longitude = ((double)lon * lon_unit);
|
|
||||||
|
|
||||||
//sanity check
|
|
||||||
if (abs (latitude) < 90 && abs(longitude) < 180)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf)", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude);
|
|
||||||
|
|
||||||
//7.2.15 Position Error
|
|
||||||
uint16_t position_error = 2 * pow(10, pos_err); //2 * 10^pos_err
|
|
||||||
if (pos_err == 0x7 ) fprintf (stderr, "\n Position Error: Unknown or Invalid");
|
|
||||||
else fprintf (stderr, "\n Position Error: Less than %dm", position_error);
|
|
||||||
|
|
||||||
//save to array for ncurses
|
|
||||||
if (pos_err != 0x7)
|
|
||||||
{
|
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: %.5lf%s%s %.5lf%s%s Err: %dm", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, position_error);
|
|
||||||
}
|
|
||||||
else sprintf (state->dmr_embedded_gps[slot], "GPS: %.5lf%s%s %.5lf%s%s Unknown Pos Err", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr);
|
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
|
||||||
FILE * pFile; //file pointer
|
|
||||||
if (opts->lrrp_file_output == 1)
|
|
||||||
{
|
|
||||||
int src = 0;
|
|
||||||
if (slot == 0) src = state->lasttg;
|
|
||||||
if (slot == 1) src = state->lasttgR;
|
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
|
||||||
fprintf (pFile, "%08d\t", src);
|
|
||||||
fprintf (pFile, "%.5lf\t", latitude);
|
|
||||||
fprintf (pFile, "%.5lf\t", longitude);
|
|
||||||
fprintf (pFile, "0\t " ); //zero for velocity
|
|
||||||
fprintf (pFile, "0\t " ); //zero for azimuth
|
|
||||||
fprintf (pFile, "\n");
|
|
||||||
fclose (pFile);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
|
||||||
|
|
||||||
//This Function has been redone and variables fixed to mirror SDRTrunk
|
|
||||||
//my earlier assumption that this was the same format as DMR Embedded GPS was incorrect
|
|
||||||
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|
||||||
{
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KYEL);
|
|
||||||
fprintf (stderr, " GPS:");
|
|
||||||
uint8_t slot = state->currentslot;
|
|
||||||
uint8_t pf = lc_bits[0];
|
|
||||||
uint8_t res_a = lc_bits[1];
|
|
||||||
uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 7);
|
|
||||||
uint8_t expired = lc_bits[23]; //this bit seems to indicate that the GPS coordinates are out of date or fresh
|
|
||||||
|
|
||||||
char deg_glyph[4];
|
|
||||||
sprintf (deg_glyph, "%s", "°");
|
|
||||||
|
|
||||||
uint32_t lon_sign = lc_bits[48];
|
|
||||||
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
|
|
||||||
uint32_t lat_sign = lc_bits[24];
|
|
||||||
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[25], 23);
|
|
||||||
//todo: acquire more samples for additional validation
|
|
||||||
double lat_unit = 90.0f / 0x7FFFFF;
|
|
||||||
double lon_unit = 180.0f / 0x7FFFFF;
|
|
||||||
double lon_sf = 1.0f; //float value we can multiple longitude with
|
|
||||||
double lat_sf = 1.0f; //float value we can multiple latitude with
|
|
||||||
|
|
||||||
char latstr[3];
|
|
||||||
char lonstr[3];
|
|
||||||
char valid[9];
|
|
||||||
sprintf (latstr, "%s", "N");
|
|
||||||
sprintf (lonstr, "%s", "E");
|
|
||||||
sprintf (valid, "%s", "Current");
|
|
||||||
|
|
||||||
double latitude = 0;
|
|
||||||
double longitude = 0;
|
|
||||||
|
|
||||||
if (pf) fprintf (stderr, " Protected");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lat_sign)
|
|
||||||
{
|
|
||||||
sprintf (latstr, "%s", "S");
|
|
||||||
lat_sf = -1.0f;
|
|
||||||
}
|
|
||||||
latitude = ((double)lat * lat_unit);
|
|
||||||
|
|
||||||
if (lon_sign)
|
|
||||||
{
|
|
||||||
sprintf (lonstr, "%s", "W");
|
|
||||||
lon_sf = -1.0f;
|
|
||||||
}
|
|
||||||
longitude = ((double)lon * lon_unit);
|
|
||||||
|
|
||||||
//sanity check
|
|
||||||
if (abs (latitude) < 90 && abs(longitude) < 180)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf) ", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, latitude * lat_sf, longitude * lon_sf);
|
|
||||||
|
|
||||||
if (expired)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Expired; ");
|
|
||||||
sprintf (valid, "%s", "Expired");
|
|
||||||
}
|
|
||||||
else if (!expired)
|
|
||||||
fprintf (stderr, "Current; ");
|
|
||||||
|
|
||||||
if (res_a)
|
|
||||||
fprintf (stderr, "RES_A: %d; ", res_a);
|
|
||||||
|
|
||||||
if (res_b)
|
|
||||||
fprintf (stderr, "RES_B: %02X; ", res_b);
|
|
||||||
|
|
||||||
//save to array for ncurses
|
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: %lf%s%s %lf%s%s %s", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, valid);
|
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
|
||||||
FILE * pFile; //file pointer
|
|
||||||
if (opts->lrrp_file_output == 1)
|
|
||||||
{
|
|
||||||
int src = 0;
|
|
||||||
if (slot == 0) src = state->lastsrc;
|
|
||||||
if (slot == 1) src = state->lastsrcR;
|
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
|
||||||
fprintf (pFile, "%08d\t", src);
|
|
||||||
fprintf (pFile, "%.5lf\t", latitude);
|
|
||||||
fprintf (pFile, "%.5lf\t", longitude);
|
|
||||||
fprintf (pFile, "0\t " ); //zero for velocity
|
|
||||||
fprintf (pFile, "0\t " ); //zero for azimuth
|
|
||||||
fprintf (pFile, "\n");
|
|
||||||
fclose (pFile);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,6 @@ int csvGroupImport(dsd_opts * opts, dsd_state * state)
|
|||||||
int row_count = 0;
|
int row_count = 0;
|
||||||
int field_count = 0;
|
int field_count = 0;
|
||||||
long int group_number = 0; //local group number for array index value
|
long int group_number = 0; //local group number for array index value
|
||||||
UNUSED(group_number);
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (fgets(buffer, BSIZE, fp)) {
|
while (fgets(buffer, BSIZE, fp)) {
|
||||||
field_count = 0;
|
field_count = 0;
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* dsd_ks.c
|
|
||||||
* Placeholder File 6 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
1273
src/dsd_main.c
1273
src/dsd_main.c
File diff suppressed because it is too large
Load Diff
140
src/dsd_mbe.c
140
src/dsd_mbe.c
@@ -17,18 +17,17 @@
|
|||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
//NOTE: This set of functions will be reorganized and simplified (hopefully) or at least
|
//NOTE: I attempted to fix the atrocious tab/space alignnment issues that happened in this file,
|
||||||
//a more logical flow will be established to jive with the new audio handling
|
//it looks fine in VSCodium, but no telling how it will translate when pushed to Github or another editor
|
||||||
|
|
||||||
void keyring(dsd_opts * opts, dsd_state * state)
|
void keyring(dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
state->R = state->rkey_array[state->payload_keyid];
|
state->R = state->rkey_array[state->payload_keyid];
|
||||||
|
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
state->RR = state->rkey_array[state->payload_keyidR];
|
state->RR = state->rkey_array[state->payload_keyidR];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RC4(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[])
|
void RC4(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[])
|
||||||
@@ -123,7 +122,7 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
|||||||
{
|
{
|
||||||
readImbe4400Data (opts, state, imbe_d);
|
readImbe4400Data (opts, state, imbe_d);
|
||||||
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||||
if (opts->audio_out == 1 && opts->floating_point == 0)
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
processAudio(opts, state);
|
processAudio(opts, state);
|
||||||
}
|
}
|
||||||
@@ -132,20 +131,15 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
|||||||
writeSynthesizedVoice (opts, state);
|
writeSynthesizedVoice (opts, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->audio_out == 1 && opts->floating_point == 0)
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
playSynthesizedVoice (opts, state);
|
playSynthesizedVoice (opts, state);
|
||||||
}
|
}
|
||||||
if (opts->floating_point == 1)
|
|
||||||
{
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
playSynthesizedVoiceFM (opts, state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (state->mbe_file_type > 0) //ambe files
|
else if (state->mbe_file_type > 0) //ambe files
|
||||||
{
|
{
|
||||||
readAmbe2450Data (opts, state, ambe_d);
|
readAmbe2450Data (opts, state, ambe_d);
|
||||||
int x;
|
int j, x;
|
||||||
unsigned long long int k;
|
unsigned long long int k;
|
||||||
if (state->K != 0) //apply Pr key
|
if (state->K != 0) //apply Pr key
|
||||||
{
|
{
|
||||||
@@ -163,7 +157,7 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
|||||||
//dstar ambe
|
//dstar ambe
|
||||||
if (state->mbe_file_type == 2) mbe_processAmbe2400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
if (state->mbe_file_type == 2) mbe_processAmbe2400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||||
|
|
||||||
if (opts->audio_out == 1 && opts->floating_point == 0)
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
processAudio(opts, state);
|
processAudio(opts, state);
|
||||||
}
|
}
|
||||||
@@ -171,16 +165,10 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
|||||||
{
|
{
|
||||||
writeSynthesizedVoice (opts, state);
|
writeSynthesizedVoice (opts, state);
|
||||||
}
|
}
|
||||||
|
if (opts->audio_out == 1)
|
||||||
if (opts->audio_out == 1 && opts->floating_point == 0)
|
|
||||||
{
|
{
|
||||||
playSynthesizedVoice (opts, state);
|
playSynthesizedVoice (opts, state);
|
||||||
}
|
}
|
||||||
if (opts->floating_point == 1)
|
|
||||||
{
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
playSynthesizedVoiceFM (opts, state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (exitflag == 1)
|
if (exitflag == 1)
|
||||||
{
|
{
|
||||||
@@ -197,14 +185,15 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
int i;
|
int i;
|
||||||
char imbe_d[88];
|
char imbe_d[88];
|
||||||
char ambe_d[49];
|
char ambe_d[49];
|
||||||
|
char ambe_d_str[50];
|
||||||
unsigned long long int k;
|
unsigned long long int k;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
//these conditions should ensure no clashing with the BP/HBP/Scrambler key loading machanisms already coded in
|
//these conditions should ensure no clashing with the BP/HBP/Scrambler key loading machanisms already coded in
|
||||||
if (state->currentslot == 0 && state->payload_algid != 0 && state->payload_algid != 0x80 && state->keyloader == 1)
|
if (state->currentslot == 0 && state->payload_algid != 0 && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->keyloader == 1)
|
||||||
keyring (opts, state);
|
keyring (opts, state);
|
||||||
|
|
||||||
if (state->currentslot == 1 && state->payload_algidR != 0 && state->payload_algidR != 0x80 && state->keyloader == 1)
|
if (state->currentslot == 1 && state->payload_algidR != 0 && state->payload_algidR != 0x80 && state->payload_keyidR != 0 && state->keyloader == 1)
|
||||||
keyring (opts, state);
|
keyring (opts, state);
|
||||||
|
|
||||||
//24-bit TG to 16-bit hash
|
//24-bit TG to 16-bit hash
|
||||||
@@ -227,7 +216,6 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
|
|
||||||
//set playback mode for this frame
|
//set playback mode for this frame
|
||||||
char mode[8];
|
char mode[8];
|
||||||
sprintf (mode, "%s", "");
|
|
||||||
|
|
||||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||||
@@ -243,12 +231,11 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
if (state->group_array[i].groupNumber == groupNumber)
|
if (state->group_array[i].groupNumber == groupNumber)
|
||||||
{
|
{
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
strcpy (mode, state->group_array[i].groupMode);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//set flag to not play audio this time, but won't prevent writing to wav files -- disabled for now
|
//set flag to not play audio this time, but won't prevent writing to wav files
|
||||||
// if (strcmp(mode, "B") == 0) opts->audio_out = 0; //causes a buzzing now (probably due to not running processAudio before the SS3 or SS4)
|
if (strcmp(mode, "B") == 0) opts->audio_out = 0;
|
||||||
|
|
||||||
//end set playback mode for this frame
|
//end set playback mode for this frame
|
||||||
|
|
||||||
@@ -541,7 +528,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t rckey[9] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
uint8_t rckey[9] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
||||||
0x00, 0x00, 0x00, 0x00}; // <- MI
|
0x00, 0x00, 0x00, 0x00}; // <- MI
|
||||||
|
|
||||||
//easier to manually load up rather than make a loop
|
//easier to manually load up rather than make a loop
|
||||||
rckey[0] = ((state->R & 0xFF00000000) >> 32);
|
rckey[0] = ((state->R & 0xFF00000000) >> 32);
|
||||||
@@ -595,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
|
||||||
@@ -619,8 +606,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t rckey[13] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
uint8_t rckey[13] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, // <- MI
|
0x00, 0x00, 0x00, 0x00, 0x00, // <- MI
|
||||||
0x00, 0x00, 0x00}; // <- MI cont.
|
0x00, 0x00, 0x00}; // <- MI cont.
|
||||||
|
|
||||||
//easier to manually load up rather than make a loop
|
//easier to manually load up rather than make a loop
|
||||||
rckey[0] = ((state->R & 0xFF00000000) >> 32);
|
rckey[0] = ((state->R & 0xFF00000000) >> 32);
|
||||||
@@ -673,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
|
||||||
@@ -824,21 +811,21 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
//DMR RC4, Slot 2
|
//DMR RC4, Slot 2
|
||||||
if (state->currentslot == 1 && state->payload_algidR == 0x21 && state->RR != 0)
|
if (state->currentslot == 1 && state->payload_algidR == 0x21 && state->RR != 0)
|
||||||
{
|
{
|
||||||
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t rckey[9] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
uint8_t rckey[9] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
||||||
0x00, 0x00, 0x00, 0x00}; // <- MI
|
0x00, 0x00, 0x00, 0x00}; // <- MI
|
||||||
|
|
||||||
//easier to manually load up rather than make a loop
|
//easier to manually load up rather than make a loop
|
||||||
rckey[0] = ((state->RR & 0xFF00000000) >> 32);
|
rckey[0] = ((state->RR & 0xFF00000000) >> 32);
|
||||||
rckey[1] = ((state->RR & 0xFF000000) >> 24);
|
rckey[1] = ((state->RR & 0xFF000000) >> 24);
|
||||||
rckey[2] = ((state->RR & 0xFF0000) >> 16);
|
rckey[2] = ((state->RR & 0xFF0000) >> 16);
|
||||||
rckey[3] = ((state->RR & 0xFF00) >> 8);
|
rckey[3] = ((state->RR & 0xFF00) >> 8);
|
||||||
rckey[4] = ((state->RR & 0xFF) >> 0);
|
rckey[4] = ((state->RR & 0xFF) >> 0);
|
||||||
rckey[5] = ((state->payload_miR & 0xFF000000) >> 24);
|
rckey[5] = ((state->payload_miR & 0xFF000000) >> 24);
|
||||||
rckey[6] = ((state->payload_miR & 0xFF0000) >> 16);
|
rckey[6] = ((state->payload_miR & 0xFF0000) >> 16);
|
||||||
rckey[7] = ((state->payload_miR & 0xFF00) >> 8);
|
rckey[7] = ((state->payload_miR & 0xFF00) >> 8);
|
||||||
rckey[8] = ((state->payload_miR & 0xFF) >> 0);
|
rckey[8] = ((state->payload_miR & 0xFF) >> 0);
|
||||||
|
|
||||||
// if (opts->payload == 1)
|
// if (opts->payload == 1)
|
||||||
// {
|
// {
|
||||||
@@ -880,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
|
||||||
@@ -904,8 +891,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t cipher[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t plain[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t rckey[13] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
uint8_t rckey[13] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, // <- MI
|
0x00, 0x00, 0x00, 0x00, 0x00, // <- MI
|
||||||
0x00, 0x00, 0x00}; // <- MI cont.
|
0x00, 0x00, 0x00}; // <- MI cont.
|
||||||
|
|
||||||
//easier to manually load up rather than make a loop
|
//easier to manually load up rather than make a loop
|
||||||
rckey[0] = ((state->RR & 0xFF00000000) >> 32);
|
rckey[0] = ((state->RR & 0xFF00000000) >> 32);
|
||||||
@@ -958,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
|
||||||
@@ -1060,33 +1047,30 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
}
|
}
|
||||||
//end reverse mute test
|
//end reverse mute test
|
||||||
|
|
||||||
//OSS 48k/1 Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other
|
#ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
|
||||||
|
//OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other
|
||||||
if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstR == 16 || state->dmrburstR == 21) )
|
if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstR == 16 || state->dmrburstR == 21) )
|
||||||
{
|
{
|
||||||
opts->audio_out = 0;
|
opts->audio_out = 0;
|
||||||
preempt = 1;
|
preempt = 1;
|
||||||
if (opts->payload == 0 && opts->slot1_on == 1)
|
if (opts->payload == 0)
|
||||||
fprintf (stderr, " *MUTED*");
|
fprintf (stderr, " *MUTED*");
|
||||||
else if (opts->payload == 0 && opts->slot1_on == 0)
|
|
||||||
fprintf (stderr, " *OFF*");
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
state->debug_audio_errors += state->errs2 + state->errs;
|
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)
|
||||||
{
|
{
|
||||||
if ( opts->floating_point == 0 ) //opts->audio_out == 1 && //needed to remove for AERO OSS so we could still save wav files during dual voices
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
processAudio(opts, state);
|
processAudio(opts, state);
|
||||||
}
|
}
|
||||||
if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot1_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
playSynthesizedVoice (opts, state); //it may be more beneficial to move this to each individual decoding type to handle, but ultimately, let's just simpifly mbe handling instead
|
playSynthesizedVoice (opts, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); //these are for mono or FDMA where we don't need to buffer and wait for a stereo mix
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->dmr_stereo == 1 && state->currentslot == 1)
|
if (opts->dmr_stereo == 1 && state->currentslot == 1)
|
||||||
@@ -1134,49 +1118,44 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
}
|
}
|
||||||
//end reverse mute test
|
//end reverse mute test
|
||||||
|
|
||||||
//OSS 48k/1 Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other
|
#ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
|
||||||
|
//OSS Specific Voice Preemption if dual voices on TDMA and one slot has preference over the other
|
||||||
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstL == 16 || state->dmrburstL == 21) )
|
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstL == 16 || state->dmrburstL == 21) )
|
||||||
{
|
{
|
||||||
opts->audio_out = 0;
|
opts->audio_out = 0;
|
||||||
preempt = 1;
|
preempt = 1;
|
||||||
if (opts->payload == 0 && opts->slot2_on == 1)
|
if (opts->payload == 0)
|
||||||
fprintf (stderr, " *MUTED*");
|
fprintf (stderr, " *MUTED*");
|
||||||
else if (opts->payload == 0 && opts->slot2_on == 0)
|
|
||||||
fprintf (stderr, " *OFF*");
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
state->debug_audio_errorsR += state->errs2R + state->errsR;
|
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)
|
||||||
{
|
{
|
||||||
if ( opts->floating_point == 0) //opts->audio_out == 1 && //needed to remove for AERO OSS so we could still save wav files during dual voices
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
processAudioR(opts, state);
|
processAudioR(opts, state);
|
||||||
}
|
}
|
||||||
if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot2_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
playSynthesizedVoiceR (opts, state);
|
playSynthesizedVoiceR (opts, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (state->f_r, state->audio_out_temp_bufR, sizeof(state->f_r));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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->errs;
|
state->debug_audio_errors += state->errs2 + state->errs;
|
||||||
if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->pulse_digi_rate_out == 8000
|
if (opts->audio_out == 1)
|
||||||
{
|
{
|
||||||
processAudio(opts, state);
|
processAudio(opts, state);
|
||||||
}
|
}
|
||||||
// if (opts->audio_out == 1)
|
if (opts->audio_out == 1)
|
||||||
// {
|
{
|
||||||
// playSynthesizedVoice (opts, state);
|
playSynthesizedVoice (opts, state);
|
||||||
// }
|
}
|
||||||
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l)); //P25p1 FDMA 8k/1 channel -f1 switch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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
|
||||||
@@ -1211,9 +1190,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
preempt = 0;
|
preempt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset audio out flag for next repitition --disabled for now
|
//reset audio out flag for next repitition
|
||||||
// if (strcmp(mode, "B") == 0) opts->audio_out = 1;
|
if (strcmp(mode, "B") == 0) opts->audio_out = 1;
|
||||||
|
|
||||||
//restore flag for null output type
|
//restore flag for null output type
|
||||||
if (opts->audio_out_type == 9) opts->audio_out = 0;
|
if (opts->audio_out_type == 9) opts->audio_out = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
174
src/dsd_mbe2.c
174
src/dsd_mbe2.c
@@ -1,174 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* TODO: Fill me in'
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* LWVMOBILE
|
|
||||||
* 2023-07 DSD-FME Florida Man Edition
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
//new and simplified/organized ambe and imbe handling
|
|
||||||
//moving all audio handling and decryption to seperate files for simplicity (eventually)
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
|
|
||||||
//the initial functions will ONLY return demodulated ambe or imbe frames, THAT'S IT!
|
|
||||||
//decryption and audio handling etc will be handled at a different area
|
|
||||||
|
|
||||||
//using soft_demod will also allow for not compiling mbelib and also using a DVstick in the future
|
|
||||||
|
|
||||||
//P25p1 IMBE 7200 or AMBE+2 EFR
|
|
||||||
void soft_demod_imbe7200 (dsd_state * state, char imbe_fr7200[8][23], char imbe_d[88])
|
|
||||||
{
|
|
||||||
state->errs = mbe_eccImbe7200x4400C0 (imbe_fr7200);
|
|
||||||
mbe_demodulateImbe7200x4400Data (imbe_fr7200);
|
|
||||||
state->errs2 = mbe_eccImbe7200x4400Data (imbe_fr7200, imbe_d);
|
|
||||||
state->debug_audio_errors += state->errs2 + state->errs;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//ProVoice IMBE 7100
|
|
||||||
void soft_demod_imbe7100 (dsd_state * state, char imbe_fr7100[7][24], char imbe_d[88])
|
|
||||||
{
|
|
||||||
state->errs = mbe_eccImbe7100x4400C0 (imbe_fr7100);
|
|
||||||
mbe_demodulateImbe7100x4400Data (imbe_fr7100);
|
|
||||||
state->errs2 = mbe_eccImbe7100x4400Data (imbe_fr7100, imbe_d);
|
|
||||||
state->debug_audio_errors += state->errs2 + state->errs;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//AMBE+2 EHR
|
|
||||||
void soft_demod_ambe2_ehr(dsd_state * state, char ambe2_ehr[4][24], char ambe_d[49])
|
|
||||||
{
|
|
||||||
state->errs = mbe_eccAmbe3600x2450C0 (ambe2_ehr);
|
|
||||||
mbe_demodulateAmbe3600x2450Data (ambe2_ehr);
|
|
||||||
state->errs2 = mbe_eccAmbe3600x2450Data (ambe2_ehr, ambe_d);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//AMBE One Shot (DSTAR)
|
|
||||||
void soft_demod_ambe_dstar(dsd_opts * opts, dsd_state * state, char ambe_fr[4][24], char ambe_d[49])
|
|
||||||
{
|
|
||||||
mbe_processAmbe3600x2400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2,
|
|
||||||
state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
else processAudio(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
//AMBE+2 One Shot (X2-TDMA)
|
|
||||||
void soft_demod_ambe_x2(dsd_opts * opts, dsd_state * state, char ambe_fr[4][24], char ambe_d[49])
|
|
||||||
{
|
|
||||||
mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2,
|
|
||||||
state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
else processAudio(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char ambe_d[49];
|
|
||||||
char imbe_d[88];
|
|
||||||
int slot = state->currentslot;
|
|
||||||
memset (ambe_d, 0, sizeof(ambe_d));
|
|
||||||
memset (imbe_d, 0, sizeof(imbe_d));
|
|
||||||
|
|
||||||
UNUSED(i);
|
|
||||||
|
|
||||||
//P25p1, YSF FR, NXDN EFR
|
|
||||||
if (state->synctype == 0 || state->synctype == 1)
|
|
||||||
{
|
|
||||||
soft_demod_imbe7200(state, imbe_fr, imbe_d);
|
|
||||||
//handle decryption here
|
|
||||||
//print IMBE frame
|
|
||||||
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
|
|
||||||
imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
|
||||||
//send to playback here
|
|
||||||
}
|
|
||||||
|
|
||||||
//ProVoice
|
|
||||||
else if (state->synctype == 14 || state->synctype == 15)
|
|
||||||
{
|
|
||||||
soft_demod_imbe7100(state, imbe7100_fr, imbe_d);
|
|
||||||
//nothing to do
|
|
||||||
|
|
||||||
//convert to 7200
|
|
||||||
mbe_convertImbe7100to7200(imbe_d);
|
|
||||||
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
|
|
||||||
imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
|
||||||
//send to playback here
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//D-STAR AMBE
|
|
||||||
else if (state->synctype == 6 || state->synctype == 7)
|
|
||||||
{
|
|
||||||
soft_demod_ambe_dstar(opts, state, ambe_fr, ambe_d);
|
|
||||||
if(opts->payload == 1)
|
|
||||||
PrintAMBEData (opts, state, ambe_d);
|
|
||||||
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
if (opts->wav_out_f != NULL)
|
|
||||||
writeSynthesizedVoice (opts, state);
|
|
||||||
|
|
||||||
if (opts->mbe_out_f != NULL)
|
|
||||||
saveAmbe2450Data (opts, state, ambe_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
//X2-TDMA AMBE
|
|
||||||
else if (state->synctype >= 2 && state->synctype <= 5)
|
|
||||||
{
|
|
||||||
soft_demod_ambe_x2(opts, state, ambe_fr, ambe_d);
|
|
||||||
if(opts->payload == 1)
|
|
||||||
PrintAMBEData (opts, state, ambe_d);
|
|
||||||
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
if (opts->wav_out_f != NULL)
|
|
||||||
writeSynthesizedVoice (opts, state);
|
|
||||||
|
|
||||||
if (opts->mbe_out_f != NULL)
|
|
||||||
saveAmbe2450Data (opts, state, ambe_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
//AMBE+2 EHR (NXDN, DMR, P25p2, YSF VD/1)
|
|
||||||
else
|
|
||||||
{
|
|
||||||
soft_demod_ambe2_ehr (state, ambe_fr, ambe_d);
|
|
||||||
//decrypt here
|
|
||||||
if(opts->payload == 1)
|
|
||||||
PrintAMBEData (opts, state, ambe_d);
|
|
||||||
//make left or right channel decision
|
|
||||||
if (slot == 0)
|
|
||||||
{
|
|
||||||
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
|
|
||||||
ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
|
||||||
}
|
|
||||||
if (slot == 1)
|
|
||||||
{
|
|
||||||
mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, &state->errsR, &state->errs2R, state->err_strR,
|
|
||||||
ambe_d, state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2, opts->uvquality);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1176
src/dsd_ncurses.c
1176
src/dsd_ncurses.c
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
|||||||
void resetState (dsd_state * state)
|
void resetState (dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
//Dibit Buffer -- Free Allocated Memory
|
//Dibit Buffer -- Free Allocated Memory
|
||||||
// free (state->dibit_buf);
|
// free (state->dibit_buf);
|
||||||
|
|||||||
@@ -30,14 +30,12 @@ void error(char *msg) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_in address;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Connect
|
// Connect
|
||||||
//
|
//
|
||||||
int Connect (char *hostname, int portno)
|
int Connect (char *hostname, int portno)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd, n;
|
||||||
struct sockaddr_in serveraddr;
|
struct sockaddr_in serveraddr;
|
||||||
struct hostent *server;
|
struct hostent *server;
|
||||||
|
|
||||||
@@ -224,10 +222,9 @@ bool GetSignalLevelEx(int sockfd, double *dBFS, int n_samp)
|
|||||||
//shoe in UDP input connection here...still having issues that I don't know how to resolve
|
//shoe in UDP input connection here...still having issues that I don't know how to resolve
|
||||||
int UDPBind (char *hostname, int portno)
|
int UDPBind (char *hostname, int portno)
|
||||||
{
|
{
|
||||||
UNUSED(hostname);
|
int sockfd, n;
|
||||||
|
struct sockaddr_in serveraddr, client_addr;
|
||||||
int sockfd;
|
struct hostent *server;
|
||||||
struct sockaddr_in serveraddr;
|
|
||||||
|
|
||||||
/* socket: create the socket */
|
/* socket: create the socket */
|
||||||
//UDP socket
|
//UDP socket
|
||||||
@@ -256,8 +253,6 @@ int UDPBind (char *hostname, int portno)
|
|||||||
//going to leave this function available, even if completely switched over to rtl_dev_tune now, may be useful in the future
|
//going to leave this function available, even if completely switched over to rtl_dev_tune now, may be useful in the future
|
||||||
void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
int handle;
|
int handle;
|
||||||
unsigned short udp_port = opts->rtl_udp_port;
|
unsigned short udp_port = opts->rtl_udp_port;
|
||||||
char data[5] = {0}; //data buffer size is 5 for UDP frequency tuning
|
char data[5] = {0}; //data buffer size is 5 for UDP frequency tuning
|
||||||
@@ -281,68 +276,4 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
|||||||
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
||||||
|
|
||||||
close (handle); //close socket after sending.
|
close (handle); //close socket after sending.
|
||||||
}
|
}
|
||||||
|
|
||||||
int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
|
|
||||||
{
|
|
||||||
UNUSED(state);
|
|
||||||
size_t err = 0;
|
|
||||||
|
|
||||||
//listen with:
|
|
||||||
|
|
||||||
//short 8k/2
|
|
||||||
//socat stdio udp-listen:23456 | play --buffer 320*2 -q -b 16 -r 8000 -c2 -t s16 -
|
|
||||||
|
|
||||||
//short 8k/1
|
|
||||||
//socat stdio udp-listen:23456 | play --buffer 160*2 -q -b 16 -r 48000 -c2 -t s16 -
|
|
||||||
|
|
||||||
//float 8k/2
|
|
||||||
//socat stdio udp-listen:23456 | play --buffer 320*4 -q -e float -b 32 -r 8000 -c2 -t f32 -
|
|
||||||
|
|
||||||
//float 8k/1
|
|
||||||
//socat stdio udp-listen:23456 | play --buffer 160*4 -q -e float -b 32 -r 8000 -c1 -t f32 -
|
|
||||||
|
|
||||||
//send audio or data to socket
|
|
||||||
err = sendto(opts->udp_sockfd, data, nsam, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
|
||||||
if (err < 0) fprintf (stderr, "\n UDP SENDTO ERR %ld", err); //return value here is size_t number of characters sent, or -1 for failure
|
|
||||||
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
|
|
||||||
}
|
|
||||||
|
|
||||||
int udp_socket_connect(dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
long int err = 0;
|
|
||||||
err = opts->udp_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
||||||
if (err < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " UDP Socket Error %ld\n", err);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't think this is needed, but doesn't seem to hurt to keep it here either
|
|
||||||
int broadcastEnable = 1;
|
|
||||||
err = setsockopt(opts->udp_sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
|
|
||||||
if (err < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " UDP Broadcast Set Error %ld\n", err);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset((char * ) & address, 0, sizeof(address));
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
err = address.sin_addr.s_addr = inet_addr(opts->udp_hostname);
|
|
||||||
if (err < 0) //error in this context reports back 32-bit inet_addr reversed order byte pairs
|
|
||||||
{
|
|
||||||
fprintf (stderr, " UDP inet_addr Error %ld\n", err);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
address.sin_port = htons(opts->udp_portno);
|
|
||||||
if (err < 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " UDP htons Error %ld\n", err);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
void
|
void
|
||||||
openSerial (dsd_opts * opts, dsd_state * state)
|
openSerial (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
struct termios tty;
|
struct termios tty;
|
||||||
speed_t baud;
|
speed_t baud;
|
||||||
@@ -74,7 +73,6 @@ resumeScan (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
char cmd[16];
|
char cmd[16];
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
UNUSED(result);
|
|
||||||
|
|
||||||
if (opts->serial_fd > 0)
|
if (opts->serial_fd > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
198
src/dsd_symbol.c
198
src/dsd_symbol.c
@@ -17,33 +17,10 @@
|
|||||||
|
|
||||||
#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)
|
||||||
{
|
{
|
||||||
short sample;
|
short sample, sample2;
|
||||||
int i, sum, symbol, count;
|
int i, sum, symbol, count;
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
|
|
||||||
@@ -144,6 +121,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
//else cleanup and exit
|
//else cleanup and exit
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
|
||||||
cleanupAndExit(opts, state);
|
cleanupAndExit(opts, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,10 +129,14 @@ 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
|
||||||
// Read demodulated stream here
|
// TODO: need to read demodulated stream here
|
||||||
if (get_rtlsdr_sample(&sample, opts, state) < 0)
|
// get_rtlsdr_sample(&sample);
|
||||||
cleanupAndExit(opts, state);
|
get_rtlsdr_sample(&sample, opts, state);
|
||||||
//update root means square power level
|
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
|
||||||
@@ -213,6 +195,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||||
fprintf (stderr, "Closing DSD-FME.\n");
|
fprintf (stderr, "Closing DSD-FME.\n");
|
||||||
|
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
|
||||||
cleanupAndExit(opts, state);
|
cleanupAndExit(opts, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,101 +247,6 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//reworked a bit to allow raw audio wav file saving without the monitoring poriton active
|
|
||||||
if (have_sync == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
//do an extra checkfor carrier signal so that random raw audio spurts don't play during decoding
|
|
||||||
if ( (state->carrier == 1) && ((time(NULL) - state->last_vc_sync_time) < 2))
|
|
||||||
{
|
|
||||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
|
||||||
state->analog_sample_counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//sanity check to prevent an overflow
|
|
||||||
if (state->analog_sample_counter > 959)
|
|
||||||
state->analog_sample_counter = 959;
|
|
||||||
|
|
||||||
state->analog_out[state->analog_sample_counter++] = sample;
|
|
||||||
|
|
||||||
if (state->analog_sample_counter == 960)
|
|
||||||
{
|
|
||||||
//get an rms value if not using the rtl built in version
|
|
||||||
if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1)
|
|
||||||
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
|
||||||
|
|
||||||
//debug
|
|
||||||
// opts->rtl_rms = 101;
|
|
||||||
|
|
||||||
//make it a little quieter
|
|
||||||
// for (int x = 0; x < 960; x++)
|
|
||||||
// state->analog_out[x] /= 4;
|
|
||||||
|
|
||||||
//seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise
|
|
||||||
if ( (opts->rtl_rms > opts->rtl_squelch_level) && (opts->monitor_input_audio == 1) )
|
|
||||||
{
|
|
||||||
if (opts->audio_out_type == 0)
|
|
||||||
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
|
|
||||||
|
|
||||||
if (opts->audio_out_type == 8)
|
|
||||||
udp_socket_blaster (opts, state, 960*2, state->analog_out);
|
|
||||||
|
|
||||||
//NOTE: Worked okay earlier in Cygwin, so should be fine -- can only operate at 48k1, else slow mode lag
|
|
||||||
|
|
||||||
//This one will only operate when OSS 48k1 (when both input and output are OSS audio)
|
|
||||||
if (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1)
|
|
||||||
write (opts->audio_out_fd, state->analog_out, 960*2);
|
|
||||||
|
|
||||||
//STDOUT, but only when operating at 48k1 (no go just yet)
|
|
||||||
// if (opts->audio_out_type == 1 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1)
|
|
||||||
// write (opts->audio_out_fd, state->analog_out, 960*2);
|
|
||||||
|
|
||||||
//OSS 8k1 (no go just yet)
|
|
||||||
// if (opts->audio_out_type == 2 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1)
|
|
||||||
// write (opts->audio_out_fd, state->analog_out, 960*2);
|
|
||||||
|
|
||||||
//test updating the sync time, so we can hold here while trunking or scanning
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
state->last_vc_sync_time = time(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
//raw wav file saving -- only write when not NXDN, dPMR, or M17 due to noise that can cause tons of false positives when no sync
|
|
||||||
if (opts->wav_out_raw != NULL && opts->frame_nxdn48 == 0 && opts->frame_nxdn96 == 0 && opts->frame_dpmr == 0 && opts->frame_m17 == 0)
|
|
||||||
{
|
|
||||||
sf_write_short(opts->wav_out_raw, state->analog_out, 960);
|
|
||||||
sf_write_sync (opts->wav_out_raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
|
||||||
state->analog_sample_counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_sync == 1)
|
|
||||||
{
|
|
||||||
//sanity check to prevent an overflow
|
|
||||||
if (state->analog_sample_counter > 959)
|
|
||||||
state->analog_sample_counter = 959;
|
|
||||||
|
|
||||||
state->analog_out[state->analog_sample_counter++] = sample;
|
|
||||||
|
|
||||||
if (state->analog_sample_counter == 960)
|
|
||||||
{
|
|
||||||
//raw wav file saving -- file size on this blimps pretty fast 1 min ~= 6 MB; 1 hour ~= 360 MB;
|
|
||||||
if (opts->wav_out_raw != NULL)
|
|
||||||
{
|
|
||||||
sf_write_short(opts->wav_out_raw, state->analog_out, 960);
|
|
||||||
sf_write_sync (opts->wav_out_raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
//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
|
if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33
|
||||||
@@ -394,7 +282,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
{
|
{
|
||||||
//sample = dmr_filter(sample); //work on filter later
|
//sample = dmr_filter(sample); //work on filter later
|
||||||
}
|
}
|
||||||
else
|
else // the 12.5KHz NXDN filter is the same as the DMR filter...hopefully
|
||||||
{
|
{
|
||||||
sample = dmr_filter(sample);
|
sample = dmr_filter(sample);
|
||||||
}
|
}
|
||||||
@@ -479,8 +367,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
|
|
||||||
if (state->samplesPerSymbol == 20) //nxdn 4800 baud 2400 symbol rate
|
if (state->samplesPerSymbol == 20) //nxdn 4800 baud 2400 symbol rate
|
||||||
{
|
{
|
||||||
// if ((i >= 9) && (i <= 11))
|
if ((i >= 9) && (i <= 11))
|
||||||
if ((i >= 7) && (i <= 13)) //7, 13 working good on multiple nxdn48, fewer random errors
|
|
||||||
{
|
{
|
||||||
sum += sample;
|
sum += sample;
|
||||||
count++;
|
count++;
|
||||||
@@ -499,24 +386,12 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
if (state->rf_mod == 0)
|
if (state->rf_mod == 0)
|
||||||
{
|
{
|
||||||
// 0: C4FM modulation
|
// 0: C4FM modulation
|
||||||
|
|
||||||
//EXPERIMENTAL: manipulate the left edge depending on sync type
|
|
||||||
//TODO: See if we can manipulate this a bit more based on AFC or similar type function
|
|
||||||
int l_edge = 2;
|
|
||||||
int r_edge = 2;
|
|
||||||
|
|
||||||
if (state->synctype == 30 || state->synctype == 31) l_edge = 1; //YSF (need to test with new recordings at BW:12000)
|
if ((i >= state->symbolCenter - 1) && (i <= state->symbolCenter + 2))
|
||||||
else if ((state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33) l_edge = 1;
|
{
|
||||||
else l_edge = 2; //P25 and NXDN96 perform better, DMR doesn't seem to care too much, but may favor 1 and not 2
|
sum += sample;
|
||||||
|
count++;
|
||||||
if ((i >= state->symbolCenter - l_edge) && (i <= state->symbolCenter + r_edge))
|
}
|
||||||
{
|
|
||||||
sum += sample;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug: show what was selected for the left edge
|
|
||||||
// fprintf (stderr, " L:%d", l_edge);
|
|
||||||
|
|
||||||
#ifdef TRACE_DSD
|
#ifdef TRACE_DSD
|
||||||
if (i == state->symbolCenter - 1) {
|
if (i == state->symbolCenter - 1) {
|
||||||
@@ -527,18 +402,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (state->rf_mod == 1) //QPSK
|
else
|
||||||
{
|
|
||||||
//going one left, two on the right for QPSK, local system seems to favor that
|
|
||||||
//with same PPM setting used on C4FM, unsure if that works on other systems, just
|
|
||||||
//testing things now, not like QPSK works well here anyways
|
|
||||||
if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 2)) //1,2
|
|
||||||
{
|
|
||||||
sum += sample;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else //GFSK
|
|
||||||
{
|
{
|
||||||
// 1: QPSK modulation
|
// 1: QPSK modulation
|
||||||
// 2: GFSK modulation
|
// 2: GFSK modulation
|
||||||
@@ -547,23 +411,12 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
// comes one sample too late.
|
// comes one sample too late.
|
||||||
// This change makes a significant improvement in the BER, at least for
|
// This change makes a significant improvement in the BER, at least for
|
||||||
// this file.
|
// this file.
|
||||||
// if ((i == state->symbolCenter) || (i == state->symbolCenter + 1))
|
//if ((i == state->symbolCenter) || (i == state->symbolCenter + 1))
|
||||||
//GFSK should ideally be the same on the left and right, I would think
|
|
||||||
//I have not observed a system that would benefit from this alignment
|
|
||||||
if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 1))
|
if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 1))
|
||||||
{
|
{
|
||||||
sum += sample;
|
sum += sample;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//MISC Notes: When using RTL input, NXDN96 at BW:16 NXDN48 at BW:12
|
|
||||||
//I am beginning to suspect that RTL input is halfing the bandwidth, which
|
|
||||||
//is my original consclusion back when I was working on it last, unsure
|
|
||||||
//or the best course on that, could just be a rtl_fm flaw
|
|
||||||
//P25 may also work better at 16 as well now, hard to tell the difference since both are good
|
|
||||||
//DMR may not be any different on 12 or 16
|
|
||||||
//most likely though, this all will just depend on signal stregth more than anything
|
|
||||||
//as to how much BW you should set
|
|
||||||
|
|
||||||
#ifdef TRACE_DSD
|
#ifdef TRACE_DSD
|
||||||
//if (i == state->symbolCenter) {
|
//if (i == state->symbolCenter) {
|
||||||
@@ -635,9 +488,9 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
state->symbolc = fgetc(opts->symbolfile);
|
state->symbolc = fgetc(opts->symbolfile);
|
||||||
|
|
||||||
//experimental throttle
|
//experimental throttle
|
||||||
|
useconds_t stime = state->symbol_throttle;
|
||||||
if (state->use_throttle == 1)
|
if (state->use_throttle == 1)
|
||||||
{
|
{
|
||||||
// useconds_t stime = state->symbol_throttle;
|
|
||||||
// usleep(stime);
|
// usleep(stime);
|
||||||
usleep(.003); //very environment specific, tuning to cygwin
|
usleep(.003); //very environment specific, tuning to cygwin
|
||||||
}
|
}
|
||||||
@@ -656,6 +509,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
//else cleanup and exit
|
//else cleanup and exit
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
|
||||||
cleanupAndExit(opts, state);
|
cleanupAndExit(opts, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,23 +136,3 @@ upsample (dsd_state * state, float invalue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//produce 6 short samples (48k) for every 1 short sample (8k)
|
|
||||||
void upsampleS (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
|
|
||||||
|
|
||||||
}
|
|
||||||
538
src/dstar.c
538
src/dstar.c
@@ -1,397 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 DSD Author
|
||||||
|
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||||
|
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: D-STAR support is fairly complete at this point.
|
||||||
|
* The ambe3600x2450 decoder is similar butnot compatible with D-STAR voice frames.
|
||||||
|
* The dstar interleave pattern is different as well.
|
||||||
|
* GMSK modulation optimizations will also required to get a usable bit error
|
||||||
|
*/
|
||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
#include "dstar_const.h"
|
#include "dstar_const.h"
|
||||||
#include "fcs.h"
|
#include "dstar_header.h"
|
||||||
|
|
||||||
//simplified DSTAR
|
|
||||||
void processDSTAR(dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
uint8_t sd[480];
|
|
||||||
memset (sd, 0, sizeof(sd));
|
|
||||||
int i, j, dibit;
|
|
||||||
char ambe_fr[4][24];
|
|
||||||
const int *w, *x;
|
|
||||||
memset(ambe_fr, 0, sizeof(ambe_fr));
|
|
||||||
w = dW;
|
|
||||||
x = dX;
|
|
||||||
|
|
||||||
//20 voice and 19 slow data frames (20th is frame sync)
|
void processDSTAR(dsd_opts * opts, dsd_state * state) {
|
||||||
for (j = 0; j < 21; j++)
|
// extracts AMBE frames from D-STAR voice frame
|
||||||
{
|
int i, j, dibit;
|
||||||
|
char ambe_fr[4][24];
|
||||||
|
unsigned char data[9];
|
||||||
|
unsigned int bits[4];
|
||||||
|
int framecount;
|
||||||
|
int sync_missed = 0;
|
||||||
|
unsigned char slowdata[4];
|
||||||
|
unsigned int bitbuffer = 0;
|
||||||
|
const int *w, *x;
|
||||||
|
|
||||||
memset(ambe_fr, 0, sizeof(ambe_fr));
|
//set carrier to 1 so ncurses will light up green
|
||||||
w = dW;
|
state->carrier = 1;
|
||||||
x = dX;
|
|
||||||
|
|
||||||
for (i = 0; i < 72; i++)
|
if (opts->errorbars == 1) {
|
||||||
{
|
fprintf (stderr, "e:");
|
||||||
dibit = getDibit(opts, state);
|
}
|
||||||
ambe_fr[*w][*x] = dibit & 1;
|
|
||||||
w++;
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
|
|
||||||
soft_mbe(opts, state, NULL, ambe_fr, NULL);
|
#ifdef DSTAR_DUMP
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (j != 20)
|
if (state->synctype == 18) {
|
||||||
{
|
framecount = 0;
|
||||||
for (i = 0; i < 24; i++)
|
state->synctype = 6;
|
||||||
{
|
} else if (state->synctype == 19) {
|
||||||
//slow data
|
framecount = 0;
|
||||||
sd[(j*24)+i] = (uint8_t) getDibit(opts, state);
|
state->synctype = 7;
|
||||||
|
} else {
|
||||||
|
framecount = 1; //just saw a sync frame; there should be 20 not 21 till the next
|
||||||
|
}
|
||||||
|
//why is this running in a loop for?
|
||||||
|
while (sync_missed < 3) {
|
||||||
|
|
||||||
}
|
memset(ambe_fr, 0, 96);
|
||||||
}
|
// voice frame
|
||||||
|
w = dW;
|
||||||
|
x = dX;
|
||||||
|
|
||||||
if (j == 20)
|
for (i = 0; i < 72; i++) {
|
||||||
processDSTAR_SD(opts, state, sd);
|
|
||||||
|
|
||||||
//since we are in a long loop, use this to improve response time in ncurses
|
dibit = getDibit(opts, state);
|
||||||
if (opts->use_ncurses_terminal == 1)
|
|
||||||
ncursesPrinter(opts, state);
|
|
||||||
|
|
||||||
}
|
bitbuffer <<= 1;
|
||||||
|
if (dibit == 1) {
|
||||||
|
bitbuffer |= 0x01;
|
||||||
|
}
|
||||||
|
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
|
||||||
|
// we're slipping bits
|
||||||
|
fprintf (stderr, "sync in voice after i=%d, restarting\n", i);
|
||||||
|
//ugh just start over
|
||||||
|
i = 0;
|
||||||
|
w = dW;
|
||||||
|
x = dX;
|
||||||
|
framecount = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
ambe_fr[*w][*x] = (1 & dibit);
|
||||||
|
w++;
|
||||||
|
x++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
processMbeFrame(opts, state, NULL, ambe_fr, NULL);
|
||||||
|
|
||||||
|
// data frame - 24 bits
|
||||||
|
for (i = 73; i < 97; i++) {
|
||||||
|
dibit = getDibit(opts, state);
|
||||||
|
bitbuffer <<= 1;
|
||||||
|
if (dibit == 1) {
|
||||||
|
bitbuffer |= 0x01;
|
||||||
|
}
|
||||||
|
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
|
||||||
|
// looking if we're slipping bits
|
||||||
|
if (i != 96) {
|
||||||
|
fprintf (stderr, "sync after i=%d\n", i);
|
||||||
|
i = 96;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slowdata[0] = (bitbuffer >> 16) & 0x000000FF;
|
||||||
|
slowdata[1] = (bitbuffer >> 8) & 0x000000FF;
|
||||||
|
slowdata[2] = (bitbuffer) & 0x000000FF;
|
||||||
|
slowdata[3] = 0;
|
||||||
|
|
||||||
|
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
|
||||||
|
//We got sync!
|
||||||
|
//fprintf (stderr, "Sync on framecount = %d\n", framecount);
|
||||||
|
sync_missed = 0;
|
||||||
|
} else if ((bitbuffer & 0x00FFFFFF) == 0xAAAAAA) {
|
||||||
|
//End of transmission
|
||||||
|
fprintf (stderr, "End of transmission\n");
|
||||||
|
goto end;
|
||||||
|
} else if (framecount % 21 == 0) {
|
||||||
|
fprintf (stderr, "Missed sync on framecount = %d, value = %x/%x/%x\n",
|
||||||
|
framecount, slowdata[0], slowdata[1], slowdata[2]);
|
||||||
|
sync_missed++;
|
||||||
|
} else if (framecount != 0 && (bitbuffer & 0x00FFFFFF) != 0x000000) {
|
||||||
|
slowdata[0] ^= 0x70;
|
||||||
|
slowdata[1] ^= 0x4f;
|
||||||
|
slowdata[2] ^= 0x93;
|
||||||
|
//fprintf (stderr, "unscrambled- %02X %02X %02X %02X \n", slowdata[0], slowdata[1], slowdata[2], slowdata[3] );
|
||||||
|
|
||||||
|
} else if (framecount == 0) {
|
||||||
|
//fprintf (stderr, "never scrambled-%c\n",slowdata);
|
||||||
|
//fprintf (stderr, "never scrambled- %02X %02X %02X %02X \n", slowdata[0], slowdata[1], slowdata[2], slowdata[3] );
|
||||||
|
|
||||||
|
}
|
||||||
|
for (short int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (slowdata[i] <= 0x7E && slowdata[i] >=0x20)
|
||||||
|
{
|
||||||
|
//fprintf (stderr, "%c", slowdata[i]);
|
||||||
|
}
|
||||||
|
//else fprintf (stderr, ".");
|
||||||
|
}
|
||||||
|
//fprintf (stderr, "\n");
|
||||||
|
framecount++;
|
||||||
|
|
||||||
|
//since we are in a while loop, run ncursesPrinter here.
|
||||||
|
if (opts->use_ncurses_terminal == 1)
|
||||||
|
{
|
||||||
|
ncursesPrinter(opts, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
} //end while loop
|
||||||
|
|
||||||
|
end: if (opts->errorbars == 1) {
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processDSTAR_HD(dsd_opts * opts, dsd_state * state)
|
void processDSTAR_HD(dsd_opts * opts, dsd_state * state) {
|
||||||
{
|
|
||||||
|
|
||||||
int i;
|
int i, j;
|
||||||
int radioheaderbuffer[660];
|
int radioheaderbuffer[660];
|
||||||
|
|
||||||
for (i = 0; i < 660; i++)
|
for (j = 0; j < 660; j++) {
|
||||||
radioheaderbuffer[i] = getDibit(opts, state);
|
radioheaderbuffer[j] = getDibit(opts, state);
|
||||||
|
}
|
||||||
|
|
||||||
dstar_header_decode(state, radioheaderbuffer);
|
// Note: These routines contain GPLed code. Remove if you object to that.
|
||||||
processDSTAR(opts, state);
|
// Due to this, they are in a separate source file.
|
||||||
|
dstar_header_decode(state, radioheaderbuffer);
|
||||||
}
|
|
||||||
|
//We officially have sync now, so just pass on to the above routine:
|
||||||
//first 24-bits of the larger scramble table
|
|
||||||
uint8_t sd_d[48] =
|
processDSTAR(opts, state);
|
||||||
{0,0,0,0, //0
|
|
||||||
1,1,1,0, //E
|
|
||||||
1,1,1,1, //F
|
|
||||||
0,0,1,0, //2
|
|
||||||
1,1,0,0, //C
|
|
||||||
1,0,0,1};//9
|
|
||||||
|
|
||||||
//no so simplified Slow Data
|
|
||||||
void processDSTAR_SD(dsd_opts * opts, dsd_state * state, uint8_t * sd)
|
|
||||||
{
|
|
||||||
|
|
||||||
int i, j, len;
|
|
||||||
uint8_t sd_bytes[60]; //raw slow data packed into bytes
|
|
||||||
uint8_t hd_bytes[60]; //storage for packed bytes sans the header indicator byte (0x55)
|
|
||||||
uint8_t payload[60]; //unchanged copy of sd_bytes for payload printing
|
|
||||||
uint8_t rev[480]; //storage for reversing the bit order
|
|
||||||
memset (sd_bytes, 0, sizeof(sd_bytes));
|
|
||||||
memset (hd_bytes, 0, sizeof(hd_bytes));
|
|
||||||
memset (payload, 0, sizeof(payload));
|
|
||||||
|
|
||||||
//apply the descrambler
|
|
||||||
for (i = 0; i < 480; i++)
|
|
||||||
sd[i] ^= sd_d[i%24];
|
|
||||||
|
|
||||||
//reverse the bit order
|
|
||||||
for (i = 0; i < 480; i++)
|
|
||||||
rev[i] = sd[479-i];
|
|
||||||
for (i = 0; i < 480; i++)
|
|
||||||
sd[i] = rev[i];
|
|
||||||
|
|
||||||
//load bytes by least significant byte to most significant byte
|
|
||||||
//as seen in "The Format of D-Star Slow Data" by Jonathan Naylor
|
|
||||||
for (i = 0; i < 60; i++)
|
|
||||||
sd_bytes[59-i] = (uint8_t)ConvertBitIntoBytes(&sd[i*8+0], 8);
|
|
||||||
|
|
||||||
//make a copy to payload that won't be altered
|
|
||||||
memcpy (payload, sd_bytes, sizeof(payload));
|
|
||||||
|
|
||||||
len = sd_bytes[0] & 0xF;
|
|
||||||
len += 1;
|
|
||||||
|
|
||||||
//load payload bytes without the header indicator byte
|
|
||||||
for (i = 0, j = 0; i < 50; i++)
|
|
||||||
{
|
|
||||||
j++;
|
|
||||||
hd_bytes[i] = sd_bytes[j];
|
|
||||||
if (j == len*1-1) j++;
|
|
||||||
if (j == len*2-1) j++;
|
|
||||||
if (j == len*3-1) j++;
|
|
||||||
if (j == len*4-1) j++;
|
|
||||||
if (j == len*5-1) j++;
|
|
||||||
if (j == len*6-1) j++;
|
|
||||||
if (j == len*7-1) j++;
|
|
||||||
if (j == len*8-1) j++;
|
|
||||||
if (j == len*9-1) j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//works on header format -- may not work on others
|
|
||||||
uint16_t crc_ext = (hd_bytes[39] << 8) + hd_bytes[40];
|
|
||||||
uint16_t crc_cmp = calc_fcs(hd_bytes, 39);
|
|
||||||
|
|
||||||
char str1[9];
|
|
||||||
char str2[9];
|
|
||||||
char str3[9];
|
|
||||||
char str4[13];
|
|
||||||
char strf[60];
|
|
||||||
char strt[60];
|
|
||||||
memset (strf, 0x20, sizeof(strf));
|
|
||||||
memset (strt, 0x20, sizeof(strf));
|
|
||||||
memcpy (str1, hd_bytes+3, 8);
|
|
||||||
memcpy (str2, hd_bytes+11, 8);
|
|
||||||
memcpy (str3, hd_bytes+19, 8);
|
|
||||||
memcpy (str4, hd_bytes+27, 12);
|
|
||||||
str1[8] = '\0';
|
|
||||||
str2[8] = '\0';
|
|
||||||
str3[8] = '\0';
|
|
||||||
str4[12] = '\0';
|
|
||||||
|
|
||||||
//safety check, don't want to load nasty values into the strings
|
|
||||||
for (i = 1; i < 60; i++)
|
|
||||||
{
|
|
||||||
//substitue non-ascii characters for spaces
|
|
||||||
if (sd_bytes[i] < 0x20)
|
|
||||||
sd_bytes[i] = 0x20;
|
|
||||||
else if (sd_bytes[i] > 0x7E)
|
|
||||||
sd_bytes[i] = 0x20;
|
|
||||||
|
|
||||||
//substitue non-ascii characters for spaces
|
|
||||||
if (hd_bytes[i] < 0x20)
|
|
||||||
hd_bytes[i] = 0x20;
|
|
||||||
else if (hd_bytes[i] > 0x7E)
|
|
||||||
hd_bytes[i] = 0x20;
|
|
||||||
|
|
||||||
//replace terminating ffffffff (repeating 0x66 values) with NULL (0x00)
|
|
||||||
if (i < 59)
|
|
||||||
{
|
|
||||||
if (sd_bytes[i] == 0x66 && sd_bytes[i+1] == 0x66)
|
|
||||||
sd_bytes[i] = 0x00;
|
|
||||||
|
|
||||||
if (hd_bytes[i] == 0x66 && hd_bytes[i+1] == 0x66)
|
|
||||||
hd_bytes[i] = 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 59 && sd_bytes[i] == 0x66)
|
|
||||||
sd_bytes[i] = 0x00;
|
|
||||||
|
|
||||||
if (i == 59 && hd_bytes[i] == 0x66)
|
|
||||||
hd_bytes[i] = 0x00;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy (strf, sd_bytes+1, 58); //copy the entire thing as a string -- full
|
|
||||||
memcpy (strt, hd_bytes+1, 48); //copy the entire thing as a string -- truncated
|
|
||||||
strf[59] = '\0';
|
|
||||||
strt[59] = '\0';
|
|
||||||
|
|
||||||
char type[7]; char temp[8]; char tempa[8]; char chungus[80]; UNUSED(chungus);
|
|
||||||
memset (chungus, 0, sizeof(chungus));
|
|
||||||
memset (temp, 0, sizeof(temp));
|
|
||||||
memset (tempa, 0, sizeof(tempa));
|
|
||||||
memset (type, 0, sizeof(type));
|
|
||||||
memcpy (type, sd_bytes+1, 5);
|
|
||||||
type[6] = '\0';
|
|
||||||
|
|
||||||
if (sd_bytes[0] == 0x55) //header format
|
|
||||||
{
|
|
||||||
|
|
||||||
if (crc_cmp == crc_ext)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " RPT 2: %s", str1);
|
|
||||||
fprintf (stderr, " RPT 1: %s", str2);
|
|
||||||
fprintf (stderr, " DST: %s", str3);
|
|
||||||
fprintf (stderr, " SRC: %s", str4);
|
|
||||||
|
|
||||||
//check flags for info
|
|
||||||
if (sd_bytes[1] & 0x80) fprintf (stderr, " DATA");
|
|
||||||
if (sd_bytes[1] & 0x40) fprintf (stderr, " REPEATER");
|
|
||||||
if (sd_bytes[1] & 0x20) fprintf (stderr, " INTERRUPTED");
|
|
||||||
if (sd_bytes[1] & 0x10) fprintf (stderr, " CONTROL SIGNAL");
|
|
||||||
if (sd_bytes[1] & 0x08) fprintf (stderr, " URGENT");
|
|
||||||
|
|
||||||
memcpy (state->dstar_rpt2, str1, sizeof(str1));
|
|
||||||
memcpy (state->dstar_rpt1, str2, sizeof(str2));
|
|
||||||
memcpy (state->dstar_dst, str3, sizeof(str3));
|
|
||||||
memcpy (state->dstar_src, str4, sizeof(str4));
|
|
||||||
}
|
|
||||||
else fprintf (stderr, " SLOW DATA - HEADER FORMAT (CRC ERR)");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else //any other format (text, aprs, etc)
|
|
||||||
{
|
|
||||||
//fixed-form at 5 bytes, evaluate
|
|
||||||
if (sd_bytes[0] == 0x35)
|
|
||||||
{
|
|
||||||
|
|
||||||
//might as well just dump both of these outputs
|
|
||||||
if (strcmp(type, "$$CRC") == 0) //APRS
|
|
||||||
{
|
|
||||||
memset (strt, 0x20, sizeof(strt)); //space fill
|
|
||||||
fprintf (stderr, " DATA: ");
|
|
||||||
for (i = 1; i < 59; i++)
|
|
||||||
{
|
|
||||||
if (i%6==0) i++;
|
|
||||||
if ( (sd_bytes[i] > 0x19) && (sd_bytes[i] < 0x7F) )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%c", sd_bytes[i]);
|
|
||||||
// strt[i] = sd_bytes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// strt[59] = '\0';
|
|
||||||
// memcpy (state->dstar_gps, strt, sizeof(strt));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(type, "$$CRC") == 0) //APRS
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n APRS - ");
|
|
||||||
sprintf (state->dstar_gps, "APRS - ");
|
|
||||||
uint8_t aprs[51];
|
|
||||||
int k = 0;
|
|
||||||
memset (aprs, 0, sizeof(aprs));
|
|
||||||
//reshuffle (yet again) into an easier format to manipulate for aprs
|
|
||||||
for (i = 1; i < 59; i++)
|
|
||||||
{
|
|
||||||
if (i % 6 == 0 ) i++;
|
|
||||||
aprs[k] = sd_bytes[i];
|
|
||||||
if ( (aprs[k] > 0x19) && (aprs[k] < 0x7F) )
|
|
||||||
aprs[i] = 0x20;
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
//start by looking for the ! exclamation point token
|
|
||||||
int start = -1;
|
|
||||||
for (i = 30; i < 40; i++)
|
|
||||||
{
|
|
||||||
if (aprs[i] == 0x21)
|
|
||||||
{
|
|
||||||
start = i+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//if not found, then skip (bad decode)
|
|
||||||
if (start == -1)
|
|
||||||
goto SKIP;
|
|
||||||
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, "S: %d; ", start); //38, or 39
|
|
||||||
|
|
||||||
//LAT
|
|
||||||
memcpy (temp, aprs+start, 2);
|
|
||||||
start += 2;
|
|
||||||
fprintf (stderr, "Lat: %sd ", temp);
|
|
||||||
strcat (state->dstar_gps, "Lat: ");
|
|
||||||
strcat (state->dstar_gps, temp);
|
|
||||||
strcat (state->dstar_gps, "d ");
|
|
||||||
memcpy (temp, aprs+start, 2);
|
|
||||||
start += 3;
|
|
||||||
fprintf (stderr, "%sm ", temp);
|
|
||||||
strcat (state->dstar_gps, temp);
|
|
||||||
strcat (state->dstar_gps, "m ");
|
|
||||||
memcpy (temp, aprs+start, 2);
|
|
||||||
start+=1;
|
|
||||||
fprintf (stderr, "%ss ", temp);
|
|
||||||
strcat (state->dstar_gps, temp);
|
|
||||||
strcat (state->dstar_gps, "s ");
|
|
||||||
fprintf (stderr, "%c", aprs[start]);
|
|
||||||
if (sd_bytes[start] == 0x4E)
|
|
||||||
strcat (state->dstar_gps, "N ");
|
|
||||||
else if (sd_bytes[start] == 0x53)
|
|
||||||
strcat (state->dstar_gps, "S ");
|
|
||||||
fprintf (stderr, "; ");
|
|
||||||
|
|
||||||
//LON
|
|
||||||
start += 3;
|
|
||||||
memcpy (tempa, aprs+start, 3);
|
|
||||||
start += 3;
|
|
||||||
fprintf (stderr, "Lon: %sd ", tempa);
|
|
||||||
strcat (state->dstar_gps, "Lon: ");
|
|
||||||
strcat (state->dstar_gps, tempa);
|
|
||||||
strcat (state->dstar_gps, "d ");
|
|
||||||
memcpy (temp, aprs+start, 2);
|
|
||||||
start += 3; //3
|
|
||||||
fprintf (stderr, "%sm ", temp);
|
|
||||||
strcat (state->dstar_gps, temp);
|
|
||||||
strcat (state->dstar_gps, "m ");
|
|
||||||
memcpy (temp, aprs+start, 2);
|
|
||||||
start += 2;
|
|
||||||
fprintf (stderr, "%ss ", temp);
|
|
||||||
strcat (state->dstar_gps, temp);
|
|
||||||
strcat (state->dstar_gps, "s ");
|
|
||||||
fprintf (stderr, "%c", aprs[start]);
|
|
||||||
if (aprs[start] == 0x45)
|
|
||||||
strcat (state->dstar_gps, "E ");
|
|
||||||
else if (aprs[start] == 0x57)
|
|
||||||
strcat (state->dstar_gps, "W ");
|
|
||||||
fprintf (stderr, "; ");
|
|
||||||
|
|
||||||
//Got the feeling nobody will actually ever see this message, but who knows
|
|
||||||
fprintf(stderr, "\n DEV NOTE: If you see this message, but incorrect lat/lon,\n please submit samples to https://github.com/lwvmobile/dsd-fme/issues/164 ");
|
|
||||||
|
|
||||||
SKIP: ; //do nothing
|
|
||||||
|
|
||||||
//this seems to work okay with a few samples, but wouldn't be surprised if it broke down
|
|
||||||
//randomly on different users, depending on location and what else in in $$CRC
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// fprintf (stderr, " %s: ", type);
|
|
||||||
memset (strt, 0x20, sizeof(strt)); //space fill
|
|
||||||
fprintf (stderr, " TEXT: ");
|
|
||||||
for (i = 1; i < 59; i++)
|
|
||||||
{
|
|
||||||
if (i%6==0) i++;
|
|
||||||
if ( (sd_bytes[i] > 0x19) && (sd_bytes[i] < 0x7F) )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%c", sd_bytes[i]);
|
|
||||||
strt[i] = sd_bytes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strt[59] = '\0';
|
|
||||||
memcpy (state->dstar_txt, strt, sizeof(strt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//free-form text at 5 bytes, truncate every 6th position
|
|
||||||
else if (sd_bytes[0] == 0x40)
|
|
||||||
{
|
|
||||||
memset (strt, 0x20, sizeof(strt)); //space fill
|
|
||||||
fprintf (stderr, " TEXT: ");
|
|
||||||
for (i = 1; i < 59; i++)
|
|
||||||
{
|
|
||||||
if (i%6==0) i++;
|
|
||||||
if ( (sd_bytes[i] > 0x19) && (sd_bytes[i] < 0x7F) )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%c", sd_bytes[i]);
|
|
||||||
strt[i] = sd_bytes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strt[59] = '\0';
|
|
||||||
memcpy (state->dstar_txt, strt, sizeof(strt));
|
|
||||||
}
|
|
||||||
//anything else
|
|
||||||
else //print entire thing
|
|
||||||
{
|
|
||||||
fprintf (stderr, " _UNK:");
|
|
||||||
fprintf (stderr, " %s", strf);
|
|
||||||
// memcpy (state->dstar_txt, strf, sizeof(strf)); //don't copy the unknown garbo strings
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->payload == 1)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n SD: ");
|
|
||||||
for (i = 0; i < 60; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "[%02X]", payload[i]);
|
|
||||||
if (i == 29) fprintf (stderr, "\n ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crc_cmp != crc_ext)
|
|
||||||
fprintf (stderr, "CRC - EXT: %04X CMP: %04X", crc_ext, crc_cmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* This code is taken largely from on1arf's GMSK code. Original copyright below:
|
* This code is taken largely from on1arf's GMSK code. Original copyright below:
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 by Kristoff Bonne, ON1ARF
|
* Copyright (C) 2011 by Kristoff Bonne, ON1ARF
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -13,84 +13,75 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "fcs.h"
|
||||||
#include "descramble.h"
|
#include "descramble.h"
|
||||||
#include "dstar_header.h"
|
#include "dstar_header.h"
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
// #include "fcs.h" //error: multiple definition of `calc_fcs'; CMakeFiles/dsd-fme.dir/src/dstar.c.o:dstar.c:(.text+0x0): first defined here
|
|
||||||
|
|
||||||
void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660])
|
void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660]) {
|
||||||
{
|
|
||||||
int radioheaderbuffer2[660];
|
int radioheaderbuffer2[660];
|
||||||
char radioheader[41];
|
unsigned char radioheader[41];
|
||||||
int octetcount, bitcount, loop;
|
int octetcount, bitcount, loop;
|
||||||
unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
|
||||||
|
unsigned int FCSinheader;
|
||||||
|
unsigned int FCScalculated;
|
||||||
|
int len;
|
||||||
|
|
||||||
scramble(radioheaderbuffer, radioheaderbuffer2);
|
scramble(radioheaderbuffer, radioheaderbuffer2);
|
||||||
deinterleave(radioheaderbuffer2, radioheaderbuffer);
|
deinterleave(radioheaderbuffer2, radioheaderbuffer);
|
||||||
FECdecoder(radioheaderbuffer, radioheaderbuffer2);
|
len = FECdecoder(radioheaderbuffer, radioheaderbuffer2);
|
||||||
memset(radioheader, 0, 41);
|
memset(radioheader, 0, 41);
|
||||||
|
//memset(state->dstarradioheader, 0, 41);
|
||||||
// note we receive 330 bits, but we only use 328 of them (41 octets)
|
// note we receive 330 bits, but we only use 328 of them (41 octets)
|
||||||
// bits 329 and 330 are unused
|
// bits 329 and 330 are unused
|
||||||
octetcount = 0;
|
octetcount = 0;
|
||||||
bitcount = 0;
|
bitcount = 0;
|
||||||
for (loop = 0; loop < 328; loop++)
|
for (loop = 0; loop < 328; loop++) {
|
||||||
{
|
if (radioheaderbuffer2[loop]) {
|
||||||
if (radioheaderbuffer2[loop])
|
|
||||||
radioheader[octetcount] |= bit2octet[bitcount];
|
radioheader[octetcount] |= bit2octet[bitcount];
|
||||||
|
};
|
||||||
bitcount++;
|
bitcount++;
|
||||||
// increase octetcounter and reset bitcounter every 8 bits
|
// increase octetcounter and reset bitcounter every 8 bits
|
||||||
if (bitcount >= 8)
|
if (bitcount >= 8) {
|
||||||
{
|
|
||||||
octetcount++;
|
octetcount++;
|
||||||
bitcount = 0;
|
bitcount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//state->dstarradioheader = radioheader;
|
||||||
|
|
||||||
char str1[9];
|
for (short i = 0; i < 41; i++)
|
||||||
char str2[9];
|
{
|
||||||
char str3[9];
|
state->dstarradioheader[i] = radioheader[i];
|
||||||
char str4[13];
|
}
|
||||||
|
|
||||||
memcpy (str1, radioheader+3, 8);
|
|
||||||
memcpy (str2, radioheader+11, 8);
|
|
||||||
memcpy (str3, radioheader+19, 8);
|
|
||||||
memcpy (str4, radioheader+27, 12);
|
|
||||||
|
|
||||||
str1[8] = '\0';
|
// print header
|
||||||
str2[8] = '\0';
|
fprintf (stderr, "\nDSTAR HEADER: ");
|
||||||
str3[8] = '\0';
|
//fprintf (stderr, "FLAG1: %02X - FLAG2: %02X - FLAG3: %02X\n", radioheader[0],
|
||||||
str4[12] = '\0';
|
// radioheader[1], radioheader[2]);
|
||||||
|
fprintf (stderr, "RPT 2: %c%c%c%c%c%c%c%c ", radioheader[3], radioheader[4],
|
||||||
|
radioheader[5], radioheader[6], radioheader[7], radioheader[8],
|
||||||
|
radioheader[9], radioheader[10]);
|
||||||
|
fprintf (stderr, "RPT 1: %c%c%c%c%c%c%c%c ", radioheader[11], radioheader[12],
|
||||||
|
radioheader[13], radioheader[14], radioheader[15], radioheader[16],
|
||||||
|
radioheader[17], radioheader[18]);
|
||||||
|
fprintf (stderr, "YOUR: %c%c%c%c%c%c%c%c ", radioheader[19], radioheader[20],
|
||||||
|
radioheader[21], radioheader[22], radioheader[23], radioheader[24],
|
||||||
|
radioheader[25], radioheader[26]);
|
||||||
|
fprintf (stderr, "MY: %c%c%c%c%c%c%c%c/%c%c%c%c\n", radioheader[27],
|
||||||
|
radioheader[28], radioheader[29], radioheader[30], radioheader[31],
|
||||||
|
radioheader[32], radioheader[33], radioheader[34], radioheader[35],
|
||||||
|
radioheader[36], radioheader[37], radioheader[38]);
|
||||||
|
|
||||||
//TODO: Add fcs_calc to header as well
|
//FCSinheader = ((radioheader[39] << 8) | radioheader[40]) & 0xFFFF;
|
||||||
// uint16_t crc_ext = (radioheader[39] << 8) + radioheader[40];
|
//FCScalculated = calc_fcs((unsigned char*) radioheader, 39);
|
||||||
// uint16_t crc_cmp = calc_fcs(radioheader, 39);
|
//fprintf (stderr, "Check sum = %04X ", FCSinheader);
|
||||||
|
//if (FCSinheader == FCScalculated) {
|
||||||
//debug
|
// fprintf (stderr, "(OK)\n");
|
||||||
// fprintf (stderr, "\n HD: ");
|
//} else {
|
||||||
// for (int i = 0; i < 40; i++)
|
// fprintf (stderr, "(NOT OK- Calculated FCS = %04X)\n", FCScalculated);
|
||||||
// fprintf (stderr, "%02X ", radioheader[i]);
|
//}; // end else - if
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
fprintf (stderr, " RPT 2: %s", str1);
|
|
||||||
fprintf (stderr, " RPT 1: %s", str2);
|
|
||||||
fprintf (stderr, " DST: %s", str3);
|
|
||||||
fprintf (stderr, " SRC: %s", str4);
|
|
||||||
|
|
||||||
//check flags for info
|
|
||||||
if (radioheader[0] & 0x80) fprintf (stderr, " DATA");
|
|
||||||
if (radioheader[0] & 0x40) fprintf (stderr, " REPEATER");
|
|
||||||
if (radioheader[0] & 0x20) fprintf (stderr, " INTERRUPTED");
|
|
||||||
if (radioheader[0] & 0x10) fprintf (stderr, " CONTROL SIGNAL");
|
|
||||||
if (radioheader[0] & 0x08) fprintf (stderr, " URGENT");
|
|
||||||
|
|
||||||
memcpy (state->dstar_rpt2, str1, sizeof(str1));
|
|
||||||
memcpy (state->dstar_rpt1, str2, sizeof(str2));
|
|
||||||
memcpy (state->dstar_dst, str3, sizeof(str3));
|
|
||||||
memcpy (state->dstar_src, str4, sizeof(str4));
|
|
||||||
|
|
||||||
//TODO: Call History for DSTAR
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,8 +332,7 @@ decode_bch()
|
|||||||
{
|
{
|
||||||
register int i, j, u, q, t2, count = 0, syn_error = 0;
|
register int i, j, u, q, t2, count = 0, syn_error = 0;
|
||||||
int elp[1026][1024], d[1026], l[1026], u_lu[1026], s[1025];
|
int elp[1026][1024], d[1026], l[1026], u_lu[1026], s[1025];
|
||||||
int root[200], loc[200], reg[201];
|
int root[200], loc[200], err[1024], reg[201];
|
||||||
(void)(root);
|
|
||||||
|
|
||||||
t2 = 2 * t;
|
t2 = 2 * t;
|
||||||
|
|
||||||
|
|||||||
442
src/edacs-fme.c
442
src/edacs-fme.c
@@ -14,261 +14,37 @@
|
|||||||
* 1994-7
|
* 1994-7
|
||||||
*
|
*
|
||||||
* LWVMOBILE
|
* LWVMOBILE
|
||||||
* 2023-11 Version EDACS-FM Florida Man Edition
|
* 2022-10 Version EDACS-FM Florida Man Edition
|
||||||
*-----------------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------------*/
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
char * getDateE(void) {
|
char * getDateE(void) {
|
||||||
#ifdef AERO_BUILD
|
char datename[99]; //might honestly just need a much smaller size, and not a larger one
|
||||||
char datename[80];
|
|
||||||
#else
|
|
||||||
char datename[99];
|
|
||||||
#endif
|
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
time_t t;
|
time_t t;
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
to = localtime( & t);
|
to = localtime( & t);
|
||||||
strftime(datename, sizeof(datename), "%Y%m%d", to);
|
strftime(datename, sizeof(datename), "%Y-%m-%d", to);
|
||||||
curr2 = strtok(datename, " ");
|
curr2 = strtok(datename, " ");
|
||||||
return curr2;
|
return curr2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b
|
char * getTimeE(void) //get pretty hh:mm:ss timestamp
|
||||||
char * getTimeE(void) //get pretty hhmmss timestamp
|
|
||||||
{
|
{
|
||||||
char * curr = (char *) malloc(9);
|
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
struct tm * ptm = localtime(& t);
|
|
||||||
sprintf(
|
char * curr;
|
||||||
curr,
|
char * stamp = asctime(localtime( & t));
|
||||||
"%02d%02d%02d",
|
|
||||||
ptm->tm_hour,
|
curr = strtok(stamp, " ");
|
||||||
ptm->tm_min,
|
curr = strtok(NULL, " ");
|
||||||
ptm->tm_sec
|
curr = strtok(NULL, " ");
|
||||||
);
|
curr = strtok(NULL, " ");
|
||||||
|
|
||||||
return curr;
|
return curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void openWavOutFile48k (dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
UNUSED(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;
|
|
||||||
int count = 5; //RMS has a 5 count (5 * 180ms) now before cutting off;
|
|
||||||
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 (!exitflag && count > 0)
|
|
||||||
{
|
|
||||||
//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
|
|
||||||
|
|
||||||
//reconfigured to use seperate audio out stream that is always 48k short
|
|
||||||
if (opts->audio_out_type == 0 && opts->slot1_on == 1)
|
|
||||||
{
|
|
||||||
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 == 8) //UDP Audio
|
|
||||||
{
|
|
||||||
udp_socket_blaster (opts, state, 960*2, analog1);
|
|
||||||
udp_socket_blaster (opts, state, 960*2, analog2);
|
|
||||||
udp_socket_blaster (opts, state, 960*2, analog3);
|
|
||||||
}
|
|
||||||
|
|
||||||
//added a condition check so that if OSS output and 8K, switches to 48K when opening OSS
|
|
||||||
if (opts->audio_out_type == 5 && opts->floating_point == 0 && opts->slot1_on == 1)
|
|
||||||
{
|
|
||||||
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) count--;
|
|
||||||
else count = 5;
|
|
||||||
|
|
||||||
if (rms > sql) fprintf(stderr, "%s", KGRN);
|
|
||||||
else fprintf(stderr, "%s", KRED);
|
|
||||||
|
|
||||||
fprintf (stderr, " Analog RMS: %04ld SQL: %ld", rms, sql);
|
|
||||||
if (afs != 0)
|
|
||||||
fprintf (stderr, " AFS [%03d] [%02d-%03d] LCN [%02d]", afs, afs >> 7, afs & 0x7F, lcn);
|
|
||||||
|
|
||||||
//debug, view hit counter
|
|
||||||
// fprintf (stderr, " CNT: %d; ", count);
|
|
||||||
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
fprintf (stderr, "Analog Floating Point Output Not Supported");
|
|
||||||
|
|
||||||
//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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//digitize analog samples for a dotting sequence check
|
|
||||||
unsigned long long int sr = 0;
|
|
||||||
for (i = 0; i < 960; i+=5) //Samples Per Symbol is 5, so incrememnt every 5
|
|
||||||
{
|
|
||||||
sr = sr << 1;
|
|
||||||
sr += digitize (opts, state, (int)analog1[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " SR: %016llX", sr);
|
|
||||||
|
|
||||||
if (sr == 0xAAAAAAAAAAAAAAAA || sr == 0x5555555555555555)
|
|
||||||
count = 0; //break while loop, sr will not equal these if just random noise
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
|
|
||||||
if (count > 0) fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
@@ -288,6 +64,7 @@ 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
|
||||||
@@ -295,11 +72,10 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
unsigned int idcmd = 0xFD;
|
unsigned int idcmd = 0xFD;
|
||||||
unsigned int peercmd = 0xF88; //using for EA detection test
|
unsigned int peercmd = 0xF88; //using for EA detection test
|
||||||
unsigned int netcmd = 0xF3; //using for Networked Test
|
unsigned int netcmd = 0xF3; //using for Networked Test
|
||||||
UNUSED2(vcmd, idcmd);
|
|
||||||
|
|
||||||
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;
|
int i, j;
|
||||||
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
|
||||||
@@ -348,32 +124,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)
|
||||||
@@ -479,7 +255,6 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, " Group [%05d] Source [%08d] LCN[%02d]", group, source, lcn);
|
fprintf (stderr, " Group [%05d] Source [%08d] LCN[%02d]", group, source, lcn);
|
||||||
|
|
||||||
char mode[8]; //allow, block, digital enc
|
char mode[8]; //allow, block, digital enc
|
||||||
sprintf (mode, "%s", "");
|
|
||||||
|
|
||||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||||
@@ -491,14 +266,9 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
strcpy (mode, state->group_array[i].groupMode);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TG hold on EDACS EA -- block non-matching target, allow matching group
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold != group) sprintf (mode, "%s", "B");
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold == group) sprintf (mode, "%s", "A");
|
|
||||||
|
|
||||||
if (mt1 == 0x1) fprintf (stderr, " TDMA Call"); //never observed, wonder if any EDACS systems ever carried a TDMA signal (X2-TDMA?)
|
if (mt1 == 0x1) fprintf (stderr, " TDMA Call"); //never observed, wonder if any EDACS systems ever carried a TDMA signal (X2-TDMA?)
|
||||||
if (mt1 == 0x2) fprintf (stderr, " Group Data Call"); //Never Seen this one before
|
if (mt1 == 0x2) fprintf (stderr, " Group Data Call"); //Never Seen this one before
|
||||||
if (mt1 == 0x3) fprintf (stderr, " Digital Call"); //ProVoice, this is what we always get on SLERS EA
|
if (mt1 == 0x3) fprintf (stderr, " Digital Call"); //ProVoice, this is what we always get on SLERS EA
|
||||||
@@ -512,9 +282,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
//openwav file and do per call right here, should probably check as well to make sure we have a valid trunking method active (rigctl, rtl)
|
//openwav file and do per call right here, should probably check as well to make sure we have a valid trunking method active (rigctl, rtl)
|
||||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||||
{
|
{
|
||||||
sprintf (opts->wav_out_file, "./WAV/%s %s EDACS 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
|
||||||
@@ -523,9 +292,8 @@ 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
|
||||||
@@ -534,8 +302,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,13 +381,11 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
int a = afs >> 7;
|
int a = afs >> 7;
|
||||||
int fs = afs & 0x7F;
|
int fs = afs & 0x7F;
|
||||||
int status = (fr_1t & 0xF00000000) >> 32;
|
int status = (fr_1t & 0xF00000000) >> 32;
|
||||||
UNUSED(status);
|
|
||||||
if (afs > 0) state->lastsrc = afs;
|
if (afs > 0) state->lastsrc = afs;
|
||||||
fprintf (stderr, "%s", KGRN);
|
fprintf (stderr, "%s", KGRN);
|
||||||
fprintf (stderr, " AFS [%03d] [%02d-%03d] LCN [%02d]", afs, a, fs, lcn);
|
fprintf (stderr, " AFS [0x%03X] [%02d-%03d] LCN [%02d]", afs, a, fs, lcn);
|
||||||
|
|
||||||
char mode[8]; //allow, block, digital enc
|
char mode[8]; //allow, block, digital enc
|
||||||
sprintf (mode, "%s", "");
|
|
||||||
|
|
||||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||||
@@ -633,69 +397,49 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
strcpy (mode, state->group_array[i].groupMode);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TG hold on EDACS Standard/Net -- block non-matching target, allow matching afs (decimal)
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold != afs) sprintf (mode, "%s", "B");
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold == afs) sprintf (mode, "%s", "A");
|
|
||||||
|
|
||||||
//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)
|
||||||
fprintf (stderr, " Analog");
|
|
||||||
|
|
||||||
//Digital Call (ProVoice, hopefully, and not Aegis in 2022)
|
|
||||||
else
|
|
||||||
fprintf (stderr, " Digital");
|
|
||||||
|
|
||||||
//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
|
|
||||||
|
|
||||||
//skip analog calls on UDP Audio Output
|
|
||||||
if (command == 0xEE && opts->audio_out_type == 8)
|
|
||||||
goto ENDPV;
|
|
||||||
|
|
||||||
//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)
|
//no handling for raw audio yet...that works properly atleast
|
||||||
|
fprintf (stderr, " Analog");
|
||||||
|
}
|
||||||
|
else //Digital Call (ProVoice, hopefully not Aegis in 2022)
|
||||||
|
{
|
||||||
|
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
|
||||||
{
|
{
|
||||||
//openwav file and do per call right here
|
if (lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
|
||||||
{
|
{
|
||||||
sprintf (opts->wav_out_file, "./WAV/%s %s EDACS Site %lld AFS %02d-%03d - %03d.wav", getDateE(), getTimeE(), state->edacs_site_id, a, fs, afs);
|
//openwav file and do per call right here
|
||||||
if (command == 0xEF) openWavOutFile (opts, state); //digital
|
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||||
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);
|
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
|
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
|
||||||
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);
|
}
|
||||||
}
|
|
||||||
|
if (opts->audio_in_type == 3) //rtl dongle
|
||||||
|
{
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||||
|
state->edacs_tuned_lcn = lcn;
|
||||||
|
opts->p25_is_tuned = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (opts->audio_in_type == 3) //rtl dongle
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
|
||||||
state->edacs_tuned_lcn = lcn;
|
|
||||||
opts->p25_is_tuned = 1;
|
|
||||||
if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
@@ -716,66 +460,10 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
} //end Standard or Networked
|
} //end Standard or Networked
|
||||||
|
|
||||||
//supply user warning to use -9 switch if decoding doesn't start shortly
|
}
|
||||||
else fprintf (stderr, " Net/EA Auto Detect; Use -9 CLI Switch For Standard;");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ENDPV:
|
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void eot_cc(dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
|
|
||||||
fprintf (stderr, "EOT; \n");
|
|
||||||
|
|
||||||
//jump back to CC here
|
|
||||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
state->lasttg = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->payload_miP = 0;
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[0], "%s", "");
|
|
||||||
sprintf (state->active_channel[1], "%s", "");
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
state->lasttg = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->payload_miP = 0;
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[0], "%s", "");
|
|
||||||
sprintf (state->active_channel[1], "%s", "");
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
297
src/ez.cpp
297
src/ez.cpp
@@ -178,167 +178,146 @@ int ez_rs28_sacch (int payload[180], int parity[132])
|
|||||||
return (ec);
|
return (ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::map <std::uint64_t, int> isch_map;
|
//I-ISCH Lookup section, borrowed from OP25
|
||||||
std::map <uint64_t, int> isch_map; //User Noted GCC potential compiler error fix on BB OP25
|
std::map <std::string, int> isch_map;
|
||||||
void map_isch()
|
void map_isch()
|
||||||
{
|
{
|
||||||
isch_map[0x184229d461ULL] = 0;
|
isch_map["184229d461"] = 0;
|
||||||
isch_map[0x18761451f6ULL] = 1;
|
isch_map["18761451f6"] = 1;
|
||||||
isch_map[0x181ae27e2fULL] = 2;
|
isch_map["181ae27e2f"] = 2;
|
||||||
isch_map[0x182edffbb8ULL] = 3;
|
isch_map["182edffbb8"] = 3;
|
||||||
isch_map[0x18df8a7510ULL] = 4;
|
isch_map["18df8a7510"] = 4;
|
||||||
isch_map[0x18ebb7f087ULL] = 5;
|
isch_map["18ebb7f087"] = 5;
|
||||||
isch_map[0x188741df5eULL] = 6;
|
isch_map["188741df5e"] = 6;
|
||||||
isch_map[0x18b37c5ac9ULL] = 7;
|
isch_map["18b37c5ac9"] = 7;
|
||||||
isch_map[0x1146a44f13ULL] = 8;
|
isch_map["1146a44f13"] = 8;
|
||||||
isch_map[0x117299ca84ULL] = 9;
|
isch_map["117299ca84"] = 9;
|
||||||
isch_map[0x111e6fe55dULL] = 10;
|
isch_map["111e6fe55d"] = 10;
|
||||||
isch_map[0x112a5260caULL] = 11;
|
isch_map["112a5260ca"] = 11;
|
||||||
isch_map[0x11db07ee62ULL] = 12;
|
isch_map["11db07ee62"] = 12;
|
||||||
isch_map[0x11ef3a6bf5ULL] = 13;
|
isch_map["11ef3a6bf5"] = 13;
|
||||||
isch_map[0x1183cc442cULL] = 14;
|
isch_map["1183cc442c"] = 14;
|
||||||
isch_map[0x11b7f1c1bbULL] = 15;
|
isch_map["11b7f1c1bb"] = 15;
|
||||||
isch_map[0x1a4a2e239eULL] = 16;
|
isch_map["1a4a2e239e"] = 16;
|
||||||
isch_map[0x1a7e13a609ULL] = 17;
|
isch_map["1a7e13a609"] = 17;
|
||||||
isch_map[0x1a12e589d0ULL] = 18;
|
isch_map["1a12e589d0"] = 18;
|
||||||
isch_map[0x1a26d80c47ULL] = 19;
|
isch_map["1a26d80c47"] = 19;
|
||||||
isch_map[0x1ad78d82efULL] = 20;
|
isch_map["1ad78d82ef"] = 20;
|
||||||
isch_map[0x1ae3b00778ULL] = 21;
|
isch_map["1ae3b00778"] = 21;
|
||||||
isch_map[0x1a8f4628a1ULL] = 22;
|
isch_map["1a8f4628a1"] = 22;
|
||||||
isch_map[0x1abb7bad36ULL] = 23;
|
isch_map["1abb7bad36"] = 23;
|
||||||
isch_map[0x134ea3b8ecULL] = 24;
|
isch_map["134ea3b8ec"] = 24;
|
||||||
isch_map[0x137a9e3d7bULL] = 25;
|
isch_map["137a9e3d7b"] = 25;
|
||||||
isch_map[0x13166812a2ULL] = 26;
|
isch_map["13166812a2"] = 26;
|
||||||
isch_map[0x1322559735ULL] = 27;
|
isch_map["1322559735"] = 27;
|
||||||
isch_map[0x13d300199dULL] = 28;
|
isch_map["13d300199d"] = 28;
|
||||||
isch_map[0x13e73d9c0aULL] = 29;
|
isch_map["13e73d9c0a"] = 29;
|
||||||
isch_map[0x138bcbb3d3ULL] = 30;
|
isch_map["138bcbb3d3"] = 30;
|
||||||
isch_map[0x13bff63644ULL] = 31;
|
isch_map["13bff63644"] = 31;
|
||||||
isch_map[0x1442f705efULL] = 32;
|
isch_map["1442f705ef"] = 32;
|
||||||
isch_map[0x1476ca8078ULL] = 33;
|
isch_map["1476ca8078"] = 33;
|
||||||
isch_map[0x141a3cafa1ULL] = 34;
|
isch_map["141a3cafa1"] = 34;
|
||||||
isch_map[0x142e012a36ULL] = 35;
|
isch_map["142e012a36"] = 35;
|
||||||
isch_map[0x14df54a49eULL] = 36;
|
isch_map["14df54a49e"] = 36;
|
||||||
isch_map[0x14eb692109ULL] = 37;
|
isch_map["14eb692109"] = 37;
|
||||||
isch_map[0x14879f0ed0ULL] = 38;
|
isch_map["14879f0ed0"] = 38;
|
||||||
isch_map[0x14b3a28b47ULL] = 39;
|
isch_map["14b3a28b47"] = 39;
|
||||||
isch_map[0x1d467a9e9dULL] = 40;
|
isch_map["1d467a9e9d"] = 40;
|
||||||
isch_map[0x1d72471b0aULL] = 41;
|
isch_map["1d72471b0a"] = 41;
|
||||||
isch_map[0x1d1eb134d3ULL] = 42;
|
isch_map["1d1eb134d3"] = 42;
|
||||||
isch_map[0x1d2a8cb144ULL] = 43;
|
isch_map["1d2a8cb144"] = 43;
|
||||||
isch_map[0x1ddbd93fecULL] = 44;
|
isch_map["1ddbd93fec"] = 44;
|
||||||
isch_map[0x1defe4ba7bULL] = 45;
|
isch_map["1defe4ba7b"] = 45;
|
||||||
isch_map[0x1d831295a2ULL] = 46;
|
isch_map["1d831295a2"] = 46;
|
||||||
isch_map[0x1db72f1035ULL] = 47;
|
isch_map["1db72f1035"] = 47;
|
||||||
isch_map[0x164af0f210ULL] = 48;
|
isch_map["164af0f210"] = 48;
|
||||||
isch_map[0x167ecd7787ULL] = 49;
|
isch_map["167ecd7787"] = 49;
|
||||||
isch_map[0x16123b585eULL] = 50;
|
isch_map["16123b585e"] = 50;
|
||||||
isch_map[0x162606ddc9ULL] = 51;
|
isch_map["162606ddc9"] = 51;
|
||||||
isch_map[0x16d7535361ULL] = 52;
|
isch_map["16d7535361"] = 52;
|
||||||
isch_map[0x16e36ed6f6ULL] = 53;
|
isch_map["16e36ed6f6"] = 53;
|
||||||
isch_map[0x168f98f92fULL] = 54;
|
isch_map["168f98f92f"] = 54;
|
||||||
isch_map[0x16bba57cb8ULL] = 55;
|
isch_map["16bba57cb8"] = 55;
|
||||||
isch_map[0x1f4e7d6962ULL] = 56;
|
isch_map["1f4e7d6962"] = 56;
|
||||||
isch_map[0x1f7a40ecf5ULL] = 57;
|
isch_map["1f7a40ecf5"] = 57;
|
||||||
isch_map[0x1f16b6c32cULL] = 58;
|
isch_map["1f16b6c32c"] = 58;
|
||||||
isch_map[0x1f228b46bbULL] = 59;
|
isch_map["1f228b46bb"] = 59;
|
||||||
isch_map[0x1fd3dec813ULL] = 60;
|
isch_map["1fd3dec813"] = 60;
|
||||||
isch_map[0x1fe7e34d84ULL] = 61;
|
isch_map["1fe7e34d84"] = 61;
|
||||||
isch_map[0x1f8b15625dULL] = 62;
|
isch_map["1f8b15625d"] = 62;
|
||||||
isch_map[0x1fbf28e7caULL] = 63;
|
isch_map["1fbf28e7ca"] = 63;
|
||||||
isch_map[0x084d62c339ULL] = 64;
|
isch_map["84d62c339"] = 64;
|
||||||
isch_map[0x08795f46aeULL] = 65;
|
isch_map["8795f46ae"] = 65;
|
||||||
isch_map[0x0815a96977ULL] = 66;
|
isch_map["815a96977"] = 66;
|
||||||
isch_map[0x082194ece0ULL] = 67;
|
isch_map["82194ece0"] = 67;
|
||||||
isch_map[0x08d0c16248ULL] = 68;
|
isch_map["8d0c16248"] = 68;
|
||||||
isch_map[0x08e4fce7dfULL] = 69;
|
isch_map["8e4fce7df"] = 69;
|
||||||
isch_map[0x08880ac806ULL] = 70;
|
isch_map["8880ac806"] = 70;
|
||||||
isch_map[0x08bc374d91ULL] = 71;
|
isch_map["8bc374d91"] = 71;
|
||||||
isch_map[0x0149ef584bULL] = 72;
|
isch_map["149ef584b"] = 72;
|
||||||
isch_map[0x017dd2dddcULL] = 73;
|
isch_map["17dd2dddc"] = 73;
|
||||||
isch_map[0x011124f205ULL] = 74;
|
isch_map["11124f205"] = 74;
|
||||||
isch_map[0x0125197792ULL] = 75;
|
isch_map["125197792"] = 75;
|
||||||
isch_map[0x01d44cf93aULL] = 76;
|
isch_map["1d44cf93a"] = 76;
|
||||||
isch_map[0x01e0717cadULL] = 77;
|
isch_map["1e0717cad"] = 77;
|
||||||
isch_map[0x018c875374ULL] = 78;
|
isch_map["18c875374"] = 78;
|
||||||
isch_map[0x01b8bad6e3ULL] = 79;
|
isch_map["1b8bad6e3"] = 79;
|
||||||
isch_map[0x0a456534c6ULL] = 80;
|
isch_map["a456534c6"] = 80;
|
||||||
isch_map[0x0a7158b151ULL] = 81;
|
isch_map["a7158b151"] = 81;
|
||||||
isch_map[0x0a1dae9e88ULL] = 82;
|
isch_map["a1dae9e88"] = 82;
|
||||||
isch_map[0x0a29931b1fULL] = 83;
|
isch_map["a29931b1f"] = 83;
|
||||||
isch_map[0x0ad8c695b7ULL] = 84;
|
isch_map["ad8c695b7"] = 84;
|
||||||
isch_map[0x0aecfb1020ULL] = 85;
|
isch_map["aecfb1020"] = 85;
|
||||||
isch_map[0x0a800d3ff9ULL] = 86;
|
isch_map["a800d3ff9"] = 86;
|
||||||
isch_map[0x0ab430ba6eULL] = 87;
|
isch_map["ab430ba6e"] = 87;
|
||||||
isch_map[0x0341e8afb4ULL] = 88;
|
isch_map["341e8afb4"] = 88;
|
||||||
isch_map[0x0375d52a23ULL] = 89;
|
isch_map["375d52a23"] = 89;
|
||||||
isch_map[0x03192305faULL] = 90;
|
isch_map["3192305fa"] = 90;
|
||||||
isch_map[0x032d1e806dULL] = 91;
|
isch_map["32d1e806d"] = 91;
|
||||||
isch_map[0x03dc4b0ec5ULL] = 92;
|
isch_map["3dc4b0ec5"] = 92;
|
||||||
isch_map[0x03e8768b52ULL] = 93;
|
isch_map["3e8768b52"] = 93;
|
||||||
isch_map[0x038480a48bULL] = 94;
|
isch_map["38480a48b"] = 94;
|
||||||
isch_map[0x03b0bd211cULL] = 95;
|
isch_map["3b0bd211c"] = 95;
|
||||||
isch_map[0x044dbc12b7ULL] = 96;
|
isch_map["44dbc12b7"] = 96;
|
||||||
isch_map[0x0479819720ULL] = 97;
|
isch_map["479819720"] = 97;
|
||||||
isch_map[0x041577b8f9ULL] = 98;
|
isch_map["41577b8f9"] = 98;
|
||||||
isch_map[0x04214a3d6eULL] = 99;
|
isch_map["4214a3d6e"] = 99;
|
||||||
isch_map[0x04d01fb3c6ULL] = 100;
|
isch_map["4d01fb3c6"] = 100;
|
||||||
isch_map[0x04e4223651ULL] = 101;
|
isch_map["4e4223651"] = 101;
|
||||||
isch_map[0x0488d41988ULL] = 102;
|
isch_map["488d41988"] = 102;
|
||||||
isch_map[0x04bce99c1fULL] = 103;
|
isch_map["4bce99c1f"] = 103;
|
||||||
isch_map[0x0d493189c5ULL] = 104;
|
isch_map["d493189c5"] = 104;
|
||||||
isch_map[0x0d7d0c0c52ULL] = 105;
|
isch_map["d7d0c0c52"] = 105;
|
||||||
isch_map[0x0d11fa238bULL] = 106;
|
isch_map["d11fa238b"] = 106;
|
||||||
isch_map[0x0d25c7a61cULL] = 107;
|
isch_map["d25c7a61c"] = 107;
|
||||||
isch_map[0x0dd49228b4ULL] = 108;
|
isch_map["dd49228b4"] = 108;
|
||||||
isch_map[0x0de0afad23ULL] = 109;
|
isch_map["de0afad23"] = 109;
|
||||||
isch_map[0x0d8c5982faULL] = 110;
|
isch_map["d8c5982fa"] = 110;
|
||||||
isch_map[0x0db864076dULL] = 111;
|
isch_map["db864076d"] = 111;
|
||||||
isch_map[0x0645bbe548ULL] = 112;
|
isch_map["645bbe548"] = 112;
|
||||||
isch_map[0x06718660dfULL] = 113;
|
isch_map["6718660df"] = 113;
|
||||||
isch_map[0x061d704f06ULL] = 114;
|
isch_map["61d704f06"] = 114;
|
||||||
isch_map[0x06294dca91ULL] = 115;
|
isch_map["6294dca91"] = 115;
|
||||||
isch_map[0x06d8184439ULL] = 116;
|
isch_map["6d8184439"] = 116;
|
||||||
isch_map[0x06ec25c1aeULL] = 117;
|
isch_map["6ec25c1ae"] = 117;
|
||||||
isch_map[0x0680d3ee77ULL] = 118;
|
isch_map["680d3ee77"] = 118;
|
||||||
isch_map[0x06b4ee6be0ULL] = 119;
|
isch_map["6b4ee6be0"] = 119;
|
||||||
isch_map[0x0f41367e3aULL] = 120;
|
isch_map["f41367e3a"] = 120;
|
||||||
isch_map[0x0f750bfbadULL] = 121;
|
isch_map["f750bfbad"] = 121;
|
||||||
isch_map[0x0f19fdd474ULL] = 122;
|
isch_map["f19fdd474"] = 122;
|
||||||
isch_map[0x0f2dc051e3ULL] = 123;
|
isch_map["f2dc051e3"] = 123;
|
||||||
isch_map[0x0fdc95df4bULL] = 124;
|
isch_map["fdc95df4b"] = 124;
|
||||||
isch_map[0x0fe8a85adcULL] = 125;
|
isch_map["fe8a85adc"] = 125;
|
||||||
isch_map[0x0f845e7505ULL] = 126;
|
isch_map["f845e7505"] = 126;
|
||||||
isch_map[0x0fb063f092ULL] = 127;
|
isch_map["fb063f092"] = 127;
|
||||||
isch_map[0x575d57f7ffULL] = -2; // S-ISCH
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//I-ISCH Lookup, borrowed from OP25 (now w/ error correction)
|
int isch_lookup (unsigned long long int isch)
|
||||||
int isch_lookup (uint64_t isch)
|
|
||||||
{
|
{
|
||||||
map_isch(); //initialize the lookup map
|
map_isch(); //initialize the lookup map
|
||||||
int decoded = -2;
|
char s[64];
|
||||||
|
int decoded = -2; //initialize lookup to an invalid number
|
||||||
// Must contain bit errors if no exact match, so
|
sprintf(s, "%llx", isch);
|
||||||
// look for codeword with smallest hamming distance
|
decoded = isch_map[s];
|
||||||
if (isch_map.find(isch) == isch_map.end())
|
return(decoded);
|
||||||
{
|
}
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
98
src/fec.c
98
src/fec.c
@@ -760,82 +760,6 @@ bool Hamming_16_11_4_decode(unsigned char *rxBits, unsigned char *decodedBits, i
|
|||||||
|
|
||||||
// ========================================================================================
|
// ========================================================================================
|
||||||
|
|
||||||
void rand_test_20_8() //from dforsi as a pull request to DSDcc
|
|
||||||
{
|
|
||||||
unsigned char msg[8];
|
|
||||||
unsigned char codeword[20], xcodeword[20];
|
|
||||||
int idx1, idx2, idx3 = 0;
|
|
||||||
int dataIn, dataOut; UNUSED(dataIn); //don't know why its reporting dataIn as unused for
|
|
||||||
int passCount = 0, failCount = 0, parityFailCount = 0;
|
|
||||||
|
|
||||||
// Run multiple times, to randomly corrupt different bits
|
|
||||||
// Takes about 10 seconds on a fast PC
|
|
||||||
for (int repeat = 0; repeat < 100000/2; repeat++)
|
|
||||||
{
|
|
||||||
// Exhaustively test all 8-bit inputs
|
|
||||||
for (int dataIn = 0; dataIn < 256; dataIn++)
|
|
||||||
{
|
|
||||||
// Convert to array of bits
|
|
||||||
for (int j = 0; j < 8; j++) {
|
|
||||||
msg[j] = (dataIn >> j) & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode
|
|
||||||
Golay_20_8_encode(msg, codeword);
|
|
||||||
|
|
||||||
// Save copy of uncorrupted codeword
|
|
||||||
memcpy(xcodeword, codeword, 20*sizeof(unsigned char));
|
|
||||||
|
|
||||||
//change the seed each time, using time(NULL) will only change the seed once every second, otherwise resets it to the same seed
|
|
||||||
srand(dataIn+dataOut);
|
|
||||||
|
|
||||||
// Randomly corrupt up to 3 bits
|
|
||||||
idx1 = rand() % 20;
|
|
||||||
idx2 = rand() % 20;
|
|
||||||
idx3 = rand() % 20;
|
|
||||||
codeword[idx1] ^= codeword[idx1];
|
|
||||||
codeword[idx2] ^= codeword[idx2];
|
|
||||||
codeword[idx3] ^= codeword[idx3];
|
|
||||||
|
|
||||||
//flip the parity bit
|
|
||||||
// codeword[19] ^= 1;
|
|
||||||
|
|
||||||
bool fail = false;
|
|
||||||
// Decode and correct errors
|
|
||||||
dataOut = 0;
|
|
||||||
if (Golay_20_8_decode(codeword))
|
|
||||||
{
|
|
||||||
// Check data is corrected
|
|
||||||
for (int j = 0; j < 8; j++) {
|
|
||||||
dataOut |= codeword[j] << j;
|
|
||||||
}
|
|
||||||
if (dataIn != dataOut) {
|
|
||||||
fail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check also that parity has been corrected, as we previously had a bug with this
|
|
||||||
if (memcmp(codeword, xcodeword, 20)) {
|
|
||||||
parityFailCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fail = true;
|
|
||||||
}
|
|
||||||
if (fail)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n Decode Failed: IN:%05X; OUT:%05X; IDX: %d, %d, %d; ", dataIn, dataOut, idx1, idx2, idx3);
|
|
||||||
failCount++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
passCount++;
|
|
||||||
// fprintf (stderr, "\n Decode Passed: IN:%05X; OUT:%05X; IDX: %d, %d, %d; ", dataIn, dataOut, idx1, idx2, idx3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf (stderr, "\n Passcount: %d; Failcount: %d; Parity Fail Count: %d \n", passCount, failCount, parityFailCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Golay_20_8_init()
|
void Golay_20_8_init()
|
||||||
{
|
{
|
||||||
@@ -882,7 +806,7 @@ void Golay_20_8_init()
|
|||||||
syndromeIP = syndromeI ^ (1 << (11-ip));
|
syndromeIP = syndromeI ^ (1 << (11-ip));
|
||||||
Golay_20_8_m_corr[syndromeIP][0] = i1;
|
Golay_20_8_m_corr[syndromeIP][0] = i1;
|
||||||
Golay_20_8_m_corr[syndromeIP][1] = i2;
|
Golay_20_8_m_corr[syndromeIP][1] = i2;
|
||||||
Golay_20_8_m_corr[syndromeIP][2] = 8 + ip;
|
Golay_20_8_m_corr[syndromeIP][2] = 12 + ip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -900,14 +824,14 @@ void Golay_20_8_init()
|
|||||||
{
|
{
|
||||||
syndromeIP1 = syndromeI ^ (1 << (11-ip1));
|
syndromeIP1 = syndromeI ^ (1 << (11-ip1));
|
||||||
Golay_20_8_m_corr[syndromeIP1][0] = i1;
|
Golay_20_8_m_corr[syndromeIP1][0] = i1;
|
||||||
Golay_20_8_m_corr[syndromeIP1][1] = 8 + ip1;
|
Golay_20_8_m_corr[syndromeIP1][1] = 12 + ip1;
|
||||||
|
|
||||||
for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
|
for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
|
||||||
{
|
{
|
||||||
syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
|
syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
|
||||||
Golay_20_8_m_corr[syndromeIP2][0] = i1;
|
Golay_20_8_m_corr[syndromeIP2][0] = i1;
|
||||||
Golay_20_8_m_corr[syndromeIP2][1] = 8 + ip1;
|
Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip1;
|
||||||
Golay_20_8_m_corr[syndromeIP2][2] = 8 + ip2;
|
Golay_20_8_m_corr[syndromeIP2][2] = 12 + ip2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -916,25 +840,23 @@ void Golay_20_8_init()
|
|||||||
for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity
|
for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity
|
||||||
{
|
{
|
||||||
syndromeIP1 = (1 << (11-ip1));
|
syndromeIP1 = (1 << (11-ip1));
|
||||||
Golay_20_8_m_corr[syndromeIP1][0] = 8 + ip1;
|
Golay_20_8_m_corr[syndromeIP1][0] = 12 + ip1;
|
||||||
|
|
||||||
for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
|
for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
|
||||||
{
|
{
|
||||||
syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
|
syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
|
||||||
Golay_20_8_m_corr[syndromeIP2][0] = 8 + ip1;
|
Golay_20_8_m_corr[syndromeIP2][0] = 12 + ip1;
|
||||||
Golay_20_8_m_corr[syndromeIP2][1] = 8 + ip2;
|
Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip2;
|
||||||
|
|
||||||
for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity
|
for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity
|
||||||
{
|
{
|
||||||
syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3));
|
syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3));
|
||||||
Golay_20_8_m_corr[syndromeIP3][0] = 8 + ip1;
|
Golay_20_8_m_corr[syndromeIP3][0] = 12 + ip1;
|
||||||
Golay_20_8_m_corr[syndromeIP3][1] = 8 + ip2;
|
Golay_20_8_m_corr[syndromeIP3][1] = 12 + ip2;
|
||||||
Golay_20_8_m_corr[syndromeIP3][2] = 8 + ip3;
|
Golay_20_8_m_corr[syndromeIP3][2] = 12 + ip3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rand_test_20_8(); //test
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not very efficient but encode is used for unit testing only
|
// Not very efficient but encode is used for unit testing only
|
||||||
|
|||||||
211
src/m17.c
211
src/m17.c
@@ -40,10 +40,9 @@ uint8_t m17_scramble[369] = {
|
|||||||
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
|
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
|
||||||
|
|
||||||
uint8_t p1[62] = {
|
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, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
|
||||||
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
|
||||||
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//from M17_Implementations -- sp5wwp -- should have just looked here to begin with
|
//from M17_Implementations -- sp5wwp -- should have just looked here to begin with
|
||||||
@@ -69,8 +68,9 @@ uint16_t crc16m17(const uint8_t *in, const uint16_t len)
|
|||||||
void M17decodeCSD(dsd_state * state, unsigned long long int dst, unsigned long long int src)
|
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
|
//evaluate dst and src, and determine if they need to be converted to calsign
|
||||||
int i;
|
int i, j;
|
||||||
char c;
|
char c;
|
||||||
|
unsigned long long int value;
|
||||||
|
|
||||||
if (dst == 0xFFFFFFFFFFFF)
|
if (dst == 0xFFFFFFFFFFFF)
|
||||||
fprintf (stderr, " DST: BROADCAST");
|
fprintf (stderr, " DST: BROADCAST");
|
||||||
@@ -136,7 +136,7 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
uint16_t lsf_type = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[96], 16);
|
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
|
//this is the way the manual/code expects you to read these bits
|
||||||
// uint8_t lsf_ps = (lsf_type >> 0) & 0x1;
|
uint8_t lsf_ps = (lsf_type >> 0) & 0x1;
|
||||||
uint8_t lsf_dt = (lsf_type >> 1) & 0x3;
|
uint8_t lsf_dt = (lsf_type >> 1) & 0x3;
|
||||||
uint8_t lsf_et = (lsf_type >> 3) & 0x3;
|
uint8_t lsf_et = (lsf_type >> 3) & 0x3;
|
||||||
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
|
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
|
||||||
@@ -147,16 +147,17 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
state->m17_str_dt = lsf_dt;
|
state->m17_str_dt = lsf_dt;
|
||||||
state->m17_dst = lsf_dst;
|
state->m17_dst = lsf_dst;
|
||||||
state->m17_src = lsf_src;
|
state->m17_src = lsf_src;
|
||||||
state->m17_can = lsf_cn;
|
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
//packet or stream
|
//packet or stream
|
||||||
// if (lsf_ps == 0) fprintf (stderr, " P-");
|
if (lsf_ps == 0) fprintf (stderr, " P-");
|
||||||
// if (lsf_ps == 1) fprintf (stderr, " S-");
|
if (lsf_ps == 1) fprintf (stderr, " S-");
|
||||||
|
|
||||||
fprintf (stderr, " CAN: %d", lsf_cn);
|
fprintf (stderr, " CAN: %d", lsf_cn);
|
||||||
M17decodeCSD(state, lsf_dst, lsf_src);
|
M17decodeCSD(state, lsf_dst, lsf_src);
|
||||||
|
|
||||||
|
if (lsf_et != 0) fprintf (stderr, " ENC");
|
||||||
|
|
||||||
if (lsf_dt == 0) fprintf (stderr, " Reserved");
|
if (lsf_dt == 0) fprintf (stderr, " Reserved");
|
||||||
if (lsf_dt == 1) fprintf (stderr, " Data");
|
if (lsf_dt == 1) fprintf (stderr, " Data");
|
||||||
@@ -165,9 +166,8 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
|
|
||||||
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
|
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
|
||||||
|
|
||||||
if (lsf_et != 0) fprintf (stderr, " ENC:");
|
if (lsf_et == 1) fprintf (stderr, " AES-CTR");
|
||||||
if (lsf_et == 2) fprintf (stderr, " AES-CTR");
|
if (lsf_et == 2) fprintf (stderr, " Scrambler - %d", lsf_es);
|
||||||
if (lsf_et == 1) fprintf (stderr, " Scrambler - %d", lsf_es);
|
|
||||||
|
|
||||||
state->m17_enc = lsf_et;
|
state->m17_enc = lsf_et;
|
||||||
state->m17_enc_st = lsf_es;
|
state->m17_enc_st = lsf_es;
|
||||||
@@ -186,16 +186,16 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
if (lsf_es == 3) fprintf (stderr, " Reserved");
|
if (lsf_es == 3) fprintf (stderr, " Reserved");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lsf_et == 2)
|
if (lsf_et == 1)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " IV: ");
|
fprintf (stderr, " IV: ");
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 14; i++)
|
||||||
fprintf (stderr, "%02X", state->m17_meta[i]);
|
fprintf (stderr, "%02X", state->m17_meta[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits)
|
int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t lich_bits[96])
|
||||||
{
|
{
|
||||||
int i, j, err;
|
int i, j, err;
|
||||||
err = 0;
|
err = 0;
|
||||||
@@ -205,8 +205,9 @@ int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits)
|
|||||||
uint8_t temp[96];
|
uint8_t temp[96];
|
||||||
bool g[4];
|
bool g[4];
|
||||||
|
|
||||||
uint8_t lich_counter = 0;
|
//for testing bit arrangement vs the crc code
|
||||||
uint8_t lich_reserve = 0;
|
uint8_t bs[240];
|
||||||
|
memset(bs, 1, sizeof(bs));
|
||||||
|
|
||||||
uint16_t crc_cmp = 0;
|
uint16_t crc_cmp = 0;
|
||||||
uint16_t crc_ext = 0;
|
uint16_t crc_ext = 0;
|
||||||
@@ -228,12 +229,12 @@ int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits)
|
|||||||
if(g[i] == FALSE) err = -1;
|
if(g[i] == FALSE) err = -1;
|
||||||
|
|
||||||
for (j = 0; j < 12; j++)
|
for (j = 0; j < 12; j++)
|
||||||
lich_decoded[i*12+j] = lich[i][j];
|
lich_decoded[i*12+j] = lich[i][j];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lich_counter = (uint8_t)ConvertBitIntoBytes(&lich_decoded[40], 3); //lich_cnt
|
uint8_t lich_counter = (uint8_t)ConvertBitIntoBytes(&lich_decoded[40], 3); //lich_cunt
|
||||||
lich_reserve = (uint8_t)ConvertBitIntoBytes(&lich_decoded[43], 5); //lich_reserved
|
uint8_t lich_reserve = (uint8_t)ConvertBitIntoBytes(&lich_decoded[43], 5); //lich_reserved
|
||||||
|
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
fprintf (stderr, "LC: %d/6 ", lich_counter+1);
|
fprintf (stderr, "LC: %d/6 ", lich_counter+1);
|
||||||
@@ -291,11 +292,14 @@ int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload)
|
void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[128])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//If payload is the same from the stream in this mode, I suppose we could use this area to parse
|
||||||
|
//or send off the remaining data to be handled or decoded , or just print out the raw data bytes
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
unsigned char voice1[8];
|
unsigned char voice1[8]; //codec2_bytes_per_frame
|
||||||
unsigned char voice2[8];
|
unsigned char voice2[8];
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
@@ -318,61 +322,42 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload
|
|||||||
fprintf (stderr, "%02X", voice1[i]);
|
fprintf (stderr, "%02X", voice1[i]);
|
||||||
fprintf (stderr, " (1600)");
|
fprintf (stderr, " (1600)");
|
||||||
|
|
||||||
fprintf (stderr, "\n A_DATA: "); //arbitrary data
|
fprintf (stderr, "\n LSDATA: "); //low speed data
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
fprintf (stderr, "%02X", voice2[i]);
|
fprintf (stderr, "%02X", voice2[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_CODEC2
|
#ifdef USE_CODEC2
|
||||||
size_t nsam;
|
size_t nsam;
|
||||||
nsam = 320;
|
nsam = 320; //codec2_samples_per_frame(state->codec2_1600);
|
||||||
|
|
||||||
|
short samp1[nsam];
|
||||||
|
// short samp2[nsam];
|
||||||
|
memset (samp1, 0, sizeof(samp1));
|
||||||
|
// memset (samp2, 0, sizeof(samp2));
|
||||||
|
|
||||||
//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);
|
codec2_decode(state->codec2_1600, samp1, voice1);
|
||||||
|
// codec2_decode(state->codec2_1600, samp2, voice2);
|
||||||
|
|
||||||
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
|
|
||||||
|
if (opts->audio_out_type == 0 && state->m17_enc == 0)
|
||||||
{
|
{
|
||||||
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
||||||
}
|
// pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
||||||
|
|
||||||
if (opts->audio_out_type == 0 && state->m17_enc == 0) //UDP Audio
|
|
||||||
{
|
|
||||||
udp_socket_blaster (opts, state, nsam*2, samp1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS 48k/1
|
if (opts->audio_out_type == 5 && state->m17_enc == 0)
|
||||||
{
|
|
||||||
//upsample to 48k and then play
|
|
||||||
prev = samp1[0];
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
{
|
|
||||||
upsampleS (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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT
|
|
||||||
{
|
|
||||||
write (opts->audio_out_fd, samp1, nsam*2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->audio_out_type == 2 && state->m17_enc == 0) //OSS 8k/1
|
|
||||||
{
|
{
|
||||||
write (opts->audio_out_fd, samp1, nsam*2);
|
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
|
//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
|
if(opts->wav_out_f != NULL && state->m17_enc == 0)
|
||||||
{
|
{
|
||||||
sf_write_short(opts->wav_out_f, samp1, nsam);
|
sf_write_short(opts->wav_out_f, samp1, nsam);
|
||||||
|
// sf_write_short(opts->wav_out_f, samp2, nsam);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Codec2 Raw file saving
|
//TODO: Codec2 Raw file saving
|
||||||
@@ -381,18 +366,14 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
free (samp1);
|
|
||||||
free (upsamp);
|
|
||||||
free (out);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload)
|
void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[128])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned char voice1[8];
|
unsigned char voice1[8]; //codec2_bytes_per_frame
|
||||||
unsigned char voice2[8];
|
unsigned char voice2[8];
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
@@ -423,64 +404,32 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload
|
|||||||
|
|
||||||
#ifdef USE_CODEC2
|
#ifdef USE_CODEC2
|
||||||
size_t nsam;
|
size_t nsam;
|
||||||
nsam = 160;
|
nsam = 160; //codec2_samples_per_frame(state->codec2_3200);
|
||||||
|
|
||||||
|
short samp1[nsam];
|
||||||
|
short samp2[nsam];
|
||||||
|
memset (samp1, 0, sizeof(samp1));
|
||||||
|
memset (samp2, 0, sizeof(samp2));
|
||||||
|
|
||||||
//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, samp1, voice1);
|
||||||
codec2_decode(state->codec2_3200, samp2, voice2);
|
codec2_decode(state->codec2_3200, samp2, voice2);
|
||||||
|
|
||||||
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
|
|
||||||
|
if (opts->audio_out_type == 0 && state->m17_enc == 0)
|
||||||
{
|
{
|
||||||
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
||||||
pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->audio_out_type == 0 && state->m17_enc == 0) //UDP Audio
|
|
||||||
{
|
|
||||||
udp_socket_blaster (opts, state, nsam*2, samp1);
|
|
||||||
udp_socket_blaster (opts, state, nsam*2, samp2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS 48k/1
|
if (opts->audio_out_type == 5 && state->m17_enc == 0)
|
||||||
{
|
|
||||||
//upsample to 48k and then play
|
|
||||||
prev = samp1[0];
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
{
|
|
||||||
upsampleS (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++)
|
|
||||||
{
|
|
||||||
upsampleS (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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->audio_out_type == 2 && state->m17_enc == 0) //OSS 8k/1
|
|
||||||
{
|
{
|
||||||
write (opts->audio_out_fd, samp1, nsam*2);
|
write (opts->audio_out_fd, samp1, nsam*2);
|
||||||
write (opts->audio_out_fd, samp2, 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
|
//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
|
if(opts->wav_out_f != NULL && state->m17_enc == 0)
|
||||||
{
|
{
|
||||||
sf_write_short(opts->wav_out_f, samp1, nsam);
|
sf_write_short(opts->wav_out_f, samp1, nsam);
|
||||||
sf_write_short(opts->wav_out_f, samp2, nsam);
|
sf_write_short(opts->wav_out_f, samp2, nsam);
|
||||||
@@ -492,26 +441,21 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
free (samp1);
|
|
||||||
free (samp2);
|
|
||||||
free (upsamp);
|
|
||||||
free (out);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t * m17_bits)
|
void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t m17_bits[368])
|
||||||
{
|
{
|
||||||
|
|
||||||
int i, k, x;
|
int i, j, k, x;
|
||||||
uint8_t m17_punc[275]; //25 * 11 = 275
|
uint8_t m17_punc[310]; //25 * 11 = 275
|
||||||
memset (m17_punc, 0, sizeof(m17_punc));
|
memset (m17_punc, 0, sizeof(m17_punc));
|
||||||
for (i = 0; i < 272; i++)
|
for (i = 0; i < 272; i++)
|
||||||
m17_punc[i] = m17_bits[i+96];
|
m17_punc[i] = m17_bits[i+96];
|
||||||
|
|
||||||
//depuncture the bits
|
//depuncture the bits
|
||||||
uint8_t m17_depunc[300]; //25 * 12 = 300
|
uint8_t m17_depunc[310]; //25 * 12 = 300
|
||||||
memset (m17_depunc, 0, sizeof(m17_depunc));
|
memset (m17_depunc, 0, sizeof(m17_depunc));
|
||||||
k = 0; x = 0;
|
k = 0; x = 0;
|
||||||
for (i = 0; i < 25; i++)
|
for (i = 0; i < 25; i++)
|
||||||
@@ -535,7 +479,7 @@ void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t * m17_bits)
|
|||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[28];
|
uint8_t m_data[28];
|
||||||
uint8_t trellis_buf[144];
|
uint8_t trellis_buf[400];
|
||||||
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));
|
||||||
@@ -576,10 +520,6 @@ void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t * m17_bits)
|
|||||||
end = trellis_buf[0];
|
end = trellis_buf[0];
|
||||||
fn = (uint16_t)ConvertBitIntoBytes(&trellis_buf[1], 15);
|
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)
|
if (opts->payload == 1)
|
||||||
fprintf (stderr, " FSN: %05d", fn);
|
fprintf (stderr, " FSN: %05d", fn);
|
||||||
|
|
||||||
@@ -610,7 +550,13 @@ void processM17STR(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
|
|
||||||
int i, x;
|
int i, x;
|
||||||
//overflow/memory issue returns in Cygwin for...reasons...
|
|
||||||
|
//NOTE: adding more space for dbuf seems to fix the memory issue, but I don't think this is
|
||||||
|
//the culprit, not entirely sure what is going on here, but the issue with Cygwin (32-bit)
|
||||||
|
//not working at all with this also is fixed by this and I can't seem to figure out why
|
||||||
|
//its probably something really dumb that I am completely blind on seeing here for some reason
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
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_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_int_bits[368]; //368 bits that are still interleaved
|
||||||
@@ -666,15 +612,18 @@ void processM17STR(dsd_opts * opts, dsd_state * state)
|
|||||||
void processM17LSF(dsd_opts * opts, dsd_state * state)
|
void processM17LSF(dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
//NOTE: Have not been able to get this to work successfully, but considering
|
//NOTE1: Pretty sure the flow here is all correct, but the initial (and only)
|
||||||
//there is only one LSF frame at the beginning of TX, its probably just as easy to
|
//LSF frame is demodulated incorrectly, so more than likely, this frame will
|
||||||
//use and rely on the STR frame and embedded LSF chunk, which does work properly
|
//always be bad since there is only one sent before STR
|
||||||
|
|
||||||
|
//NOTE2: Even with the preamble detection and LSF sync, we still get bad decode on this
|
||||||
|
|
||||||
int i, j, k, x;
|
int i, j, k, x;
|
||||||
uint8_t dbuf[184]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
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_rnd_bits[500]; //368 bits that are still scrambled (randomized)
|
||||||
uint8_t m17_int_bits[368]; //368 bits that are still interleaved
|
uint8_t m17_int_bits[500]; //368 bits that are still interleaved
|
||||||
uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble
|
uint8_t m17_bits[500]; //368 bits that have been de-interleaved and de-scramble
|
||||||
uint8_t m17_depunc[488]; //488 bits after depuncturing
|
uint8_t m17_depunc[500]; //488 bits after depuncturing
|
||||||
|
|
||||||
memset (dbuf, 0, sizeof(dbuf));
|
memset (dbuf, 0, sizeof(dbuf));
|
||||||
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
|
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
|
||||||
@@ -711,7 +660,7 @@ void processM17LSF(dsd_opts * opts, dsd_state * state)
|
|||||||
for (i = 0; i < 488; i++)
|
for (i = 0; i < 488; i++)
|
||||||
{
|
{
|
||||||
if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++];
|
if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++];
|
||||||
else m17_depunc[x++] = 0;
|
else m17_depunc[x++] = 1;
|
||||||
|
|
||||||
if (k == 61) k = 0; //61 -- should reset 8 times againt the array
|
if (k == 61) k = 0; //61 -- should reset 8 times againt the array
|
||||||
|
|
||||||
@@ -721,11 +670,11 @@ void processM17LSF(dsd_opts * opts, dsd_state * state)
|
|||||||
// fprintf (stderr, "K = %d; J = %d; X = %d", k, j, x);
|
// fprintf (stderr, "K = %d; J = %d; X = %d", k, j, x);
|
||||||
|
|
||||||
//setup the convolutional decoder
|
//setup the convolutional decoder
|
||||||
uint8_t temp[488];
|
uint8_t temp[500];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[30];
|
uint8_t m_data[32];
|
||||||
uint8_t trellis_buf[240]; //30*8 = 240
|
uint8_t trellis_buf[400];
|
||||||
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));
|
||||||
|
|||||||
@@ -45,16 +45,17 @@ static const uint8_t CNXDNConvolution_BRANCH_TABLE1[8] = {0U, 0U, 0U, 0U, 2U, 2U
|
|||||||
static const uint8_t CNXDNConvolution_BRANCH_TABLE2[8] = {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 uint32_t CNXDNConvolution_M = 4U;
|
static const uint32_t CNXDNConvolution_M = 4U;
|
||||||
static const unsigned int CNXDNConvolution_K = 5U;
|
static const unsigned int CNXDNConvolution_K = 5U;
|
||||||
|
|
||||||
//NOTE:
|
//NOTE:
|
||||||
uint16_t m_metrics1[16];
|
static uint16_t m_metrics1[16U];
|
||||||
uint16_t m_metrics2[16];
|
static uint16_t m_metrics2[16U];
|
||||||
uint64_t m_decisions[8*300];
|
static uint64_t m_decisions[300U]; //300
|
||||||
uint16_t * m_oldMetrics = NULL;
|
static uint16_t * m_oldMetrics = NULL;
|
||||||
uint16_t * m_newMetrics = NULL;
|
static uint16_t * m_newMetrics = NULL;
|
||||||
uint64_t * m_dp = NULL;
|
static uint64_t * m_dp = NULL;
|
||||||
|
|
||||||
/* Functions ----------------------------------------------------------------*/
|
/* Functions ----------------------------------------------------------------*/
|
||||||
|
|
||||||
@@ -162,12 +163,10 @@ void CNXDNConvolution_start(void)
|
|||||||
m_newMetrics = m_metrics2;
|
m_newMetrics = m_metrics2;
|
||||||
m_dp = m_decisions;
|
m_dp = m_decisions;
|
||||||
|
|
||||||
}
|
memset(m_metrics1, 0x00U, sizeof(m_metrics1));
|
||||||
|
memset(m_metrics2, 0x00U, sizeof(m_metrics2));
|
||||||
void CNXDNConvolution_init()
|
memset(m_decisions, 0x00U, sizeof(m_decisions));
|
||||||
{
|
|
||||||
memset(m_metrics1, 0xFF, 16*sizeof(uint16_t));
|
for (int x = 0; x < 4; x++) CNXDNConvolution_decode(0U, 0U);
|
||||||
memset(m_metrics2, 0xFF, 16*sizeof(uint16_t));
|
|
||||||
// memset(m_decisions,0xFF, 8*300*sizeof(uint64_t));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ 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[144]; //144
|
uint8_t deperm[200]; //144
|
||||||
uint8_t depunc[192]; //192
|
uint8_t depunc[200]; //192
|
||||||
uint8_t trellis_buf[96]; //96
|
uint8_t trellis_buf[400]; //96
|
||||||
uint16_t crc = 1; //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;
|
||||||
|
|
||||||
@@ -70,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[200];
|
uint8_t temp[210];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[20]; //13
|
uint8_t m_data[20]; //13
|
||||||
@@ -79,10 +79,17 @@ 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 = 0; i < 96; i++)
|
for (int i = 0U; i < 100U; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -90,7 +97,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, 92);
|
CNXDNConvolution_chainback(m_data, 96U);
|
||||||
|
|
||||||
for(int i = 0; i < 12; i++)
|
for(int i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
@@ -111,32 +118,8 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
|||||||
check = check | trellis_buf[84+i]; //80
|
check = check | trellis_buf[84+i]; //80
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug
|
|
||||||
// if (crc == check)
|
|
||||||
// fprintf (stderr, " Pass 1 ");
|
|
||||||
|
|
||||||
//if the crc fails, attempt again with the other trellis decoder
|
|
||||||
if (crc != check)
|
|
||||||
{
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " Pass 2 ");
|
|
||||||
crc = 1; check = 0;
|
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
||||||
memset (m_data, 0, sizeof(m_data));
|
|
||||||
trellis_decode(trellis_buf, depunc, 92);
|
|
||||||
//fill m_data bytes with trellis_buf
|
|
||||||
for(int i = 0; i < 12; i++)
|
|
||||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
|
||||||
crc = crc12f (trellis_buf, 84);
|
|
||||||
for (int i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
check = check << 1;
|
|
||||||
check = check | trellis_buf[i+84];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -160,16 +143,16 @@ 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[60]; //60
|
uint8_t deperm[200]; //60
|
||||||
uint8_t depunc[72]; //72
|
uint8_t depunc[200]; //72
|
||||||
uint8_t trellis_buf[32]; //32
|
uint8_t trellis_buf[400]; //32
|
||||||
|
|
||||||
memset (deperm, 0, sizeof(deperm));
|
memset (deperm, 0, sizeof(deperm));
|
||||||
memset (depunc, 0, sizeof(depunc));
|
memset (depunc, 0, sizeof(depunc));
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
|
|
||||||
int o = 0;
|
int o = 0;
|
||||||
uint8_t crc = 1; //value computed by crc6 on payload
|
uint8_t crc = 0; //value computed by crc6 on payload
|
||||||
uint8_t check = 0; //value pulled from last 6 bits
|
uint8_t check = 0; //value pulled from last 6 bits
|
||||||
int sf = 0;
|
int sf = 0;
|
||||||
int ran = 0;
|
int ran = 0;
|
||||||
@@ -193,20 +176,27 @@ 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[80];
|
uint8_t temp[90];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[5]; //5
|
uint8_t m_data[10]; //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 = 0; i < 36; i++)
|
for (int i = 0U; i < 36U; i++) //40
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -215,7 +205,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, 32);
|
CNXDNConvolution_chainback(m_data, 32U); //36
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++)
|
for(int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
@@ -236,37 +226,13 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
|||||||
check = check | trellis_buf[i+26];
|
check = check | trellis_buf[i+26];
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug
|
|
||||||
// if (crc == check)
|
|
||||||
// fprintf (stderr, " Pass 1 ");
|
|
||||||
|
|
||||||
//if the crc fails, attempt again with the other trellis decoder
|
|
||||||
if (crc != check)
|
|
||||||
{
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " Pass 2 ");
|
|
||||||
crc = 1; check = 0;
|
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
||||||
memset (m_data, 0, sizeof(m_data));
|
|
||||||
trellis_decode(trellis_buf, depunc, 32);
|
|
||||||
//fill m_data bytes with trellis_buf
|
|
||||||
for(int i = 0; i < 4; i++)
|
|
||||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
|
||||||
crc = crc6(trellis_buf, 26); //32
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
check = check << 1;
|
|
||||||
check = check | trellis_buf[i+26];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//FIRST! If part of a non_superframe, and CRC is good, send directly to NXDN_Elements_Content_decode
|
//FIRST! If part of a non_superframe, and CRC is good, send directly to NXDN_Elements_Content_decode
|
||||||
if (state->nxdn_sacch_non_superframe == TRUE)
|
if (state->nxdn_sacch_non_superframe == TRUE)
|
||||||
{
|
{
|
||||||
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[26];
|
uint8_t nsf_sacch[400];
|
||||||
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++)
|
||||||
{
|
{
|
||||||
@@ -332,12 +298,12 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
|||||||
|
|
||||||
fprintf (stderr, "PF %d/4", part_of_frame+1);
|
fprintf (stderr, "PF %d/4", part_of_frame+1);
|
||||||
|
|
||||||
// if (crc != check)
|
if (crc != check)
|
||||||
// {
|
{
|
||||||
// fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
// fprintf (stderr, " (CRC ERR)");
|
fprintf (stderr, " (CRC ERR)");
|
||||||
// fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
// }
|
}
|
||||||
|
|
||||||
//reset scrambler seed to key value on new superframe
|
//reset scrambler seed to key value on new superframe
|
||||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
||||||
@@ -367,16 +333,16 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
|||||||
NXDN_SACCH_Full_decode (opts, state);
|
NXDN_SACCH_Full_decode (opts, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->payload == 1)
|
// if (opts->payload == 1)
|
||||||
{
|
// {
|
||||||
fprintf (stderr, "\n");
|
// fprintf (stderr, "\n");
|
||||||
fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
|
// fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
|
||||||
for (int i = 0; i < 4; i++)
|
// for (int i = 0; i < 4; i++)
|
||||||
{
|
// {
|
||||||
fprintf (stderr, "[%02X]", m_data[i]);
|
// fprintf (stderr, "[%02X]", m_data[i]);
|
||||||
}
|
// }
|
||||||
if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
|
// // if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,9 +350,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[348]; //348
|
uint8_t deperm[500]; //348
|
||||||
uint8_t depunc[406]; //406
|
uint8_t depunc[500]; //406
|
||||||
uint8_t trellis_buf[208]; //199
|
uint8_t trellis_buf[400]; //199
|
||||||
int id = 0;
|
int id = 0;
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
uint16_t check = 0;
|
uint16_t check = 0;
|
||||||
@@ -415,19 +381,26 @@ 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[406];
|
uint8_t temp[500]; //220, this one was way too small
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[26]; //26
|
uint8_t m_data[52]; //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 = 0; i < 203; i++)
|
for (int i = 0U; i < 207U; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -436,7 +409,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, 199);
|
CNXDNConvolution_chainback(m_data, 203U);
|
||||||
|
|
||||||
for(int i = 0; i < 26; i++)
|
for(int i = 0; i < 26; i++)
|
||||||
{
|
{
|
||||||
@@ -457,30 +430,6 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
check = check | trellis_buf[i+184];
|
check = check | trellis_buf[i+184];
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug
|
|
||||||
// if (crc == check)
|
|
||||||
// fprintf (stderr, " Pass 1 ");
|
|
||||||
|
|
||||||
//if the crc fails, attempt again with the other trellis decoder
|
|
||||||
if (crc != check)
|
|
||||||
{
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " Pass 2 ");
|
|
||||||
crc = 1; check = 0;
|
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
||||||
memset (m_data, 0, sizeof(m_data));
|
|
||||||
trellis_decode(trellis_buf, depunc, 199);
|
|
||||||
//fill m_data bytes with trellis_buf
|
|
||||||
for(int i = 0; i < 26; i++)
|
|
||||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
|
||||||
crc = crc15(trellis_buf, 199);
|
|
||||||
for (int i = 0; i < 15; i++)
|
|
||||||
{
|
|
||||||
check = check << 1;
|
|
||||||
check = check | trellis_buf[i+184];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
if (type == 0) fprintf (stderr, " UDCH");
|
if (type == 0) fprintf (stderr, " UDCH");
|
||||||
if (type == 1) fprintf (stderr, " FACCH2");
|
if (type == 1) fprintf (stderr, " FACCH2");
|
||||||
@@ -491,7 +440,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-15; i++)
|
for (int i = 0; i < 199-8; i++)
|
||||||
{
|
{
|
||||||
f2u_message_buffer[i] = trellis_buf[i+8];
|
f2u_message_buffer[i] = trellis_buf[i+8];
|
||||||
}
|
}
|
||||||
@@ -499,38 +448,13 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
if (crc == check)
|
if (crc == check)
|
||||||
{
|
{
|
||||||
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 == 0) {} //need handling for user data (text messages and AVL)
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (type == 0 && crc == check)
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n UDCH Data: " );
|
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
|
||||||
for (int i = 0; i < 24; i++) //all but last crc portion
|
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||||
fprintf (stderr, "%02X", m_data[i]);
|
}
|
||||||
|
|
||||||
fprintf (stderr, "\n UDCH Data: ASCII - " );
|
|
||||||
for (int i = 0; i < 24; i++) //remove crc portion
|
|
||||||
{
|
|
||||||
if (m_data[i] <= 0x7E && m_data[i] >=0x20)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%c", m_data[i]);
|
|
||||||
}
|
|
||||||
else fprintf (stderr, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crc != check)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s", KRED);
|
|
||||||
fprintf (stderr, " (CRC ERR)");
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
@@ -553,27 +477,27 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
|
|
||||||
// if (crc != check) fprintf (stderr, " CRC ERR ");
|
// if (crc != check) fprintf (stderr, " CRC ERR ");
|
||||||
|
|
||||||
// if (type == 0)
|
if (type == 0)
|
||||||
// {
|
{
|
||||||
// fprintf (stderr, "\n UDCH Data: ASCII - " );
|
fprintf (stderr, "\n UDCH Data: ASCII - " );
|
||||||
// for (int i = 0; i < 24; i++) //remove crc portion
|
for (int i = 0; i < 24; i++) //remove crc portion
|
||||||
// {
|
{
|
||||||
// if (m_data[i] <= 0x7E && m_data[i] >=0x20)
|
if (m_data[i] <= 0x7E && m_data[i] >=0x20)
|
||||||
// {
|
{
|
||||||
// fprintf (stderr, "%c", m_data[i]);
|
fprintf (stderr, "%c", m_data[i]);
|
||||||
// }
|
}
|
||||||
// else fprintf (stderr, " ");
|
else fprintf (stderr, " ");
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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[300]; //300
|
uint8_t deperm[500]; //300
|
||||||
uint8_t depunc[350]; //350
|
uint8_t depunc[500]; //350
|
||||||
uint8_t trellis_buf[176]; //176
|
uint8_t trellis_buf[400]; //171
|
||||||
int id = 0;
|
int id = 0;
|
||||||
int ran = 0;
|
int ran = 0;
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
@@ -602,19 +526,21 @@ 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[179];
|
uint8_t temp[360];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[22]; //26
|
uint8_t m_data[52]; //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 = 0; i < 175; i++) //179
|
for (int i = 0U; i < 179U; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -622,7 +548,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, 171); //175
|
CNXDNConvolution_chainback(m_data, 175U);
|
||||||
|
|
||||||
for(int i = 0; i < 22; i++)
|
for(int i = 0; i < 22; i++)
|
||||||
{
|
{
|
||||||
@@ -638,28 +564,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);
|
||||||
|
|
||||||
//debug
|
uint8_t cac_message_buffer[400]; //171
|
||||||
// if (crc == 0)
|
|
||||||
// fprintf (stderr, " Pass 1 ");
|
|
||||||
|
|
||||||
if (crc != 0)
|
|
||||||
{
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " Pass 2 ");
|
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
||||||
memset (m_data, 0, sizeof(m_data));
|
|
||||||
trellis_decode(trellis_buf, depunc, 171);
|
|
||||||
//fill m_data bytes with trellis_buf
|
|
||||||
for(int i = 0; i < 22; i++)
|
|
||||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
|
||||||
crc = crc16cac(trellis_buf, 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 and ending crc
|
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field
|
||||||
for (int i = 0; i < 147; i++)
|
for (int i = 0; i < 160; i++)
|
||||||
{
|
{
|
||||||
cac_message_buffer[i] = trellis_buf[i+8];
|
cac_message_buffer[i] = trellis_buf[i+8];
|
||||||
}
|
}
|
||||||
@@ -685,7 +594,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)
|
||||||
{
|
{
|
||||||
@@ -709,9 +618,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[60]; //60
|
uint8_t deperm[200]; //60
|
||||||
uint8_t depunc[72]; //72
|
uint8_t depunc[200]; //72
|
||||||
uint8_t trellis_buf[32]; //32
|
uint8_t trellis_buf[400]; //32
|
||||||
|
|
||||||
memset (deperm, 0, sizeof(deperm));
|
memset (deperm, 0, sizeof(deperm));
|
||||||
memset (depunc, 0, sizeof(depunc));
|
memset (depunc, 0, sizeof(depunc));
|
||||||
@@ -741,20 +650,27 @@ 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[72];
|
uint8_t temp[90];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[5]; //5
|
uint8_t m_data[10]; //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 = 0; i < 36; i++)
|
for (int i = 0U; i < 36U; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -762,7 +678,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, 32);
|
CNXDNConvolution_chainback(m_data, 32U);
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++)
|
for(int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
@@ -783,30 +699,6 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
|||||||
check = check | trellis_buf[i+25];
|
check = check | trellis_buf[i+25];
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug
|
|
||||||
// if (crc == check)
|
|
||||||
// fprintf (stderr, " Pass 1 ");
|
|
||||||
|
|
||||||
//if the crc fails, attempt again with the other trellis decoder
|
|
||||||
if (crc != check)
|
|
||||||
{
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " Pass 2 ");
|
|
||||||
crc = 1; check = 0;
|
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
||||||
memset (m_data, 0, sizeof(m_data));
|
|
||||||
trellis_decode(trellis_buf, depunc, 32); //32?
|
|
||||||
//fill m_data bytes with trellis_buf
|
|
||||||
for(int i = 0; i < 4; i++)
|
|
||||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
|
||||||
crc = crc7_scch(trellis_buf, 25);
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
check = check << 1;
|
|
||||||
check = check | trellis_buf[i+25];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//check the sf early for scrambler reset, if required
|
//check the sf early for scrambler reset, if required
|
||||||
sf = (trellis_buf[0] << 1) | trellis_buf[1];
|
sf = (trellis_buf[0] << 1) | trellis_buf[1];
|
||||||
if (sf == 3) part_of_frame = 0;
|
if (sf == 3) part_of_frame = 0;
|
||||||
@@ -839,7 +731,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);
|
||||||
|
|
||||||
@@ -865,9 +757,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[144]; //144
|
uint8_t deperm[300]; //144
|
||||||
uint8_t depunc[192]; //192
|
uint8_t depunc[300]; //192
|
||||||
uint8_t trellis_buf[96]; //96
|
uint8_t trellis_buf[600]; //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
|
||||||
@@ -875,10 +767,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[192];
|
uint8_t temp[500];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[12]; //13
|
uint8_t m_data[40]; //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));
|
||||||
@@ -902,10 +794,17 @@ 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 = 0; i < 96; i++)
|
for (int i = 0U; i < 100U; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -913,7 +812,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, 92);
|
CNXDNConvolution_chainback(m_data, 96U);
|
||||||
|
|
||||||
for(int i = 0; i < 12; i++)
|
for(int i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
@@ -934,31 +833,6 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
check[j] = check[j] | trellis_buf[84+i]; //84
|
check[j] = check[j] | trellis_buf[84+i]; //84
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//debug
|
|
||||||
// if (crc[j] == check[j])
|
|
||||||
// fprintf (stderr, "P:%d Pass 1 ", j);
|
|
||||||
|
|
||||||
//if the crc fails, attempt again with the other trellis decoder
|
|
||||||
if (crc[j] != check[j])
|
|
||||||
{
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, "P:%d Pass 2 ", j);
|
|
||||||
crc[j] = 1; check[j] = 0;
|
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
|
||||||
memset (m_data, 0, sizeof(m_data));
|
|
||||||
trellis_decode(trellis_buf, depunc, 92);
|
|
||||||
//fill m_data bytes with trellis_buf
|
|
||||||
for(int i = 0; i < 12; i++)
|
|
||||||
m_data[i] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8);
|
|
||||||
crc[j] = crc12f (trellis_buf, 84);
|
|
||||||
for (int i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
check[j] = check[j] << 1;
|
|
||||||
check[j] = check[j] | trellis_buf[i+84];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//transfer to storage sans crc and tail bits
|
//transfer to storage sans crc and tail bits
|
||||||
for (int i = 0; i < 80; i++) f3_udch2[i+(j*80)] = trellis_buf[i];
|
for (int i = 0; i < 80; i++) f3_udch2[i+(j*80)] = trellis_buf[i];
|
||||||
for (int i = 0; i < 12; i++) f3_udch2_bytes[i+(j*12)] = m_data[i];
|
for (int i = 0; i < 12; i++) f3_udch2_bytes[i+(j*12)] = m_data[i];
|
||||||
@@ -973,44 +847,12 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
if (crc[0] == check[0] && crc[1] == check[1])
|
if (crc[0] == check[0] && crc[1] == check[1])
|
||||||
{
|
{
|
||||||
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 == 0) {} //need handling for user data (text messages and AVL)
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (type == 0)
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n UDCH2 Data: " );
|
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||||
for (int i = 0; i < 22; i++) //all but last crc portion
|
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||||
{
|
|
||||||
if (i == 10)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " "); //space seperator?
|
|
||||||
i = 12; //skip first crc portion
|
|
||||||
}
|
|
||||||
fprintf (stderr, "%02X", f3_udch2_bytes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "\n UDCH2 Data: ASCII - " );
|
|
||||||
for (int i = 0; i < 22; i++) //all but last crc portion
|
|
||||||
{
|
|
||||||
if (i == 10) i = 12; //skip first crc portion
|
|
||||||
if (f3_udch2_bytes[i] <= 0x7E && f3_udch2_bytes[i] >=0x20)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%c", f3_udch2_bytes[i]);
|
|
||||||
}
|
|
||||||
else fprintf (stderr, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crc[0] != check[0] && crc[1] != check[1])
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s", KRED);
|
|
||||||
fprintf (stderr, " (CRC ERR)");
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
@@ -1036,19 +878,19 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
// fprintf (stderr, " - %03X %03X", check[1], crc[1]);
|
// fprintf (stderr, " - %03X %03X", check[1], crc[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (type == 0)
|
if (type == 0)
|
||||||
// {
|
{
|
||||||
// fprintf (stderr, "\n UDCH2 Data: ASCII - " );
|
fprintf (stderr, "\n UDCH2 Data: ASCII - " );
|
||||||
// for (int i = 0; i < 22; i++) //all but last crc portion
|
for (int i = 0; i < 22; i++) //all but last crc portion
|
||||||
// {
|
{
|
||||||
// if (i == 12) i = 14; //skip first crc portion
|
if (i == 12) i = 14; //skip first crc portion
|
||||||
// if (f3_udch2_bytes[i] <= 0x7E && f3_udch2_bytes[i] >=0x20)
|
if (f3_udch2_bytes[i] <= 0x7E && f3_udch2_bytes[i] >=0x20)
|
||||||
// {
|
{
|
||||||
// fprintf (stderr, "%c", f3_udch2_bytes[i]);
|
fprintf (stderr, "%c", f3_udch2_bytes[i]);
|
||||||
// }
|
}
|
||||||
// else fprintf (stderr, " ");
|
else fprintf (stderr, " ");
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1056,7 +898,6 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
|
|
||||||
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
|
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
//NOTE: Most Req/Resp (request and respone) share same message type but differ depending on channel type
|
//NOTE: Most Req/Resp (request and respone) share same message type but differ depending on channel type
|
||||||
//RTCH Outbound will take precedent when differences may occur (except CALL_ASSGN)
|
//RTCH Outbound will take precedent when differences may occur (except CALL_ASSGN)
|
||||||
@@ -1108,13 +949,6 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
|
|||||||
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));
|
||||||
sprintf (state->nxdn_call_type, "%s", "");
|
sprintf (state->nxdn_call_type, "%s", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MessageType == 0x07 ||MessageType == 0x08 || MessageType == 0x11)
|
|
||||||
{
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1139,7 +973,7 @@ void LFSRN(char * BufferIn, char * BufferOut, dsd_state * state)
|
|||||||
state->payload_miN = lfsr & 0x7FFF;
|
state->payload_miN = lfsr & 0x7FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_i(const uint8_t val[], int len) {
|
static inline int load_i(const uint8_t val[], int len) {
|
||||||
int acc = 0;
|
int acc = 0;
|
||||||
for (int i=0; i<len; i++){
|
for (int i=0; i<len; i++){
|
||||||
acc = (acc << 1) + (val[i] & 1);
|
acc = (acc << 1) + (val[i] & 1);
|
||||||
@@ -1147,7 +981,7 @@ int load_i(const uint8_t val[], int len) {
|
|||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t crc6(const uint8_t buf[], int len)
|
static uint8_t crc6(const uint8_t buf[], int len)
|
||||||
{
|
{
|
||||||
uint8_t s[6];
|
uint8_t s[6];
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
@@ -1165,7 +999,7 @@ uint8_t crc6(const uint8_t buf[], int len)
|
|||||||
return load_i(s, 6);
|
return load_i(s, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t crc12f(const uint8_t buf[], int len)
|
static uint16_t crc12f(const uint8_t buf[], int len)
|
||||||
{
|
{
|
||||||
uint8_t s[12];
|
uint8_t s[12];
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
@@ -1189,7 +1023,7 @@ uint16_t crc12f(const uint8_t buf[], int len)
|
|||||||
return load_i(s, 12);
|
return load_i(s, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t crc15(const uint8_t buf[], int len)
|
static uint16_t crc15(const uint8_t buf[], int len)
|
||||||
{
|
{
|
||||||
uint8_t s[15];
|
uint8_t s[15];
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
@@ -1216,7 +1050,7 @@ uint16_t crc15(const uint8_t buf[], int len)
|
|||||||
return load_i(s, 15);
|
return load_i(s, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t crc16cac(const uint8_t buf[], int len)
|
static uint16_t crc16cac(const uint8_t buf[], int len)
|
||||||
{
|
{
|
||||||
uint32_t crc = 0xc3ee; //not sure why this though
|
uint32_t crc = 0xc3ee; //not sure why this though
|
||||||
uint32_t poly = (1<<12) + (1<<5) + 1; //poly is fine
|
uint32_t poly = (1<<12) + (1<<5) + 1; //poly is fine
|
||||||
@@ -1229,7 +1063,7 @@ uint16_t crc16cac(const uint8_t buf[], int len)
|
|||||||
return crc & 0xffff;
|
return crc & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t crc7_scch(uint8_t bits[], int len)
|
static uint8_t crc7_scch(uint8_t bits[], int len)
|
||||||
{
|
{
|
||||||
uint8_t s[7];
|
uint8_t s[7];
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
|
|||||||
@@ -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[72]; //72
|
uint8_t SACCH[400]; //72
|
||||||
uint8_t sacch_bytes[9];
|
uint8_t sacch_bytes[10];
|
||||||
|
|
||||||
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));
|
||||||
@@ -62,7 +62,10 @@ void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
|
|||||||
void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||||
uint8_t CrcCorrect, uint8_t * ElementsContent)
|
uint8_t CrcCorrect, uint8_t * ElementsContent)
|
||||||
{
|
{
|
||||||
|
uint32_t i;
|
||||||
uint8_t MessageType;
|
uint8_t MessageType;
|
||||||
|
uint64_t CurrentIV = 0;
|
||||||
|
unsigned long long int FullMessage = 0;
|
||||||
/* Get the "Message Type" field */
|
/* Get the "Message Type" field */
|
||||||
MessageType = (ElementsContent[2] & 1) << 5;
|
MessageType = (ElementsContent[2] & 1) << 5;
|
||||||
MessageType |= (ElementsContent[3] & 1) << 4;
|
MessageType |= (ElementsContent[3] & 1) << 4;
|
||||||
@@ -86,15 +89,6 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
|||||||
/* Decode the right "Message Type" */
|
/* Decode the right "Message Type" */
|
||||||
switch(MessageType)
|
switch(MessageType)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
|
||||||
//Note: CAC Message with same Message Type -- This is a private call request and rejection (TODO: Seperate handling depending on CAC, FACCH< Sacch, etc)
|
|
||||||
20:56:15 Sync: NXDN96 RCCH Data RAN 01 CAC VCALL (VCALL_REQ)
|
|
||||||
Private Call - Half Duplex 9600bps/EHR (02) - Src=211 - Dst/TG=1603
|
|
||||||
20:56:15 Sync: NXDN96 RCCH Data RAN 01 CAC DISC (VCALL_REJECTION)
|
|
||||||
Private Call - Disconnect - Src=1603 - Dst/TG=211
|
|
||||||
|
|
||||||
*/
|
|
||||||
//Debug: Disable DUP messages if they cause random issues with Type-C trunking (i.e. changing SRC ang TGT IDs, hopping in the middle of calls, etc)
|
//Debug: Disable DUP messages if they cause random issues with Type-C trunking (i.e. changing SRC ang TGT IDs, hopping in the middle of calls, etc)
|
||||||
|
|
||||||
//VCALL_ASSGN_DUP
|
//VCALL_ASSGN_DUP
|
||||||
@@ -167,12 +161,6 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
|||||||
opts->p25_is_tuned = 0;
|
opts->p25_is_tuned = 0;
|
||||||
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->p25_cc_freq);
|
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||||
|
|
||||||
state->nxdn_last_rid = 0;
|
|
||||||
state->nxdn_last_tg = 0;
|
|
||||||
if (state->M == 0)
|
|
||||||
state->nxdn_cipher_type = 0;
|
|
||||||
sprintf (state->nxdn_call_type, "%s", "");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//rtl
|
//rtl
|
||||||
@@ -185,12 +173,6 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
|||||||
memset(state->active_channel, 0, sizeof(state->active_channel));
|
memset(state->active_channel, 0, sizeof(state->active_channel));
|
||||||
opts->p25_is_tuned = 0;
|
opts->p25_is_tuned = 0;
|
||||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||||
|
|
||||||
state->nxdn_last_rid = 0;
|
|
||||||
state->nxdn_last_tg = 0;
|
|
||||||
if (state->M == 0)
|
|
||||||
state->nxdn_cipher_type = 0;
|
|
||||||
sprintf (state->nxdn_call_type, "%s", "");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +250,6 @@ void nxdn_location_id_handler (dsd_state * state, uint32_t location_id, uint8_t
|
|||||||
|
|
||||||
void nxdn_srv_info_handler (dsd_state * state, uint16_t svc_info)
|
void nxdn_srv_info_handler (dsd_state * state, uint16_t svc_info)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
//handle the service information elements
|
//handle the service information elements
|
||||||
//Part 1-A Common Air Interface Ver.2.0
|
//Part 1-A Common Air Interface Ver.2.0
|
||||||
//6.5.33. Service Information
|
//6.5.33. Service Information
|
||||||
@@ -295,8 +276,6 @@ void nxdn_srv_info_handler (dsd_state * state, uint16_t svc_info)
|
|||||||
|
|
||||||
void nxdn_rst_info_handler (dsd_state * state, uint32_t rst_info)
|
void nxdn_rst_info_handler (dsd_state * state, uint32_t rst_info)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
//handle the restriction information elements
|
//handle the restriction information elements
|
||||||
//Part 1-A Common Air Interface Ver.2.0
|
//Part 1-A Common Air Interface Ver.2.0
|
||||||
//6.5.34. Restriction Information
|
//6.5.34. Restriction Information
|
||||||
@@ -358,7 +337,6 @@ void nxdn_ca_info_handler (dsd_state * state, uint32_t ca_info)
|
|||||||
uint32_t step = (ca_info >> 21) & 0x3; //Stepping
|
uint32_t step = (ca_info >> 21) & 0x3; //Stepping
|
||||||
uint32_t base = (ca_info >> 18) & 0x7; //Base Frequency
|
uint32_t base = (ca_info >> 18) & 0x7; //Base Frequency
|
||||||
uint32_t spare = ca_info & 0x3FF;
|
uint32_t spare = ca_info & 0x3FF;
|
||||||
UNUSED(spare);
|
|
||||||
|
|
||||||
//set state variable here to tell us to use DFA or Channel Versions
|
//set state variable here to tell us to use DFA or Channel Versions
|
||||||
if (RCN == 1)
|
if (RCN == 1)
|
||||||
@@ -382,7 +360,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
uint16_t DestinationID = 0;
|
uint16_t DestinationID = 0;
|
||||||
uint8_t CallTimer = 0;
|
uint8_t CallTimer = 0;
|
||||||
uint16_t Channel = 0;
|
uint16_t Channel = 0;
|
||||||
UNUSED(CallTimer);
|
uint8_t LocationIDOption = 0;
|
||||||
|
|
||||||
uint8_t DuplexMode[32] = {0};
|
uint8_t DuplexMode[32] = {0};
|
||||||
uint8_t TransmissionMode[32] = {0};
|
uint8_t TransmissionMode[32] = {0};
|
||||||
@@ -405,7 +383,6 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
uint8_t bw = 0;
|
uint8_t bw = 0;
|
||||||
uint16_t OFN = 0;
|
uint16_t OFN = 0;
|
||||||
uint16_t IFN = 0;
|
uint16_t IFN = 0;
|
||||||
UNUSED2(bw, IFN);
|
|
||||||
|
|
||||||
/* Decode "CC Option" */
|
/* Decode "CC Option" */
|
||||||
CCOption = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
|
CCOption = (uint8_t)ConvertBitIntoBytes(&Message[8], 8);
|
||||||
@@ -478,8 +455,8 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
|
|
||||||
/* Print the "Voice Call Option" */
|
/* Print the "Voice Call Option" */
|
||||||
if (MessageType == 0x4 || MessageType == 0x5) NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
|
if (MessageType == 0x4 || MessageType == 0x5) NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
|
||||||
if (MessageType == 0x4 || MessageType == 0x5) fprintf(stderr, "%s %s (%02X) - ", DuplexMode, TransmissionMode, VoiceCallOption);
|
if (MessageType == 0x4 || MessageType == 0x5) fprintf(stderr, "%s %s - ", DuplexMode, TransmissionMode);
|
||||||
else fprintf (stderr, " Data Call Assignment (%02X) - ", VoiceCallOption); //DCALL_ASSGN or DCALL_ASSGN_DUP
|
else fprintf (stderr, " Data Call Assignment - "); //DCALL_ASSGN or DCALL_ASSGN_DUP
|
||||||
|
|
||||||
/* Print Source ID and Destination ID (Talk Group or Unit ID) */
|
/* Print Source ID and Destination ID (Talk Group or Unit ID) */
|
||||||
fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF);
|
fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF);
|
||||||
@@ -504,25 +481,11 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TG Hold during VCALL_ASSGN_DUP, allow tuning to TG hold channel assignment
|
|
||||||
if (MessageType == 0x5 && opts->p25_is_tuned == 1 && opts->p25_trunk == 1)
|
|
||||||
{
|
|
||||||
if ( state->tg_hold != 0 && state->tg_hold == DestinationID )
|
|
||||||
{
|
|
||||||
MessageType = 0x04; //convert to VCALL
|
|
||||||
// opts->p25_is_tuned = 0; //open tuning back up to tune
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//use DUP to display any other rolling active channels while on a call (from the dup message)
|
|
||||||
int dup = 0;
|
|
||||||
if (MessageType == 0x5) dup = 1;
|
|
||||||
|
|
||||||
//assign active call to string (might place inside of tune decision to get multiple ones?)
|
//assign active call to string (might place inside of tune decision to get multiple ones?)
|
||||||
if (state->nxdn_rcn == 0)
|
if (state->nxdn_rcn == 0)
|
||||||
sprintf (state->active_channel[dup], "Active Ch: %d TG: %d SRC: %d; ", Channel, DestinationID, SourceUnitID);
|
sprintf (state->active_channel[0], "Active Ch: %d TG: %d; ", Channel, DestinationID);
|
||||||
if (state->nxdn_rcn == 1)
|
if (state->nxdn_rcn == 1)
|
||||||
sprintf (state->active_channel[dup], "Active Ch: %d TG: %d SRC: %d; ", OFN, DestinationID, SourceUnitID);
|
sprintf (state->active_channel[0], "Active Ch: %d TG: %d; ", OFN, DestinationID);
|
||||||
|
|
||||||
state->last_active_time = time(NULL);
|
state->last_active_time = time(NULL);
|
||||||
|
|
||||||
@@ -574,7 +537,6 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
//run group/source analysis and tune if available/desired
|
//run group/source analysis and tune if available/desired
|
||||||
//group list mode so we can look and see if we need to block tuning any groups, etc
|
//group list mode so we can look and see if we need to block tuning any groups, etc
|
||||||
char mode[8]; //allow, block, digital, enc, etc
|
char mode[8]; //allow, block, digital, enc, etc
|
||||||
sprintf (mode, "%s", "");
|
|
||||||
|
|
||||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||||
@@ -582,43 +544,19 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
|
|
||||||
for (int i = 0; i < state->group_tally; i++)
|
for (int i = 0; i < state->group_tally; i++)
|
||||||
{
|
{
|
||||||
if (state->group_array[i].groupNumber == DestinationID && DestinationID != 0) //destination, if it isn't 0
|
if (state->group_array[i].groupNumber == DestinationID) //source, or destination?
|
||||||
{
|
{
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
strcpy (mode, state->group_array[i].groupMode);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
//might not be ideal if both source and group/target are both in the array
|
//might not be ideal if both source and group/target are both in the array
|
||||||
else if (state->group_array[i].groupNumber == SourceUnitID && DestinationID == 0) //source, if destination is 0
|
else if (state->group_array[i].groupNumber == SourceUnitID) //source, or destination?
|
||||||
{
|
{
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
strcpy (mode, state->group_array[i].groupMode);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check purely by SourceUnitID as last resort -- this is a bugfix to block individual radios on selected systems
|
|
||||||
if ((strcmp(mode, "") == 0))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < state->group_tally; i++)
|
|
||||||
{
|
|
||||||
if (state->group_array[i].groupNumber == SourceUnitID)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TG hold on NXDN -- block non-matching target, allow matching DestinationID
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold != DestinationID) sprintf (mode, "%s", "B");
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold == DestinationID)
|
|
||||||
{
|
|
||||||
sprintf (mode, "%s", "A");
|
|
||||||
opts->p25_is_tuned = 0; //unlock tuner at this stage and not above check
|
|
||||||
}
|
|
||||||
|
|
||||||
//check to see if the source/target candidate is blocked first
|
//check to see if the source/target candidate is blocked first
|
||||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0)) //DE is digital encrypted, B is block
|
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0)) //DE is digital encrypted, B is block
|
||||||
{
|
{
|
||||||
@@ -641,9 +579,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||||
|
|
||||||
//set rid and tg when we actually tune to it
|
//set rid and tg when we actually tune to it
|
||||||
//only assign rid if not spare and not reserved (happens on private calls, unsure of its significance)
|
state->nxdn_last_rid = SourceUnitID;
|
||||||
if ( (VoiceCallOption & 0xF) < 4) //ideally, only want 0, 2, or 3
|
|
||||||
state->nxdn_last_rid = SourceUnitID;
|
|
||||||
state->nxdn_last_tg = DestinationID;
|
state->nxdn_last_tg = DestinationID;
|
||||||
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
||||||
|
|
||||||
@@ -674,9 +610,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
opts->p25_is_tuned = 1;
|
opts->p25_is_tuned = 1;
|
||||||
|
|
||||||
//set rid and tg when we actually tune to it
|
//set rid and tg when we actually tune to it
|
||||||
//only assign rid if not spare and not reserved (happens on private calls, unsure of its significance)
|
state->nxdn_last_rid = SourceUnitID;
|
||||||
if ( (VoiceCallOption & 0xF) < 4) //ideally, only want 0, 2, or 3
|
|
||||||
state->nxdn_last_rid = SourceUnitID;
|
|
||||||
state->nxdn_last_tg = DestinationID;
|
state->nxdn_last_tg = DestinationID;
|
||||||
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
||||||
|
|
||||||
@@ -702,16 +636,11 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
|||||||
|
|
||||||
void NXDN_decode_Alias(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
void NXDN_decode_Alias(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
uint8_t Alias1 = 0x20; //value of an ascii 'space' character
|
||||||
|
|
||||||
uint8_t Alias1 = 0x20;
|
|
||||||
uint8_t Alias2 = 0x20;
|
uint8_t Alias2 = 0x20;
|
||||||
uint8_t Alias3 = 0x20;
|
uint8_t Alias3 = 0x20;
|
||||||
uint8_t Alias4 = 0x20;
|
uint8_t Alias4 = 0x20;
|
||||||
uint8_t blocknumber = 0;
|
uint8_t blocknumber = 0;
|
||||||
uint8_t total = 0;
|
|
||||||
uint8_t unk1 = 0;
|
|
||||||
uint8_t unk2 = 0;
|
|
||||||
uint8_t CrcCorrect = 0;
|
uint8_t CrcCorrect = 0;
|
||||||
|
|
||||||
//alias can also hit on a facch1 -- do we still need this checkdown?
|
//alias can also hit on a facch1 -- do we still need this checkdown?
|
||||||
@@ -724,23 +653,12 @@ void NXDN_decode_Alias(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
|
|
||||||
//FACCH Payload [3F][68][82][04][2 <- block number4] "[69][6F][6E][20]" <- 4 alias octets [00][7F][1C]
|
//FACCH Payload [3F][68][82][04][2 <- block number4] "[69][6F][6E][20]" <- 4 alias octets [00][7F][1C]
|
||||||
blocknumber = (uint8_t)ConvertBitIntoBytes(&Message[32], 4) & 0x7; // & 0x7, might just be three bits, unsure
|
blocknumber = (uint8_t)ConvertBitIntoBytes(&Message[32], 4) & 0x7; // & 0x7, might just be three bits, unsure
|
||||||
total = (uint8_t)ConvertBitIntoBytes(&Message[36], 4) & 0x7; //second value seems to be total number of blocks? or len of alias in this segment?
|
|
||||||
unk1 = (uint8_t)ConvertBitIntoBytes(&Message[8], 8); //unknown values in first two bytes after the opcode
|
|
||||||
unk2 = (uint8_t)ConvertBitIntoBytes(&Message[16], 8); //could be related to the format of these (Iso8? etc)
|
|
||||||
UNUSED4(unk1, unk2, total, blocknumber);
|
|
||||||
Alias1 = (uint8_t)ConvertBitIntoBytes(&Message[40], 8);
|
Alias1 = (uint8_t)ConvertBitIntoBytes(&Message[40], 8);
|
||||||
Alias2 = (uint8_t)ConvertBitIntoBytes(&Message[48], 8);
|
Alias2 = (uint8_t)ConvertBitIntoBytes(&Message[48], 8);
|
||||||
Alias3 = (uint8_t)ConvertBitIntoBytes(&Message[56], 8);
|
Alias3 = (uint8_t)ConvertBitIntoBytes(&Message[56], 8);
|
||||||
Alias4 = (uint8_t)ConvertBitIntoBytes(&Message[64], 8);
|
Alias4 = (uint8_t)ConvertBitIntoBytes(&Message[64], 8);
|
||||||
|
|
||||||
char str_a[120]; char str_b[50];
|
|
||||||
|
|
||||||
//debug/test
|
|
||||||
// fprintf (stderr, " U1: %02X U2: %02X;", unk1, unk2);
|
|
||||||
// fprintf (stderr, " A:%d/%d; ", blocknumber, total);
|
|
||||||
|
|
||||||
//sanity check to prevent OOB array assignment
|
//sanity check to prevent OOB array assignment
|
||||||
if (blocknumber > 0 && blocknumber < 4) //last 'block' may have been assigning garbage name values -- I'm honestly not sure block'4' contains Alias data, but other data or something
|
if (blocknumber > 0 && blocknumber < 4) //last 'block' may have been assigning garbage name values -- needs testing
|
||||||
{
|
{
|
||||||
//assign to index -1, since block number conveyed here is 1,2,3,4, and index values are 0,1,2,3
|
//assign to index -1, since block number conveyed here is 1,2,3,4, and index values are 0,1,2,3
|
||||||
//only assign if within valid range of ascii characters (not including diacritical extended alphabet)
|
//only assign if within valid range of ascii characters (not including diacritical extended alphabet)
|
||||||
@@ -749,33 +667,16 @@ void NXDN_decode_Alias(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
//since we are zeroing out the blocks on tx_rel and other conditions, better to just set nothing to bad Alias bytes
|
//since we are zeroing out the blocks on tx_rel and other conditions, better to just set nothing to bad Alias bytes
|
||||||
//tends to zero out otherwise already good blocks set in a previous repitition.
|
//tends to zero out otherwise already good blocks set in a previous repitition.
|
||||||
if (Alias1 > 0x19 && Alias1 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][0], "%c", Alias1);
|
if (Alias1 > 0x19 && Alias1 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][0], "%c", Alias1);
|
||||||
// else sprintf (state->nxdn_alias_block_segment[blocknumber-1][0], "%c", 0x20); //space
|
else ;// sprintf (state->nxdn_alias_block_segment[blocknumber-1][0], "%c", 32); //space
|
||||||
|
|
||||||
if (Alias2 > 0x19 && Alias2 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][1], "%c", Alias2);
|
if (Alias2 > 0x19 && Alias2 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][1], "%c", Alias2);
|
||||||
// else sprintf (state->nxdn_alias_block_segment[blocknumber-1][1], "%c", 0x20); //space
|
else ; //sprintf (state->nxdn_alias_block_segment[blocknumber-1][1], "%c", 0); //space
|
||||||
|
|
||||||
if (Alias3 > 0x19 && Alias3 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][2], "%c", Alias3);
|
if (Alias3 > 0x19 && Alias3 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][2], "%c", Alias3);
|
||||||
// else sprintf (state->nxdn_alias_block_segment[blocknumber-1][2], "%c", 0x20); //space
|
else ; //sprintf (state->nxdn_alias_block_segment[blocknumber-1][2], "%c", 0); //space
|
||||||
|
|
||||||
if (Alias4 > 0x19 && Alias4 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][3], "%c", Alias4);
|
if (Alias4 > 0x19 && Alias4 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][3], "%c", Alias4);
|
||||||
// else sprintf (state->nxdn_alias_block_segment[blocknumber-1][3], "%c", 0x20); //space
|
else ; //sprintf (state->nxdn_alias_block_segment[blocknumber-1][3], "%c", 0); //space
|
||||||
|
|
||||||
sprintf (str_a, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
|
||||||
state->nxdn_alias_block_segment[0][0], state->nxdn_alias_block_segment[0][1], state->nxdn_alias_block_segment[0][2], state->nxdn_alias_block_segment[0][3],
|
|
||||||
state->nxdn_alias_block_segment[1][0], state->nxdn_alias_block_segment[1][1], state->nxdn_alias_block_segment[1][2], state->nxdn_alias_block_segment[1][3],
|
|
||||||
state->nxdn_alias_block_segment[2][0], state->nxdn_alias_block_segment[2][1], state->nxdn_alias_block_segment[2][2], state->nxdn_alias_block_segment[2][3],
|
|
||||||
state->nxdn_alias_block_segment[3][0], state->nxdn_alias_block_segment[3][1], state->nxdn_alias_block_segment[3][2], state->nxdn_alias_block_segment[3][3]);
|
|
||||||
|
|
||||||
//juggle strings here so we don't get compiler warnings on assignment size
|
|
||||||
memcpy (str_b, str_a, 48); str_b[49] = '\0';
|
|
||||||
|
|
||||||
//one noteable issue is that on conventional, its possible to decode an alias before decong the src id
|
|
||||||
//just depends on reception and if VCALL is decoded before Alias, this will lead to alias being assigned
|
|
||||||
//to incorrect src values or placement in the ncurses terminal's call history section
|
|
||||||
|
|
||||||
if (state->nxdn_last_rid != 0)
|
|
||||||
sprintf (state->str50a, "%s", str_b);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//crc errs in one repitition may occlude an otherwise good alias, so test and change if needed
|
//crc errs in one repitition may occlude an otherwise good alias, so test and change if needed
|
||||||
@@ -805,7 +706,6 @@ void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
uint16_t channel2 = 0;
|
uint16_t channel2 = 0;
|
||||||
long int freq1 = 0;
|
long int freq1 = 0;
|
||||||
long int freq2 = 0;
|
long int freq2 = 0;
|
||||||
UNUSED2(channel2sts, freq2);
|
|
||||||
|
|
||||||
//DFA
|
//DFA
|
||||||
uint8_t bw1 = 0;
|
uint8_t bw1 = 0;
|
||||||
@@ -814,7 +714,6 @@ void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
uint8_t bw2 = 0;
|
uint8_t bw2 = 0;
|
||||||
uint16_t OFN2 = 0;
|
uint16_t OFN2 = 0;
|
||||||
uint16_t IFN2 = 0;
|
uint16_t IFN2 = 0;
|
||||||
UNUSED(bw2);
|
|
||||||
|
|
||||||
location_id = (uint32_t)ConvertBitIntoBytes(&Message[8], 24);
|
location_id = (uint32_t)ConvertBitIntoBytes(&Message[8], 24);
|
||||||
channel1sts = (uint8_t)ConvertBitIntoBytes(&Message[32], 6);
|
channel1sts = (uint8_t)ConvertBitIntoBytes(&Message[32], 6);
|
||||||
@@ -956,7 +855,6 @@ void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message
|
|||||||
uint16_t channel2 = 0;
|
uint16_t channel2 = 0;
|
||||||
long int freq1 = 0;
|
long int freq1 = 0;
|
||||||
long int freq2 = 0;
|
long int freq2 = 0;
|
||||||
UNUSED2(freq1, freq2);
|
|
||||||
|
|
||||||
location_id = (uint32_t)ConvertBitIntoBytes(&Message[8], 24);
|
location_id = (uint32_t)ConvertBitIntoBytes(&Message[8], 24);
|
||||||
cs_info = (uint16_t)ConvertBitIntoBytes(&Message[32], 16);
|
cs_info = (uint16_t)ConvertBitIntoBytes(&Message[32], 16);
|
||||||
@@ -1015,17 +913,21 @@ void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
uint32_t adj1_site = 0;
|
uint32_t adj1_site = 0;
|
||||||
uint32_t adj2_site = 0;
|
uint32_t adj2_site = 0;
|
||||||
uint32_t adj3_site = 0;
|
uint32_t adj3_site = 0;
|
||||||
|
uint32_t adj4_site = 0;
|
||||||
//options -- 6.5.38. Adjacent Site Option -- 4 LSB are Site Number, 2 MSB are spares
|
//options -- 6.5.38. Adjacent Site Option -- 4 LSB are Site Number, 2 MSB are spares
|
||||||
uint8_t adj1_opt = 0;
|
uint8_t adj1_opt = 0;
|
||||||
uint8_t adj2_opt = 0;
|
uint8_t adj2_opt = 0;
|
||||||
uint8_t adj3_opt = 0;
|
uint8_t adj3_opt = 0;
|
||||||
//channel or OFN
|
uint8_t adj4_opt = 0;
|
||||||
|
//channel or OFN
|
||||||
uint16_t adj1_chan = 0;
|
uint16_t adj1_chan = 0;
|
||||||
uint16_t adj2_chan = 0;
|
uint16_t adj2_chan = 0;
|
||||||
uint16_t adj3_chan = 0;
|
uint16_t adj3_chan = 0;
|
||||||
|
uint16_t adj4_chan = 0;
|
||||||
//DFA only BW value
|
//DFA only BW value
|
||||||
uint8_t adj1_bw = 0;
|
uint8_t adj1_bw = 0;
|
||||||
uint8_t adj2_bw = 0;
|
uint8_t adj2_bw = 0;
|
||||||
|
uint8_t adj3_bw = 0;
|
||||||
|
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
|
||||||
@@ -1137,7 +1039,6 @@ void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
|
|
||||||
void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
uint8_t CCOption = 0;
|
uint8_t CCOption = 0;
|
||||||
uint8_t CallType = 0;
|
uint8_t CallType = 0;
|
||||||
@@ -1148,6 +1049,7 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
uint8_t KeyID = 0;
|
uint8_t KeyID = 0;
|
||||||
uint8_t DuplexMode[32] = {0};
|
uint8_t DuplexMode[32] = {0};
|
||||||
uint8_t TransmissionMode[32] = {0};
|
uint8_t TransmissionMode[32] = {0};
|
||||||
|
unsigned long long int FullMessage = 0;
|
||||||
|
|
||||||
uint8_t MessageType;
|
uint8_t MessageType;
|
||||||
/* Get the "Message Type" field */
|
/* Get the "Message Type" field */
|
||||||
@@ -1188,7 +1090,6 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
uint8_t idas = 0;
|
uint8_t idas = 0;
|
||||||
uint8_t rep1 = 0;
|
uint8_t rep1 = 0;
|
||||||
uint8_t rep2 = 0;
|
uint8_t rep2 = 0;
|
||||||
UNUSED(rep2);
|
|
||||||
if (strcmp (state->nxdn_location_category, "Type-D") == 0) idas = 1;
|
if (strcmp (state->nxdn_location_category, "Type-D") == 0) idas = 1;
|
||||||
if (idas)
|
if (idas)
|
||||||
{
|
{
|
||||||
@@ -1230,7 +1131,7 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
|
|
||||||
/* Print the "Voice Call Option" */
|
/* Print the "Voice Call Option" */
|
||||||
if (MessageType == 0x1) NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
|
if (MessageType == 0x1) NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
|
||||||
if (MessageType == 0x1) fprintf(stderr, "%s %s (%02X) - ", DuplexMode, TransmissionMode, VoiceCallOption);
|
if (MessageType == 0x1) fprintf(stderr, "%s %s - ", DuplexMode, TransmissionMode);
|
||||||
else if (MessageType == 0x07) fprintf (stderr, "Transmission Release Ex - "); //TX_REL_EX
|
else if (MessageType == 0x07) fprintf (stderr, "Transmission Release Ex - "); //TX_REL_EX
|
||||||
else if (MessageType == 0x08) fprintf (stderr, " Transmission Release - "); //TX_REL
|
else if (MessageType == 0x08) fprintf (stderr, " Transmission Release - "); //TX_REL
|
||||||
else if (MessageType == 0x11) fprintf (stderr, " Disconnect - "); //DISC
|
else if (MessageType == 0x11) fprintf (stderr, " Disconnect - "); //DISC
|
||||||
@@ -1277,20 +1178,11 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
//only grab if VCALL
|
//only grab if VCALL
|
||||||
if(MessageType == 0x1)
|
if(MessageType == 0x1)
|
||||||
{
|
{
|
||||||
//only assign rid if not spare and not reserved (happens on private calls, unsure of its significance)
|
state->nxdn_last_rid = SourceUnitID;
|
||||||
if ( (VoiceCallOption & 0xF) < 4) //ideally, only want 0, 2, or 3
|
|
||||||
state->nxdn_last_rid = SourceUnitID;
|
|
||||||
state->nxdn_last_tg = DestinationID;
|
state->nxdn_last_tg = DestinationID;
|
||||||
state->nxdn_key = KeyID;
|
state->nxdn_key = KeyID;
|
||||||
state->nxdn_cipher_type = CipherType;
|
state->nxdn_cipher_type = CipherType;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
state->nxdn_last_rid = 0;
|
|
||||||
state->nxdn_last_tg = 0;
|
|
||||||
sprintf (state->str50a, "%s", "");
|
|
||||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
|
||||||
}
|
|
||||||
|
|
||||||
//set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic
|
//set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic
|
||||||
if (state->nxdn_cipher_type != 0)
|
if (state->nxdn_cipher_type != 0)
|
||||||
@@ -1301,51 +1193,11 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
|||||||
{
|
{
|
||||||
state->dmr_encL = 0;
|
state->dmr_encL = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TG ENC LO/B if ENC trunked following disabled #121 -- was locking out everything
|
|
||||||
if (opts->p25_trunk == 1 && opts->trunk_tune_enc_calls == 0 && MessageType == 0x1 && state->dmr_encL == 1)
|
|
||||||
{
|
|
||||||
int i, lo = 0;
|
|
||||||
uint16_t t = 0; char gm[8]; char gn[50];
|
|
||||||
|
|
||||||
//check to see if this group already exists, or has already been locked out, or is allowed
|
|
||||||
for (i = 0; i <= state->group_tally; i++)
|
|
||||||
{
|
|
||||||
t = (uint16_t)state->group_array[i].groupNumber;
|
|
||||||
if (DestinationID == t && t != 0)
|
|
||||||
{
|
|
||||||
lo = 1;
|
|
||||||
//write current mode and name to temp strings
|
|
||||||
sprintf (gm, "%s", state->group_array[i].groupMode);
|
|
||||||
sprintf (gn, "%s", state->group_array[i].groupName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if group doesn't exist, or isn't locked out, then do so now.
|
|
||||||
if (lo == 0)
|
|
||||||
{
|
|
||||||
state->group_array[state->group_tally].groupNumber = DestinationID;
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
|
||||||
sprintf (state->group_array[state->group_tally].groupName, "%s", "ENC LO");
|
|
||||||
sprintf (gm, "%s", "DE");
|
|
||||||
sprintf (gn, "%s", "ENC LO");
|
|
||||||
state->group_tally++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Craft a fake DISC Message send it to return to CC
|
|
||||||
uint8_t dbits[96]; memset (dbits, 0, sizeof(dbits)); dbits[3] = 1; dbits[7] = 1; //DISC = 0x11;
|
|
||||||
if ( (strcmp(gm, "DE") == 0) && (strcmp(gn, "ENC LO") == 0) )
|
|
||||||
NXDN_Elements_Content_decode (opts, state, 1, dbits);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* End NXDN_decode_VCALL() */
|
} /* End NXDN_decode_VCALL() */
|
||||||
|
|
||||||
void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
uint32_t i;
|
||||||
|
|
||||||
state->payload_miN = 0; //zero out
|
state->payload_miN = 0; //zero out
|
||||||
unsigned long long int IV = 0;
|
unsigned long long int IV = 0;
|
||||||
|
|
||||||
@@ -1537,7 +1389,6 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
|||||||
//run group/tgt analysis and tune if available/desired
|
//run group/tgt analysis and tune if available/desired
|
||||||
//group list mode so we can look and see if we need to block tuning any groups, etc
|
//group list mode so we can look and see if we need to block tuning any groups, etc
|
||||||
char mode[8]; //allow, block, digital, enc, etc
|
char mode[8]; //allow, block, digital, enc, etc
|
||||||
sprintf (mode, "%s", "");
|
|
||||||
|
|
||||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||||
@@ -1549,18 +1400,9 @@ void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uin
|
|||||||
{
|
{
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
strcpy (mode, state->group_array[i].groupMode);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TG hold on IDAS -- block non-matching target, allow matching DestinationID
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold != id) sprintf (mode, "%s", "B");
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold == id)
|
|
||||||
{
|
|
||||||
sprintf (mode, "%s", "A");
|
|
||||||
opts->p25_is_tuned = 0; //unlock tuner at this stage and not above check
|
|
||||||
}
|
|
||||||
|
|
||||||
long int freq = 0;
|
long int freq = 0;
|
||||||
freq = nxdn_channel_to_frequency(opts, state, rep1);
|
freq = nxdn_channel_to_frequency(opts, state, rep1);
|
||||||
|
|
||||||
@@ -1710,7 +1552,7 @@ char * NXDN_Call_Type_To_Str(uint8_t CallType)
|
|||||||
{
|
{
|
||||||
case 0: Ptr = "Broadcast Call"; break;
|
case 0: Ptr = "Broadcast Call"; break;
|
||||||
case 1: Ptr = "Group Call"; break;
|
case 1: Ptr = "Group Call"; break;
|
||||||
case 2: Ptr = "Idle"; break; //"Unspecified Call" This value is used only on Idle Burst TX_REL message.
|
case 2: Ptr = "Transmission Release"; break; //"Unspecified Call" This value is used only on TX_REL message.
|
||||||
case 3: Ptr = "Session Call"; break; //"reserved" is session call on Type D
|
case 3: Ptr = "Session Call"; break; //"reserved" is session call on Type D
|
||||||
case 4: Ptr = "Private Call"; break;
|
case 4: Ptr = "Private Call"; break;
|
||||||
case 5: Ptr = "Reserved"; break;
|
case 5: Ptr = "Reserved"; break;
|
||||||
@@ -1732,25 +1574,12 @@ void NXDN_Voice_Call_Option_To_Str(uint8_t VoiceCallOption, uint8_t * Duplex, ui
|
|||||||
if(VoiceCallOption & 0x10) strcpy((char *)Duplex, "Duplex");
|
if(VoiceCallOption & 0x10) strcpy((char *)Duplex, "Duplex");
|
||||||
else strcpy((char *)Duplex, "Half Duplex");
|
else strcpy((char *)Duplex, "Half Duplex");
|
||||||
|
|
||||||
switch(VoiceCallOption & 0xF)
|
switch(VoiceCallOption & 0x17)
|
||||||
{ //added all options, getting a random one on an NXDN96 System, need to know what it is
|
{
|
||||||
case 0: Ptr = "4800bps/EHR"; break;
|
case 0: Ptr = "4800bps/EHR"; break;
|
||||||
case 1: Ptr = "Reserved 1"; break;
|
case 2: Ptr = "9600bps/EHR"; break;
|
||||||
case 2: Ptr = "9600bps/EHR"; break;
|
case 3: Ptr = "9600bps/EFR"; break;
|
||||||
case 3: Ptr = "9600bps/EFR"; break;
|
default: Ptr = "Reserved Voice Call Option"; break;
|
||||||
case 4: Ptr = "Reserved 4"; break;
|
|
||||||
case 5: Ptr = "Reserved 5"; break;
|
|
||||||
case 6: Ptr = "Reserved 6"; break;
|
|
||||||
case 7: Ptr = "Reserved 7"; break;
|
|
||||||
case 8: Ptr = "4800bps/EHR S:1"; break; //spare bit enabled
|
|
||||||
case 9: Ptr = "Reserved 9; S:1"; break; //spare bit enabled
|
|
||||||
case 10: Ptr = "9600bps/EHR S:1"; break; //spare bit enabled
|
|
||||||
case 11: Ptr = "9600bps/EFR S:1"; break; //spare bit enabled
|
|
||||||
case 12: Ptr = "Reserved C; S1;"; break; //spare bit enabled
|
|
||||||
case 13: Ptr = "Reserved D; S1"; break; //spare bit enabled
|
|
||||||
case 14: Ptr = "Reserved E; S1"; break; //spare bit enabled
|
|
||||||
case 15: Ptr = "Reserved F: S1"; break; //spare bit enabled
|
|
||||||
default: Ptr = "Unk;"; break; //should never get here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy((char *)TransmissionMode, Ptr);
|
strcpy((char *)TransmissionMode, Ptr);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
|||||||
// length is implicitly 192, with frame sync in first 10 dibits
|
// length is implicitly 192, with frame sync in first 10 dibits
|
||||||
uint8_t dbuf[182];
|
uint8_t dbuf[182];
|
||||||
uint8_t lich;
|
uint8_t lich;
|
||||||
|
int answer_len = 0;
|
||||||
uint8_t answer[32];
|
uint8_t answer[32];
|
||||||
uint8_t sacch_answer[32];
|
uint8_t sacch_answer[32];
|
||||||
int lich_parity_received;
|
int lich_parity_received;
|
||||||
@@ -42,6 +43,8 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
|||||||
int udch = 0;
|
int udch = 0;
|
||||||
int sacch = 0;
|
int sacch = 0;
|
||||||
int cac = 0;
|
int cac = 0;
|
||||||
|
int sr_structure;
|
||||||
|
int sr_ran;
|
||||||
|
|
||||||
//new, and even more confusing NXDN Type-D / "IDAS" acronyms
|
//new, and even more confusing NXDN Type-D / "IDAS" acronyms
|
||||||
int idas = 0;
|
int idas = 0;
|
||||||
@@ -54,7 +57,6 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t lich_fc = 0; //Functional Channel Type
|
uint8_t lich_fc = 0; //Functional Channel Type
|
||||||
uint8_t lich_op = 0; //Options
|
uint8_t lich_op = 0; //Options
|
||||||
uint8_t direction; //inbound or outbound direction
|
uint8_t direction; //inbound or outbound direction
|
||||||
UNUSED2(lich_fc, lich_op);
|
|
||||||
|
|
||||||
uint8_t lich_dibits[8];
|
uint8_t lich_dibits[8];
|
||||||
uint8_t sacch_bits[60];
|
uint8_t sacch_bits[60];
|
||||||
|
|||||||
@@ -55,10 +55,11 @@ const int nZ[36] = { 5, 3, 4, 2, 3, 1,
|
|||||||
|
|
||||||
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182])
|
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182])
|
||||||
{
|
{
|
||||||
int i;
|
int i, j, dibit;
|
||||||
int start, stop;
|
int start, stop;
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
|
|
||||||
|
unsigned char *pr;
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
|
|
||||||
//these conditions will determine our starting and stopping value for voice
|
//these conditions will determine our starting and stopping value for voice
|
||||||
@@ -89,13 +90,6 @@ void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182
|
|||||||
|
|
||||||
}
|
}
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
|
|
||||||
if (opts->floating_point == 0 )
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
|
|||||||
167
src/p25_12.c
167
src/p25_12.c
@@ -1,167 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* p25_12.c
|
|
||||||
* P25p1 1/2 Rate Simple Trellis Decoder
|
|
||||||
*
|
|
||||||
* LWVMOBILE
|
|
||||||
* 2023-10 DSD-FME Florida Man Edition
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
|
|
||||||
uint8_t p25_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 constellation points
|
|
||||||
uint8_t p25_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 p25_fsm[16] = {
|
|
||||||
0,15,12,3,
|
|
||||||
4,11,8,7,
|
|
||||||
13,2,1,14,
|
|
||||||
9,6,5,10 };
|
|
||||||
|
|
||||||
//this is a dibit-pair to trellis dibit transition matrix (SDRTrunk and Ossmann)
|
|
||||||
//when evaluating hamming distance, we want to use this xor the dibit-pair nib,
|
|
||||||
//and not the fsm xor the constellation point
|
|
||||||
uint8_t p25_dtm[16] = {
|
|
||||||
2,12,1,15,
|
|
||||||
14,0,13,3,
|
|
||||||
9,7,10,4,
|
|
||||||
5,11,6,8 };
|
|
||||||
|
|
||||||
int count_bits(uint8_t b, int slen)
|
|
||||||
{
|
|
||||||
int i = 0; int j = 0;
|
|
||||||
for (j = 0; j < slen; j++)
|
|
||||||
{
|
|
||||||
if ( (b & 1) == 1) i++;
|
|
||||||
b = b >> 1;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t find_min(uint8_t list[4], int len)
|
|
||||||
{
|
|
||||||
int min = list[0];
|
|
||||||
uint8_t index = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 1; i < len; i++)
|
|
||||||
{
|
|
||||||
if (list[i] < min)
|
|
||||||
{
|
|
||||||
min = list[i];
|
|
||||||
index = (uint8_t)i;
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOTE: Disqualifying result on uniqueness can impact decoding
|
|
||||||
//let the CRC determine if the result is good or bad
|
|
||||||
//its not uncommon for two values of the same min
|
|
||||||
//distance to emerge, so its 50/50 each time
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int p25_12(uint8_t * input, uint8_t treturn[12])
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
int 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[p25_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] = p25_constellation_map[nibs[i]];
|
|
||||||
|
|
||||||
//debug view points
|
|
||||||
// fprintf (stderr, "\n P =");
|
|
||||||
// for (i = 0; i < 49; i++)
|
|
||||||
// fprintf (stderr, " %02d", point[i]);
|
|
||||||
|
|
||||||
//convert constellation points into tdibit values using the FSM
|
|
||||||
uint8_t state = 0;
|
|
||||||
uint8_t tdibits[49]; //trellis dibits 1/2 rate
|
|
||||||
memset (tdibits, 0xF, sizeof(tdibits));
|
|
||||||
uint8_t hd[4]; //array of the four fsm words hamming distance
|
|
||||||
memset (hd, 0, sizeof(hd));
|
|
||||||
uint8_t min = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 49; i++)
|
|
||||||
{
|
|
||||||
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
if ( p25_fsm[(state*4)+j] == point[i] )
|
|
||||||
{
|
|
||||||
//return our tdibit value and state for the next point
|
|
||||||
tdibits[i] = state = (uint8_t)j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if tdibit value is greater than 3, then we have a decoding error
|
|
||||||
if (tdibits[i] == 0xF)
|
|
||||||
{
|
|
||||||
irr_err++; //increment number of errors
|
|
||||||
|
|
||||||
//debug position of error and state value
|
|
||||||
// fprintf (stderr, " %d:%d;", i, state);
|
|
||||||
|
|
||||||
//this method only seems to be reliable up to 1-2 bit errors...sometimes
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
hd[j] = count_bits ( ((nibs[i] ^ p25_dtm[(state*4)+j]) & 0xF ), 4 );
|
|
||||||
min = find_min (hd, 4);
|
|
||||||
tdibits[i] = state = min;
|
|
||||||
|
|
||||||
memset (hd, 0, sizeof(hd));
|
|
||||||
min = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug view tdibits/states
|
|
||||||
// fprintf (stderr, "\n T =");
|
|
||||||
// for (i = 0; i < 49; i++)
|
|
||||||
// fprintf (stderr, " %02d", tdibits[i]);
|
|
||||||
|
|
||||||
//pack tdibits into return payload bytes
|
|
||||||
for (i = 0; i < 12; i++)
|
|
||||||
treturn[i] = (tdibits[(i*4)+0] << 6) | (tdibits[(i*4)+1] << 4) | (tdibits[(i*4)+2] << 2) | tdibits[(i*4)+3];
|
|
||||||
|
|
||||||
//trellis point/state err tally
|
|
||||||
// if (irr_err != 0)
|
|
||||||
// fprintf (stderr, " P_ERR = %d", irr_err);
|
|
||||||
|
|
||||||
return (irr_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
168
src/p25_crc.c
168
src/p25_crc.c
@@ -1,168 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* p25_crc.c
|
|
||||||
* P25 Misc CRC checks
|
|
||||||
*
|
|
||||||
* LWVMOBILE
|
|
||||||
* 2022-09 DSD-FME Florida Man Edition
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
|
|
||||||
//modified from the LEH ComputeCrcCCITT to accept variable len buffer bits
|
|
||||||
uint16_t ComputeCrcCCITT16b(const uint8_t buf[], unsigned int len)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
uint16_t CRC = 0x0000;
|
|
||||||
uint16_t Polynome = 0x1021;
|
|
||||||
for(i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
if(((CRC >> 15) & 1) ^ (buf[i] & 1))
|
|
||||||
{
|
|
||||||
CRC = (CRC << 1) ^ Polynome;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CRC <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invert the CRC */
|
|
||||||
CRC ^= 0xFFFF;
|
|
||||||
|
|
||||||
/* Return the CRC */
|
|
||||||
return CRC;
|
|
||||||
} /* End ComputeCrcCCITT() */
|
|
||||||
|
|
||||||
//modified from crc12_ok to run a quickie on 16 instead
|
|
||||||
static uint16_t crc16_ok(const uint8_t bits[], unsigned int len) {
|
|
||||||
uint16_t crc = 0;
|
|
||||||
// fprintf (stderr, "\n LEN = %d", len);
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
crc = crc << 1;
|
|
||||||
crc = crc | bits[i+len];
|
|
||||||
}
|
|
||||||
uint16_t check = ComputeCrcCCITT16b(bits, len);
|
|
||||||
|
|
||||||
if (crc == check)
|
|
||||||
{
|
|
||||||
//fprintf (stderr, " CRC = %04X %04X", crc, check);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//fprintf (stderr, " CRC = %04X %04X", crc, check);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//TSBK/LCCH CRC16 x-bit bridge to crc16b and crc16b_okay, wip, may need multi pdu format as well
|
|
||||||
int crc16_lb_bridge (int payload[190], int len)
|
|
||||||
{
|
|
||||||
int err = -2;
|
|
||||||
uint8_t buf[190] = {0};
|
|
||||||
|
|
||||||
for (int i = 0; i < len+16; i++) //add +16 here so we load the entire frame but only run crc on the len portion
|
|
||||||
{
|
|
||||||
buf[i] = payload[i];
|
|
||||||
}
|
|
||||||
err = crc16_ok(buf, len);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
//borrowing crc12 from OP25
|
|
||||||
static uint16_t crc12(const uint8_t bits[], unsigned int len) {
|
|
||||||
uint16_t crc=0;
|
|
||||||
static const unsigned int K = 12;
|
|
||||||
//g12(x) = x12 + x11 + x7 + x4 + x2 + x + 1
|
|
||||||
static const uint8_t poly[13] = {1,1,0,0,0,1,0,0,1,0,1,1,1}; // p25 p2 crc 12 poly
|
|
||||||
uint8_t buf[256];
|
|
||||||
if (len+K > sizeof(buf)) {
|
|
||||||
//fprintf (stderr, "crc12: buffer length %u exceeds maximum %u\n", 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 ^ 0xfff;
|
|
||||||
}
|
|
||||||
|
|
||||||
//borrowing crc12_ok from OP25
|
|
||||||
static uint16_t crc12_ok(const uint8_t bits[], unsigned int len) {
|
|
||||||
uint16_t crc = 0;
|
|
||||||
for (int i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
crc = crc << 1;
|
|
||||||
crc = crc | bits[i+len];
|
|
||||||
}
|
|
||||||
uint16_t check = crc12(bits,len);
|
|
||||||
|
|
||||||
if (crc == check)
|
|
||||||
{
|
|
||||||
//fprintf (stderr, " CRC = %03X %03X", crc, check);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//fprintf (stderr, " CRC = %03X %03X", crc, check);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//xCCH CRC12 x-bit bridge to crc12b and crc12b_okay
|
|
||||||
int crc12_xb_bridge (int payload[190], int len)
|
|
||||||
{
|
|
||||||
int err = -5;
|
|
||||||
uint8_t buf[190] = {0};
|
|
||||||
|
|
||||||
//need to load up the 12 crc bits as well, else it will fail on the check, but not on the crc calc
|
|
||||||
for (int i = 0; i < len+12; i++)
|
|
||||||
{
|
|
||||||
buf[i] = payload[i];
|
|
||||||
}
|
|
||||||
err = crc12_ok(buf, len);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t lsd_parity[256] = {
|
|
||||||
0x00, 0x39, 0x72, 0x4B, 0xE4, 0xDD, 0x96, 0xAF, 0xF1, 0xC8, 0x83, 0xBA, 0x15, 0x2C, 0x67, 0x5E,
|
|
||||||
0xDB, 0xE2, 0xA9, 0x90, 0x3F, 0x06, 0x4D, 0x74, 0x2A, 0x13, 0x58, 0x61, 0xCE, 0xF7, 0xBC, 0x85,
|
|
||||||
0x8F, 0xB6, 0xFD, 0xC4, 0x6B, 0x52, 0x19, 0x20, 0x7E, 0x47, 0x0C, 0x35, 0x9A, 0xA3, 0xE8, 0xD1,
|
|
||||||
0x54, 0x6D, 0x26, 0x1F, 0xB0, 0x89, 0xC2, 0xFB, 0xA5, 0x9C, 0xD7, 0xEE, 0x41, 0x78, 0x33, 0x0A,
|
|
||||||
0x27, 0x1E, 0x55, 0x6C, 0xC3, 0xFA, 0xB1, 0x88, 0xD6, 0xEF, 0xA4, 0x9D, 0x32, 0x0B, 0x40, 0x79,
|
|
||||||
0xFC, 0xC5, 0x8E, 0xB7, 0x18, 0x21, 0x6A, 0x53, 0x0D, 0x34, 0x7F, 0x46, 0xE9, 0xD0, 0x9B, 0xA2,
|
|
||||||
0xA8, 0x91, 0xDA, 0xE3, 0x4C, 0x75, 0x3E, 0x07, 0x59, 0x60, 0x2B, 0x12, 0xBD, 0x84, 0xCF, 0xF6,
|
|
||||||
0x73, 0x4A, 0x01, 0x38, 0x97, 0xAE, 0xE5, 0xDC, 0x82, 0xBB, 0xF0, 0xC9, 0x66, 0x5F, 0x14, 0x2D,
|
|
||||||
0x4E, 0x77, 0x3C, 0x05, 0xAA, 0x93, 0xD8, 0xE1, 0xBF, 0x86, 0xCD, 0xF4, 0x5B, 0x62, 0x29, 0x10,
|
|
||||||
0x95, 0xAC, 0xE7, 0xDE, 0x71, 0x48, 0x03, 0x3A, 0x64, 0x5D, 0x16, 0x2F, 0x80, 0xB9, 0xF2, 0xCB,
|
|
||||||
0xC1, 0xF8, 0xB3, 0x8A, 0x25, 0x1C, 0x57, 0x6E, 0x30, 0x09, 0x42, 0x7B, 0xD4, 0xED, 0xA6, 0x9F,
|
|
||||||
0x1A, 0x23, 0x68, 0x51, 0xFE, 0xC7, 0x8C, 0xB5, 0xEB, 0xD2, 0x99, 0xA0, 0x0F, 0x36, 0x7D, 0x44,
|
|
||||||
0x69, 0x50, 0x1B, 0x22, 0x8D, 0xB4, 0xFF, 0xC6, 0x98, 0xA1, 0xEA, 0xD3, 0x7C, 0x45, 0x0E, 0x37,
|
|
||||||
0xB2, 0x8B, 0xC0, 0xF9, 0x56, 0x6F, 0x24, 0x1D, 0x43, 0x7A, 0x31, 0x08, 0xA7, 0x9E, 0xD5, 0xEC,
|
|
||||||
0xE6, 0xDF, 0x94, 0xAD, 0x02, 0x3B, 0x70, 0x49, 0x17, 0x2E, 0x65, 0x5C, 0xF3, 0xCA, 0x81, 0xB8,
|
|
||||||
0x3D, 0x04, 0x4F, 0x76, 0xD9, 0xE0, 0xAB, 0x92, 0xCC, 0xF5, 0xBE, 0x87, 0x28, 0x11, 0x5A, 0x63};
|
|
||||||
|
|
||||||
int p25p1_lsd_fec(uint8_t * input)
|
|
||||||
{
|
|
||||||
uint8_t lsd = (uint8_t)ConvertBitIntoBytes(&input[0], 8);
|
|
||||||
uint8_t par = (uint8_t)ConvertBitIntoBytes(&input[8], 8);
|
|
||||||
uint8_t chk = lsd_parity[lsd];
|
|
||||||
//NOTE: Simply checking the parity doesn't account for the parity bits being bad, but the
|
|
||||||
//low speed data bits being correct, but is better than nothing
|
|
||||||
if (chk == par) return 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//TODO: some FEC functions
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
//P25
|
//P25
|
||||||
long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channel)
|
long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channel)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
//RX and SU TX frequencies.
|
//RX and SU TX frequencies.
|
||||||
//SU RX = (Base Frequency) + (Channel Number) x (Channel Spacing).
|
//SU RX = (Base Frequency) + (Channel Number) x (Channel Spacing).
|
||||||
@@ -62,8 +61,6 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
|
|||||||
|
|
||||||
long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t channel)
|
long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t channel)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
long int freq;
|
long int freq;
|
||||||
long int base = 0;
|
long int base = 0;
|
||||||
long int step = 0;
|
long int step = 0;
|
||||||
|
|||||||
126
src/p25_lcw.c
126
src/p25_lcw.c
@@ -11,15 +11,12 @@
|
|||||||
//new p25_lcw function here -- TIA-102.AABF-D LCW Format Messages (if anybody wants to fill the rest out)
|
//new p25_lcw function here -- TIA-102.AABF-D LCW Format Messages (if anybody wants to fill the rest out)
|
||||||
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors)
|
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors)
|
||||||
{
|
{
|
||||||
UNUSED(irrecoverable_errors);
|
|
||||||
|
|
||||||
uint8_t lc_format = (uint8_t)ConvertBitIntoBytes(&LCW_bits[0], 8); //format
|
uint8_t lc_format = (uint8_t)ConvertBitIntoBytes(&LCW_bits[0], 8); //format
|
||||||
uint8_t lc_opcode = (uint8_t)ConvertBitIntoBytes(&LCW_bits[2], 6); //opcode portion of format
|
uint8_t lc_opcode = (uint8_t)ConvertBitIntoBytes(&LCW_bits[2], 8); //opcode portion of format
|
||||||
uint8_t lc_mfid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8); //mfid
|
uint8_t lc_mfid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8); //mfid
|
||||||
uint8_t lc_svcopt = (uint8_t)ConvertBitIntoBytes(&LCW_bits[16], 8); //service options
|
uint8_t lc_svcopt = (uint8_t)ConvertBitIntoBytes(&LCW_bits[16], 8); //service options
|
||||||
uint8_t lc_pf = LCW_bits[0]; //protect flag
|
uint8_t lc_pf = LCW_bits[0]; //protect flag
|
||||||
uint8_t lc_sf = LCW_bits[1]; //Implicit / Explicit MFID Format
|
uint8_t lc_sf = LCW_bits[1]; //Implicit / Explicit MFID Format
|
||||||
UNUSED2(lc_opcode, lc_sf);
|
|
||||||
|
|
||||||
if (lc_pf == 1) //check the protect flag -- if set, its an encrypted lcw
|
if (lc_pf == 1) //check the protect flag -- if set, its an encrypted lcw
|
||||||
{
|
{
|
||||||
@@ -63,7 +60,6 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
uint16_t group = (uint16_t)ConvertBitIntoBytes(&LCW_bits[32], 16);
|
uint16_t group = (uint16_t)ConvertBitIntoBytes(&LCW_bits[32], 16);
|
||||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
|
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
|
||||||
fprintf (stderr, " - Group %d Source %d", group, source);
|
fprintf (stderr, " - Group %d Source %d", group, source);
|
||||||
UNUSED2(res, explicit);
|
|
||||||
|
|
||||||
//don't set this when zero, annoying blink occurs in ncurses
|
//don't set this when zero, annoying blink occurs in ncurses
|
||||||
if (group != 0) state->lasttg = group;
|
if (group != 0) state->lasttg = group;
|
||||||
@@ -93,9 +89,7 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Allow Tuning from Call Grants either in LDU1 or TDULC? (TDMA to p1 fallback?)
|
//uses explicit bit?
|
||||||
//TODO: Allow TG Hold overrides here either in LDU1 or TDULC?
|
|
||||||
//NOTE: If we have an active TG hold, we really should't be here anyways
|
|
||||||
else if (lc_format == 0x42) //is this group only, or group and private?
|
else if (lc_format == 0x42) //is this group only, or group and private?
|
||||||
{
|
{
|
||||||
fprintf (stderr, " Group Voice Channel Update - ");
|
fprintf (stderr, " Group Voice Channel Update - ");
|
||||||
@@ -127,7 +121,6 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
|
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
|
||||||
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
|
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
|
||||||
fprintf (stderr, "Ch: %04X TG: %d; ", channelt, group1);
|
fprintf (stderr, "Ch: %04X TG: %d; ", channelt, group1);
|
||||||
UNUSED(channelr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (lc_format == 0x45)
|
else if (lc_format == 0x45)
|
||||||
@@ -193,6 +186,20 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
fprintf (stderr, " Call Alert");
|
fprintf (stderr, " Call Alert");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (lc_format == 0x57)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Extended Function Command");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (lc_format == 0x58)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Channel Identifier Update");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (lc_format == 0x59)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Channel Identifier Update VU");
|
||||||
|
}
|
||||||
|
|
||||||
else if (lc_format == 0x5A)
|
else if (lc_format == 0x5A)
|
||||||
{
|
{
|
||||||
@@ -250,7 +257,6 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[48], 16);
|
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[48], 16);
|
||||||
uint8_t cfva = (uint8_t)ConvertBitIntoBytes(&LCW_bits[64], 4);
|
uint8_t cfva = (uint8_t)ConvertBitIntoBytes(&LCW_bits[64], 4);
|
||||||
fprintf (stderr, " - RFSS %d Site %d CH %04X", rfssid, siteid, channelt);
|
fprintf (stderr, " - RFSS %d Site %d CH %04X", rfssid, siteid, channelt);
|
||||||
UNUSED2(lra, channelr);
|
|
||||||
|
|
||||||
//debug print only
|
//debug print only
|
||||||
// fprintf (stderr, "\n ");
|
// fprintf (stderr, "\n ");
|
||||||
@@ -259,7 +265,7 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
// if (cfva & 0x4) fprintf (stderr, " Failure Condition");
|
// if (cfva & 0x4) fprintf (stderr, " Failure Condition");
|
||||||
// if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
|
// if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
|
||||||
// else fprintf (stderr, " Last Known");
|
// else fprintf (stderr, " Last Known");
|
||||||
if (cfva & 0x1) fprintf (stderr, " - Connection Active");
|
if (cfva & 0x1) fprintf (stderr, "- Connection Active");
|
||||||
// process_channel_to_freq (opts, state, channelt);
|
// process_channel_to_freq (opts, state, channelt);
|
||||||
//end debug, way too much for a simple link control line
|
//end debug, way too much for a simple link control line
|
||||||
|
|
||||||
@@ -289,19 +295,12 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
//tune back to CC here - save about 1-2 seconds
|
//tune back to CC here - save about 1-2 seconds
|
||||||
else if (lc_format == 0x4F) //# Call Termination/Cancellation
|
else if (lc_format == 0x4F) //# Call Termination/Cancellation
|
||||||
{
|
{
|
||||||
uint32_t tgt = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24); //can be individual, or all units (0xFFFFFF)
|
fprintf (stderr, " Call Termination");
|
||||||
fprintf (stderr, " Call Termination; TGT: %d;", tgt);
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
||||||
//Will we need to check for a symbolrate change here, can a P25p2 TDMA-CC system
|
//Will we need to check for a symbolrate change here, can a P25p2 TDMA-CC system
|
||||||
//revert back to a phase 1 traffic channel or carry a phase 1 traffic channel?
|
//revert back to a phase 1 traffic channel or carry a phase 1 traffic channel?
|
||||||
if (state->p25_cc_is_tdma == 1)
|
|
||||||
{
|
|
||||||
state->samplesPerSymbol = 8;
|
|
||||||
state->symbolCenter = 3;
|
|
||||||
opts->frame_p25p1 = 0; //turn it back off
|
|
||||||
}
|
|
||||||
|
|
||||||
//clear heuristics from current traffic channel
|
//clear heuristics from current traffic channel
|
||||||
if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1)
|
if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1)
|
||||||
@@ -310,10 +309,6 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||||||
}
|
}
|
||||||
|
|
||||||
//re-enable both slots (failsafe)
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
opts->slot2_on = 1;
|
|
||||||
|
|
||||||
//rigctl
|
//rigctl
|
||||||
if (opts->use_rigctl == 1)
|
if (opts->use_rigctl == 1)
|
||||||
{
|
{
|
||||||
@@ -357,90 +352,8 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
else fprintf (stderr, " Unknown Format %02X MFID %02X SVC %02X", lc_format, lc_mfid, lc_svcopt);
|
else fprintf (stderr, " Unknown Format %02X MFID %02X SVC %02X", lc_format, lc_mfid, lc_svcopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Look through all LCW format messages and move here if they don't use the MFID field
|
|
||||||
//just going to add/fix a few values I've observed for now, one issue with doing so may
|
|
||||||
//be where there is a reserved field that is also used as an MFID, i.e., Call Termination 0xF vs Moto Talker EOT 0xF with
|
|
||||||
//the reserved field showing the 0x90 for moto in it, and Harris 0xA vs Unit to Unit Voice Call 0xA
|
|
||||||
|
|
||||||
//TODO: Add Identification of Special SU Address values
|
|
||||||
//0 - No Unit
|
|
||||||
//1-0xFFFFFB - Assignable Units
|
|
||||||
//0xFFFFFC - FNE 16777212
|
|
||||||
//0xFFFFFD - System Default (FNE Calling Functions, Registration, Mobility)
|
|
||||||
//0xFFFFFE - Registration Default (registration transactions from SU)
|
|
||||||
//0xFFFFFF - All Units
|
|
||||||
|
|
||||||
//This lc_format doesn't use the MFID field
|
|
||||||
else if (lc_format == 0x42)
|
|
||||||
fprintf (stderr, " Conventional Fallback Indication");
|
|
||||||
|
|
||||||
//This lc_format doesn't use the MFID field
|
|
||||||
else if (lc_format == 0x57)
|
|
||||||
fprintf (stderr, " Extended Function Command");
|
|
||||||
|
|
||||||
//This lc_format doesn't use the MFID field
|
|
||||||
else if (lc_format == 0x58)
|
|
||||||
{
|
|
||||||
uint8_t iden = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 4);
|
|
||||||
uint32_t base = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 32);
|
|
||||||
fprintf (stderr, " Channel Identifier Update VU; Iden: %X; Base: %d;", iden, base*5);
|
|
||||||
}
|
|
||||||
|
|
||||||
//This lc_format doesn't use the MFID field
|
|
||||||
else if (lc_format == 0x59)
|
|
||||||
{
|
|
||||||
uint8_t iden = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 4);
|
|
||||||
uint32_t base = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 32);
|
|
||||||
fprintf (stderr, " Channel Identifier Update VU; Iden: %X; Base: %d;", iden, base*5);
|
|
||||||
}
|
|
||||||
|
|
||||||
//This lc_format doesn't use the MFID field
|
|
||||||
else if (lc_format == 0x63)
|
|
||||||
fprintf (stderr, " RFSS Status Broadcast");
|
|
||||||
|
|
||||||
//MFID 90 Embedded GPS
|
|
||||||
else if (lc_mfid == 0x90 && lc_opcode == 0x6)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " MFID90 (Moto)");
|
|
||||||
apx_embedded_gps (opts, state, LCW_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (lc_mfid == 0x90 && lc_opcode == 0x0)
|
|
||||||
fprintf (stderr, " MFID90 (Moto) Group Regroup Channel User (LCGRGR)");
|
|
||||||
|
|
||||||
else if (lc_mfid == 0x90 && lc_opcode == 0x1)
|
|
||||||
fprintf (stderr, " MFID90 (Moto) Group Regroup Channel Update (LCGRGU)");
|
|
||||||
|
|
||||||
else if (lc_mfid == 0x90 && lc_opcode == 0x3)
|
|
||||||
fprintf (stderr, " MFID90 (Moto) Group Regroup Add");
|
|
||||||
|
|
||||||
else if (lc_mfid == 0x90 && lc_opcode == 0x4)
|
|
||||||
fprintf (stderr, " MFID90 (Moto) Group Regroup Delete");
|
|
||||||
|
|
||||||
else if (lc_mfid == 0x90 && lc_opcode == 0xF)
|
|
||||||
{
|
|
||||||
uint32_t src = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
|
|
||||||
fprintf (stderr, " MFID90 (Moto) Talker EOT; SRC: %d;", src);
|
|
||||||
}
|
|
||||||
|
|
||||||
//observed format value on Harris SNDCP data channel (Phase 2 CC to Phase 1 MPDU channel)
|
|
||||||
else if (lc_mfid == 0xA4 && lc_format == 0x0A)
|
|
||||||
{
|
|
||||||
//Could also just be a Unit to Unit Voice Channel User using the reserved field as the MFID?
|
|
||||||
//if it were similar to Unit to Unit though, the TGT and SRC values seem to be reversed
|
|
||||||
//this appears to be a data channel indicator, has a matching target and the FNE address in it
|
|
||||||
uint32_t src = (uint32_t)ConvertBitIntoBytes(&LCW_bits[24], 24);
|
|
||||||
uint32_t tgt = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
|
|
||||||
fprintf (stderr, " MFIDA4 (Harris) Data Channel; SRC: %d; TGT: %d;", src, tgt);
|
|
||||||
}
|
|
||||||
|
|
||||||
//not a duplicate, this one will print if not MFID 0 or 1
|
//not a duplicate, this one will print if not MFID 0 or 1
|
||||||
else
|
else fprintf (stderr, " Unknown Format %02X MFID %02X ", lc_format, lc_mfid);
|
||||||
{
|
|
||||||
fprintf (stderr, " Unknown Format %02X MFID %02X ", lc_format, lc_mfid);
|
|
||||||
if (lc_mfid == 0x90) fprintf (stderr, "(Moto)");
|
|
||||||
else if (lc_mfid == 0xA4) fprintf (stderr, "(Harris)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//ending line break
|
//ending line break
|
||||||
@@ -448,4 +361,3 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
277
src/p25p1_block.cpp
Normal file
277
src/p25p1_block.cpp
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* p25p1_block.c
|
||||||
|
* P25 Block Bridge for TSBK Deinterleaving, CRC12 and CRC16 checks
|
||||||
|
*
|
||||||
|
* original copyrights for portions used below (OP25, Ossman, and LEH)
|
||||||
|
*
|
||||||
|
* LWVMOBILE
|
||||||
|
* 2022-09 DSD-FME Florida Man Edition
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
typedef std::vector<bool> bit_vector;
|
||||||
|
|
||||||
|
/* adapted from wireshark/plugins/p25/packet-p25cai.c */
|
||||||
|
/* Copyright 2008, Michael Ossmann <mike@ossmann.com> */
|
||||||
|
/* deinterleave and trellis1_2 decoding, count_bits, and find_min*/
|
||||||
|
/* buf is assumed to be a buffer of 12 bytes */
|
||||||
|
|
||||||
|
//typedef std::vector<bool> bit_vector;
|
||||||
|
|
||||||
|
//ugly copy and paste below
|
||||||
|
static int count_bits(unsigned int n) {
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; n != 0; i++)
|
||||||
|
n &= n - 1;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_min(uint8_t list[], int len) {
|
||||||
|
int min = list[0];
|
||||||
|
int index = 0;
|
||||||
|
int unique = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < len; i++) {
|
||||||
|
if (list[i] < min) {
|
||||||
|
min = list[i];
|
||||||
|
index = i;
|
||||||
|
unique = 1;
|
||||||
|
} else if (list[i] == min) {
|
||||||
|
//unique = 0;
|
||||||
|
; //do nothing, still can be correct and pass CRC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* return -1 if a minimum can't be found */
|
||||||
|
if (!unique)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int block_deinterleave(bit_vector& bv, unsigned int start, uint8_t* buf)
|
||||||
|
{
|
||||||
|
static const uint16_t deinterleave_tb[] = {
|
||||||
|
0, 1, 2, 3, 52, 53, 54, 55, 100,101,102,103, 148,149,150,151,
|
||||||
|
4, 5, 6, 7, 56, 57, 58, 59, 104,105,106,107, 152,153,154,155,
|
||||||
|
8, 9, 10, 11, 60, 61, 62, 63, 108,109,110,111, 156,157,158,159,
|
||||||
|
12, 13, 14, 15, 64, 65, 66, 67, 112,113,114,115, 160,161,162,163,
|
||||||
|
16, 17, 18, 19, 68, 69, 70, 71, 116,117,118,119, 164,165,166,167,
|
||||||
|
20, 21, 22, 23, 72, 73, 74, 75, 120,121,122,123, 168,169,170,171,
|
||||||
|
24, 25, 26, 27, 76, 77, 78, 79, 124,125,126,127, 172,173,174,175,
|
||||||
|
28, 29, 30, 31, 80, 81, 82, 83, 128,129,130,131, 176,177,178,179,
|
||||||
|
32, 33, 34, 35, 84, 85, 86, 87, 132,133,134,135, 180,181,182,183,
|
||||||
|
36, 37, 38, 39, 88, 89, 90, 91, 136,137,138,139, 184,185,186,187,
|
||||||
|
40, 41, 42, 43, 92, 93, 94, 95, 140,141,142,143, 188,189,190,191,
|
||||||
|
44, 45, 46, 47, 96, 97, 98, 99, 144,145,146,147, 192,193,194,195,
|
||||||
|
48, 49, 50, 51 };
|
||||||
|
|
||||||
|
uint8_t hd[4];
|
||||||
|
int b, d, j;
|
||||||
|
int state = 0;
|
||||||
|
uint8_t codeword;
|
||||||
|
|
||||||
|
static const uint8_t next_words[4][4] = {
|
||||||
|
{0x2, 0xC, 0x1, 0xF},
|
||||||
|
{0xE, 0x0, 0xD, 0x3},
|
||||||
|
{0x9, 0x7, 0xA, 0x4},
|
||||||
|
{0x5, 0xB, 0x6, 0x8}
|
||||||
|
};
|
||||||
|
|
||||||
|
memset(buf, 0, 12);
|
||||||
|
|
||||||
|
for (b=0; b < 98*2; b += 4) {
|
||||||
|
codeword = (bv[start+deinterleave_tb[b+0]] << 3) +
|
||||||
|
(bv[start+deinterleave_tb[b+1]] << 2) +
|
||||||
|
(bv[start+deinterleave_tb[b+2]] << 1) +
|
||||||
|
bv[start+deinterleave_tb[b+3]] ;
|
||||||
|
|
||||||
|
/* try each codeword in a row of the state transition table */
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
/* find Hamming distance for candidate */
|
||||||
|
hd[j] = count_bits(codeword ^ next_words[state][j]);
|
||||||
|
}
|
||||||
|
/* find the dibit that matches the most codeword bits (minimum Hamming distance) */
|
||||||
|
state = find_min(hd, 4);
|
||||||
|
/* error if minimum can't be found */
|
||||||
|
if(state == -1)
|
||||||
|
return -1; // decode error, return failure
|
||||||
|
/* It also might be nice to report a condition where the minimum is
|
||||||
|
* non-zero, i.e. an error has been corrected. It probably shouldn't
|
||||||
|
* be a permanent failure, though.
|
||||||
|
*
|
||||||
|
* DISSECTOR_ASSERT(hd[state] == 0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* append dibit onto output buffer */
|
||||||
|
d = b >> 2; // dibit ctr
|
||||||
|
if (d < 48) {
|
||||||
|
buf[d >> 2] |= state << (6 - ((d%4) * 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bd_bridge (int payload[196], uint8_t decoded[12])
|
||||||
|
{
|
||||||
|
std::vector<bool> vc(196,0);
|
||||||
|
int ec = 69; //initialize error value
|
||||||
|
|
||||||
|
//gather payload from tsbk handler and pass it to the block_deinterleave function
|
||||||
|
//and then return its payload back to the tsbk handler
|
||||||
|
|
||||||
|
//initialize our decoded byte buffer with zeroes
|
||||||
|
for (int i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
decoded[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert/load payload into a vector vc to pass to block_deinterleave
|
||||||
|
for (int i = 0; i < 196; i++)
|
||||||
|
{
|
||||||
|
vc[i] = payload[i];
|
||||||
|
}
|
||||||
|
int block_count = 0; //
|
||||||
|
unsigned int start = block_count*196;
|
||||||
|
|
||||||
|
ec = block_deinterleave(vc, start, decoded);
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
//modified from the LEH ComputeCrcCCITT to accept variable len buffer bits
|
||||||
|
uint16_t ComputeCrcCCITT16b(const uint8_t buf[], unsigned int len)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
|
||||||
|
/* Polynomial x^16 + x^12 + x^5 + 1
|
||||||
|
* Normal = 0x1021
|
||||||
|
* Reciprocal = 0x0811
|
||||||
|
* Reversed = 0x8408
|
||||||
|
* Reversed reciprocal = 0x8810 */
|
||||||
|
uint16_t Polynome = 0x1021;
|
||||||
|
for(i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if(((CRC >> 15) & 1) ^ (buf[i] & 1))
|
||||||
|
{
|
||||||
|
CRC = (CRC << 1) ^ Polynome;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CRC <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invert the CRC */
|
||||||
|
CRC ^= 0xFFFF;
|
||||||
|
|
||||||
|
/* Return the CRC */
|
||||||
|
return CRC;
|
||||||
|
} /* End ComputeCrcCCITT() */
|
||||||
|
|
||||||
|
|
||||||
|
//modified from crc12_ok to run a quickie on 16 instead
|
||||||
|
static uint16_t crc16_ok(const uint8_t bits[], unsigned int len) {
|
||||||
|
uint16_t crc = 0;
|
||||||
|
// fprintf (stderr, "\n LEN = %d", len);
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
crc = crc << 1;
|
||||||
|
crc = crc | bits[i+len];
|
||||||
|
}
|
||||||
|
// uint16_t check = crc16b(bits,len);
|
||||||
|
uint16_t check = ComputeCrcCCITT16b(bits, len);
|
||||||
|
|
||||||
|
if (crc == check)
|
||||||
|
{
|
||||||
|
//fprintf (stderr, " CRC = %04X %04X", crc, check);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//fprintf (stderr, " CRC = %04X %04X", crc, check);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TSBK/LCCH CRC16 x-bit bridge to crc16b and crc16b_okay, wip, may need multi pdu format as well
|
||||||
|
int crc16_lb_bridge (int payload[190], int len)
|
||||||
|
{
|
||||||
|
int err = -2;
|
||||||
|
uint16_t crc = -2;
|
||||||
|
uint8_t buf[190] = {0};
|
||||||
|
|
||||||
|
for (int i = 0; i < len+16; i++) //add +16 here so we load the entire frame but only run crc on the len portion
|
||||||
|
{
|
||||||
|
buf[i] = payload[i];
|
||||||
|
}
|
||||||
|
err = crc16_ok(buf, len);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
//borrowing crc12 from OP25
|
||||||
|
static uint16_t crc12(const uint8_t bits[], unsigned int len) {
|
||||||
|
uint16_t crc=0;
|
||||||
|
static const unsigned int K = 12;
|
||||||
|
//g12(x) = x12 + x11 + x7 + x4 + x2 + x + 1
|
||||||
|
static const uint8_t poly[K+1] = {1,1,0,0,0,1,0,0,1,0,1,1,1}; // p25 p2 crc 12 poly
|
||||||
|
uint8_t buf[256];
|
||||||
|
if (len+K > sizeof(buf)) {
|
||||||
|
//fprintf (stderr, "crc12: buffer length %u exceeds maximum %u\n", 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 ^ 0xfff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//borrowing crc12_ok from OP25
|
||||||
|
static uint16_t crc12_ok(const uint8_t bits[], unsigned int len) {
|
||||||
|
uint16_t crc = 0;
|
||||||
|
for (int i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
crc = crc << 1;
|
||||||
|
crc = crc | bits[i+len];
|
||||||
|
}
|
||||||
|
uint16_t check = crc12(bits,len);
|
||||||
|
|
||||||
|
if (crc == check)
|
||||||
|
{
|
||||||
|
//fprintf (stderr, " CRC = %03X %03X", crc, check);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//fprintf (stderr, " CRC = %03X %03X", crc, check);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//xCCH CRC12 x-bit bridge to crc12b and crc12b_okay
|
||||||
|
int crc12_xb_bridge (int payload[190], int len)
|
||||||
|
{
|
||||||
|
int err = -5;
|
||||||
|
uint16_t crc = -2;
|
||||||
|
uint8_t buf[190] = {0};
|
||||||
|
|
||||||
|
//need to load up the 12 crc bits as well, else it will fail on the check, but not on the crc calc
|
||||||
|
for (int i = 0; i < len+12; i++)
|
||||||
|
{
|
||||||
|
buf[i] = payload[i];
|
||||||
|
}
|
||||||
|
err = crc12_ok(buf, len);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
@@ -26,7 +26,6 @@ read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count, i
|
|||||||
{
|
{
|
||||||
int dibit;
|
int dibit;
|
||||||
int status;
|
int status;
|
||||||
UNUSED(status);
|
|
||||||
|
|
||||||
if (*status_count == 35) {
|
if (*status_count == 35) {
|
||||||
|
|
||||||
@@ -66,6 +65,7 @@ read_dibit_update_analog_data (dsd_opts* opts, dsd_state* state, char* output, u
|
|||||||
AnalogSignal* analog_signal_array, int* analog_signal_index)
|
AnalogSignal* analog_signal_array, int* analog_signal_index)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
unsigned int debug_left, debug_right;
|
||||||
|
|
||||||
for (i=0; i<count; i+=2)
|
for (i=0; i<count; i+=2)
|
||||||
{
|
{
|
||||||
@@ -215,9 +215,9 @@ correct_golay_dibits_6(char* corrected_hex_data, int hex_count, AnalogSignal* an
|
|||||||
void
|
void
|
||||||
processHDU(dsd_opts* opts, dsd_state* state)
|
processHDU(dsd_opts* opts, dsd_state* state)
|
||||||
{
|
{
|
||||||
uint8_t mi[73];
|
char mi[73], mfid[9], algid[9], kid[17], tgid[17], tmpstr[255];
|
||||||
char mfid[9], algid[9], kid[17], tgid[17];
|
|
||||||
int i, j;
|
int i, j;
|
||||||
|
long talkgroup;
|
||||||
int algidhex, kidhex;
|
int algidhex, kidhex;
|
||||||
char hex[6];
|
char hex[6];
|
||||||
int status_count;
|
int status_count;
|
||||||
@@ -225,7 +225,6 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
|||||||
unsigned long long int mihex1, mihex2, mihex3;
|
unsigned long long int mihex1, mihex2, mihex3;
|
||||||
char hex_data[20][6]; // Data in hex-words (6 bit words). A total of 20 hex words.
|
char hex_data[20][6]; // Data in hex-words (6 bit words). A total of 20 hex words.
|
||||||
char hex_parity[16][6]; // Parity of the data, again in hex-word format. A total of 16 parity hex words.
|
char hex_parity[16][6]; // Parity of the data, again in hex-word format. A total of 16 parity hex words.
|
||||||
UNUSED4(mfid, tgid, status, mihex3);
|
|
||||||
|
|
||||||
int irrecoverable_errors;
|
int irrecoverable_errors;
|
||||||
|
|
||||||
@@ -502,9 +501,5 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
|||||||
fprintf (stderr, " HDU FEC ERR \n");
|
fprintf (stderr, " HDU FEC ERR \n");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,6 +315,7 @@ int estimate_symbol(int rf_mod, P25Heuristics* heuristics, int previous_dibit, i
|
|||||||
static void debug_print_symbol_heuristics(int previous_dibit, int dibit, SymbolHeuristics* sh)
|
static void debug_print_symbol_heuristics(int previous_dibit, int dibit, SymbolHeuristics* sh)
|
||||||
{
|
{
|
||||||
float mean, sd;
|
float mean, sd;
|
||||||
|
int k;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
n = sh->count;
|
n = sh->count;
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count)
|
|||||||
int j, dibit, status;
|
int j, dibit, status;
|
||||||
char imbe_fr[8][23];
|
char imbe_fr[8][23];
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
UNUSED(status);
|
|
||||||
|
|
||||||
w = iW;
|
w = iW;
|
||||||
x = iX;
|
x = iX;
|
||||||
|
|||||||
215
src/p25p1_ldu1.c
215
src/p25p1_ldu1.c
@@ -28,10 +28,10 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
{
|
{
|
||||||
// extracts IMBE frames from LDU frame
|
// extracts IMBE frames from LDU frame
|
||||||
int i;
|
int i;
|
||||||
uint8_t lcformat[9], mfid[9], lcinfo[57];
|
char lcformat[9], mfid[9], lcinfo[57];
|
||||||
char lsd1[9], lsd2[9];
|
char lsd1[9], lsd2[9];
|
||||||
uint8_t lsd_hex1, lsd_hex2; uint8_t lowspeeddata[32]; memset (lowspeeddata, 0, sizeof(lowspeeddata));
|
|
||||||
int status_count; int lsd1_okay, lsd2_okay = 0;
|
int status_count;
|
||||||
|
|
||||||
char hex_data[12][6]; // Data in hex-words (6 bit words). A total of 12 hex words.
|
char hex_data[12][6]; // Data in hex-words (6 bit words). A total of 12 hex words.
|
||||||
char hex_parity[12][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words.
|
char hex_parity[12][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words.
|
||||||
@@ -59,29 +59,12 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '0';
|
state->debug_prefix_2 = '0';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// IMBE 2
|
// IMBE 2
|
||||||
#ifdef TRACE_DSD
|
#ifdef TRACE_DSD
|
||||||
state->debug_prefix_2 = '1';
|
state->debug_prefix_2 = '1';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 2
|
// Read data after IMBE 2
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -94,15 +77,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '2';
|
state->debug_prefix_2 = '2';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 3
|
// Read data after IMBE 3
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -115,15 +89,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '3';
|
state->debug_prefix_2 = '3';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 4
|
// Read data after IMBE 4
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -136,15 +101,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '4';
|
state->debug_prefix_2 = '4';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 5
|
// Read data after IMBE 5
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -157,15 +113,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '5';
|
state->debug_prefix_2 = '5';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 6
|
// Read data after IMBE 6
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -178,15 +125,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '6';
|
state->debug_prefix_2 = '6';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 7
|
// Read data after IMBE 7
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -199,14 +137,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '7';
|
state->debug_prefix_2 = '7';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 8: LSD (low speed data)
|
// Read data after IMBE 8: LSD (low speed data)
|
||||||
{
|
{
|
||||||
@@ -221,14 +151,9 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
{
|
{
|
||||||
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
||||||
}
|
}
|
||||||
lsd_hex1 = 0;
|
|
||||||
for (i=0; i<8; i++)
|
for (i=0; i<8; i++)
|
||||||
{
|
{
|
||||||
lsd_hex1 = lsd_hex1 << 1;
|
|
||||||
lsd1[i] = lsd[i] + '0';
|
lsd1[i] = lsd[i] + '0';
|
||||||
lsd_hex1 |= (uint8_t)lsd[i];
|
|
||||||
lowspeeddata[i+0] = (uint8_t)lsd1[i];
|
|
||||||
lowspeeddata[i+8] = (uint8_t)cyclic_parity[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<=6; i+=2)
|
for (i=0; i<=6; i+=2)
|
||||||
@@ -239,18 +164,13 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
{
|
{
|
||||||
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
||||||
}
|
}
|
||||||
lsd_hex2 = 0;
|
|
||||||
for (i=0; i<8; i++)
|
for (i=0; i<8; i++)
|
||||||
{
|
{
|
||||||
lsd_hex2 = lsd_hex2 << 1;
|
|
||||||
lsd2[i] = lsd[i] + '0';
|
lsd2[i] = lsd[i] + '0';
|
||||||
lsd_hex2 |= (uint8_t)lsd[i];
|
|
||||||
lowspeeddata[i+16] = (uint8_t)lsd2[i];
|
|
||||||
lowspeeddata[i+24] = (uint8_t)cyclic_parity[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: error correction of the LSD bytes... <--THIS!
|
// TODO: error correction of the LSD bytes...
|
||||||
// TODO: do something useful with the LSD bytes... <--THIS!
|
// TODO: do something useful with the LSD bytes...
|
||||||
|
|
||||||
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
||||||
}
|
}
|
||||||
@@ -260,14 +180,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
state->debug_prefix_2 = '8';
|
state->debug_prefix_2 = '8';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
@@ -284,7 +196,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
int status;
|
int status;
|
||||||
status = getDibit (opts, state) + '0';
|
status = getDibit (opts, state) + '0';
|
||||||
// TODO: do something useful with the status bits...
|
// TODO: do something useful with the status bits...
|
||||||
UNUSED(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error correct the hex_data using Reed-Solomon hex_parity
|
// Error correct the hex_data using Reed-Solomon hex_parity
|
||||||
@@ -453,17 +364,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
fprintf (stderr, "%s\n", KNRM);
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: LSD is also encrypted if voice is encrypted, so let's just zip it for now
|
|
||||||
if (state->payload_algid != 0x80)
|
|
||||||
{
|
|
||||||
lsd_hex1 = 0;
|
|
||||||
lsd_hex2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//WIP: LSD FEC
|
|
||||||
lsd1_okay = p25p1_lsd_fec (lowspeeddata+0);
|
|
||||||
lsd2_okay = p25p1_lsd_fec (lowspeeddata+16);
|
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s",KCYN);
|
fprintf (stderr, "%s",KCYN);
|
||||||
@@ -472,110 +372,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "[%02X]", LCW_bytes[i]);
|
fprintf (stderr, "[%02X]", LCW_bytes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SOFTID
|
|
||||||
//view Low Speed Data
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, " LSD: %02X %02X ", lsd_hex1, lsd_hex2);
|
|
||||||
if ( (lsd_hex1 > 0x19) && (lsd_hex1 < 0x7F) && (lsd1_okay == 1) ) fprintf (stderr, "(%c", lsd_hex1);
|
|
||||||
else fprintf (stderr, "( ");
|
|
||||||
if ( (lsd_hex2 > 0x19) && (lsd_hex2 < 0x7F) && (lsd2_okay == 1) ) fprintf (stderr, "%c)", lsd_hex2);
|
|
||||||
else fprintf (stderr, " )");
|
|
||||||
if (lsd1_okay == 0) fprintf (stderr, " L1 ERR");
|
|
||||||
if (lsd2_okay == 0) fprintf (stderr, " L2 ERR");
|
|
||||||
#endif
|
|
||||||
fprintf (stderr, "%s\n", KNRM);
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
}
|
}
|
||||||
#ifdef SOFTID
|
|
||||||
//TEST: Store LSD into array if 0x02 0x08 (opcode and len?)
|
|
||||||
int k = 0;
|
|
||||||
if (state->dmr_alias_format[0] == 0x02)
|
|
||||||
{
|
|
||||||
k = state->data_block_counter[0];
|
|
||||||
if ( (lsd_hex1 > 0x19) && (lsd_hex1 < 0x7F) && (lsd1_okay == 1) )
|
|
||||||
state->dmr_alias_block_segment[0][0][k/4][k%4] = (char)lsd_hex1;
|
|
||||||
// else state->dmr_alias_block_segment[0][0][k/4][k%4] = 0x20;
|
|
||||||
k++;
|
|
||||||
if ( (lsd_hex2 > 0x19) && (lsd_hex2 < 0x7F) && (lsd2_okay == 1) )
|
|
||||||
state->dmr_alias_block_segment[0][0][k/4][k%4] = (char)lsd_hex2;
|
|
||||||
// else state->dmr_alias_block_segment[0][0][k/4][k%4] = 0x20;
|
|
||||||
k++;
|
|
||||||
state->data_block_counter[0] = k;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset format, len, counter.
|
|
||||||
if (lsd_hex1 == 0x02 && lsd1_okay == 1 && lsd2_okay == 1)
|
|
||||||
{
|
|
||||||
state->dmr_alias_format[0] = 0x02;
|
|
||||||
if (lsd_hex2 > 8) lsd_hex2 = 8; //sanity check
|
|
||||||
state->dmr_alias_len[0] = lsd_hex2;
|
|
||||||
state->data_block_counter[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (k >= state->dmr_alias_len[0]) && (state->dmr_alias_format[0] == 0x02) )
|
|
||||||
{
|
|
||||||
//storage for completed string
|
|
||||||
char str[16]; int wr = 0; int tsrc = state->lastsrc; int z = 0; k = 0;
|
|
||||||
for (i = 0; i < 16; i++) str[i] = 0;
|
|
||||||
|
|
||||||
//print out what we've gathered
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, " LSD Soft ID: ");
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%c", state->dmr_alias_block_segment[0][0][i][j]);
|
|
||||||
if (state->dmr_alias_block_segment[0][0][i][j] != 0) str[k++] = state->dmr_alias_block_segment[0][0][i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " STR: %s", str);
|
|
||||||
|
|
||||||
//assign to tg name string, but only if not trunking (this could clash with ENC LO functionality)
|
|
||||||
if (tsrc != 0) //&& opts->p25_trunk == 0 //should never get here if enc, should be zeroed out, but could potentially slip if HDU is missed and offchance of 02 opcode
|
|
||||||
{
|
|
||||||
for (int x = 0; x < state->group_tally; x++)
|
|
||||||
{
|
|
||||||
if (state->group_array[x].groupNumber == tsrc)
|
|
||||||
{
|
|
||||||
wr = 1; //already in there, so no need to assign it
|
|
||||||
z = x;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if not already in there, so save it there now
|
|
||||||
if (wr == 0)
|
|
||||||
{
|
|
||||||
state->group_array[state->group_tally].groupNumber = tsrc;
|
|
||||||
if (state->payload_algid != 0x80 && opts->trunk_tune_enc_calls == 0 && state->R == 0)
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
|
||||||
else
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "D");
|
|
||||||
sprintf (state->group_array[state->group_tally].groupName, "%s", str);
|
|
||||||
state->group_tally++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if its in there, but doesn't match (bad/partial decode)
|
|
||||||
else if (strcmp(str, state->group_array[z].groupName) != 0)
|
|
||||||
{
|
|
||||||
state->group_array[z].groupNumber = tsrc;
|
|
||||||
if (state->payload_algid != 0x80 && opts->trunk_tune_enc_calls == 0 && state->R == 0)
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
|
||||||
else
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "D");
|
|
||||||
sprintf (state->group_array[z].groupName, "%s", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s",KNRM);
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
UNUSED2(lsd1_okay, lsd2_okay);
|
|
||||||
#endif //SOFTID
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
230
src/p25p1_ldu2.c
230
src/p25p1_ldu2.c
@@ -28,14 +28,11 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
// extracts IMBE frames from LDU frame
|
// extracts IMBE frames from LDU frame
|
||||||
int i;
|
int i;
|
||||||
uint8_t mi[73];
|
char mi[73], algid[9], kid[17];
|
||||||
char algid[9], kid[17];
|
|
||||||
char lsd1[9], lsd2[9];
|
char lsd1[9], lsd2[9];
|
||||||
int algidhex, kidhex;
|
int algidhex, kidhex;
|
||||||
uint8_t lsd_hex1, lsd_hex2; uint8_t lowspeeddata[32]; memset (lowspeeddata, 0, sizeof(lowspeeddata));
|
|
||||||
unsigned long long int mihex1, mihex2, mihex3;
|
unsigned long long int mihex1, mihex2, mihex3;
|
||||||
int status_count; int lsd1_okay, lsd2_okay = 0;
|
int status_count;
|
||||||
UNUSED(mihex3);
|
|
||||||
|
|
||||||
char hex_data[16][6]; // Data in hex-words (6 bit words). A total of 16 hex words.
|
char hex_data[16][6]; // Data in hex-words (6 bit words). A total of 16 hex words.
|
||||||
char hex_parity[8][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words.
|
char hex_parity[8][6]; // Parity of the data, again in hex-word format. A total of 12 parity hex words.
|
||||||
@@ -64,29 +61,12 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '0';
|
state->debug_prefix_2 = '0';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// IMBE 2
|
// IMBE 2
|
||||||
#ifdef TRACE_DSD
|
#ifdef TRACE_DSD
|
||||||
state->debug_prefix_2 = '1';
|
state->debug_prefix_2 = '1';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 2
|
// Read data after IMBE 2
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -99,15 +79,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '2';
|
state->debug_prefix_2 = '2';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 3
|
// Read data after IMBE 3
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -120,15 +91,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '3';
|
state->debug_prefix_2 = '3';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 4
|
// Read data after IMBE 4
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -141,15 +103,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '4';
|
state->debug_prefix_2 = '4';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 5
|
// Read data after IMBE 5
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -162,15 +115,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '5';
|
state->debug_prefix_2 = '5';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 6
|
// Read data after IMBE 6
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -183,13 +127,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '6';
|
state->debug_prefix_2 = '6';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 7
|
// Read data after IMBE 7
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index);
|
||||||
@@ -202,15 +139,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '7';
|
state->debug_prefix_2 = '7';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
// Read data after IMBE 8: LSD (low speed data)
|
// Read data after IMBE 8: LSD (low speed data)
|
||||||
{
|
{
|
||||||
char lsd[8];
|
char lsd[8];
|
||||||
@@ -224,14 +152,9 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
||||||
}
|
}
|
||||||
lsd_hex1 = 0;
|
|
||||||
for (i=0; i<8; i++)
|
for (i=0; i<8; i++)
|
||||||
{
|
{
|
||||||
lsd_hex1 = lsd_hex1 << 1;
|
|
||||||
lsd1[i] = lsd[i] + '0';
|
lsd1[i] = lsd[i] + '0';
|
||||||
lsd_hex1 |= (uint8_t)lsd[i];
|
|
||||||
lowspeeddata[i+0] = (uint8_t)lsd1[i];
|
|
||||||
lowspeeddata[i+8] = (uint8_t)cyclic_parity[i];;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<=6; i+=2)
|
for (i=0; i<=6; i+=2)
|
||||||
@@ -242,18 +165,13 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
read_dibit(opts, state, cyclic_parity+i, &status_count, NULL, NULL);
|
||||||
}
|
}
|
||||||
lsd_hex2 = 0;
|
|
||||||
for (i=0; i<8; i++)
|
for (i=0; i<8; i++)
|
||||||
{
|
{
|
||||||
lsd_hex2 = lsd_hex2 << 1;
|
|
||||||
lsd2[i] = lsd[i] + '0';
|
lsd2[i] = lsd[i] + '0';
|
||||||
lsd_hex2 |= (uint8_t)lsd[i];
|
|
||||||
lowspeeddata[i+16] = (uint8_t)lsd2[i];
|
|
||||||
lowspeeddata[i+24] = (uint8_t)cyclic_parity[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: error correction of the LSD bytes... <--THIS!
|
// TODO: error correction of the LSD bytes...
|
||||||
// TODO: do something useful with the LSD bytes... <--THIS!
|
// TODO: do something useful with the LSD bytes...
|
||||||
|
|
||||||
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
||||||
}
|
}
|
||||||
@@ -263,14 +181,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
state->debug_prefix_2 = '8';
|
state->debug_prefix_2 = '8';
|
||||||
#endif
|
#endif
|
||||||
process_IMBE (opts, state, &status_count);
|
process_IMBE (opts, state, &status_count);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
|
|
||||||
//set vc counter to 0
|
//set vc counter to 0
|
||||||
state->p25vc = 0;
|
state->p25vc = 0;
|
||||||
@@ -293,7 +203,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
int status;
|
int status;
|
||||||
status = getDibit (opts, state) + '0';
|
status = getDibit (opts, state) + '0';
|
||||||
// TODO: do something useful with the status bits...
|
// TODO: do something useful with the status bits...
|
||||||
UNUSED(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error correct the hex_data using Reed-Solomon hex_parity
|
// Error correct the hex_data using Reed-Solomon hex_parity
|
||||||
@@ -459,17 +368,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||||
|
|
||||||
//NOTE: LSD is also encrypted if voice is encrypted, so let's just zip it for now
|
|
||||||
if (state->payload_algid != 0x80)
|
|
||||||
{
|
|
||||||
lsd_hex1 = 0;
|
|
||||||
lsd_hex2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//WIP: LSD FEC
|
|
||||||
lsd1_okay = p25p1_lsd_fec (lowspeeddata+0);
|
|
||||||
lsd2_okay = p25p1_lsd_fec (lowspeeddata+16);
|
|
||||||
|
|
||||||
if (irrecoverable_errors == 0)
|
if (irrecoverable_errors == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
@@ -496,130 +394,16 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, " ENC");
|
fprintf (stderr, " ENC");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf (stderr, " LDU2 FEC ERR ");
|
fprintf (stderr, " LDU2 FEC ERR \n");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SOFTID
|
|
||||||
if (opts->payload == 1)
|
|
||||||
{
|
|
||||||
//view Low Speed Data
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, " LSD: %02X %02X ", lsd_hex1, lsd_hex2);
|
|
||||||
if ( (lsd_hex1 > 0x19) && (lsd_hex1 < 0x7F) && (lsd1_okay == 1) ) fprintf (stderr, "(%c", lsd_hex1);
|
|
||||||
else fprintf (stderr, "( ");
|
|
||||||
if ( (lsd_hex2 > 0x19) && (lsd_hex2 < 0x7F) && (lsd2_okay == 1) ) fprintf (stderr, "%c)", lsd_hex2);
|
|
||||||
else fprintf (stderr, " )");
|
|
||||||
if (lsd1_okay == 0) fprintf (stderr, " L1 ERR");
|
|
||||||
if (lsd2_okay == 0) fprintf (stderr, " L2 ERR");
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
//TEST: Store LSD into array if 0x02 0x08 (opcode and len?)
|
|
||||||
int k = 0;
|
|
||||||
if (state->dmr_alias_format[0] == 0x02)
|
|
||||||
{
|
|
||||||
k = state->data_block_counter[0];
|
|
||||||
if ( (lsd_hex1 > 0x19) && (lsd_hex1 < 0x7F) && (lsd1_okay == 1) )
|
|
||||||
state->dmr_alias_block_segment[0][0][k/4][k%4] = (char)lsd_hex1;
|
|
||||||
// else state->dmr_alias_block_segment[0][0][k/4][k%4] = 0x20;
|
|
||||||
k++;
|
|
||||||
if ( (lsd_hex2 > 0x19) && (lsd_hex2 < 0x7F) && (lsd2_okay == 1) )
|
|
||||||
state->dmr_alias_block_segment[0][0][k/4][k%4] = (char)lsd_hex2;
|
|
||||||
// else state->dmr_alias_block_segment[0][0][k/4][k%4] = 0x20;
|
|
||||||
k++;
|
|
||||||
state->data_block_counter[0] = k;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset format, len, counter.
|
|
||||||
if (lsd_hex1 == 0x02 && lsd1_okay == 1 && lsd2_okay == 1)
|
|
||||||
{
|
|
||||||
state->dmr_alias_format[0] = 0x02;
|
|
||||||
if (lsd_hex2 > 8) lsd_hex2 = 8; //sanity check
|
|
||||||
state->dmr_alias_len[0] = lsd_hex2;
|
|
||||||
state->data_block_counter[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (k >= state->dmr_alias_len[0]) && (state->dmr_alias_format[0] == 0x02) )
|
|
||||||
{
|
|
||||||
//storage for completed string
|
|
||||||
char str[16]; int wr = 0; int tsrc = state->lastsrc; int z = 0; k = 0;
|
|
||||||
for (i = 0; i < 16; i++) str[i] = 0;
|
|
||||||
|
|
||||||
//print out what we've gathered
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, " LSD Soft ID: ");
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%c", state->dmr_alias_block_segment[0][0][i][j]);
|
|
||||||
if (state->dmr_alias_block_segment[0][0][i][j] != 0) str[k++] = state->dmr_alias_block_segment[0][0][i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " STR: %s", str);
|
|
||||||
|
|
||||||
//assign to tg name string, but only if not trunking (this could clash with ENC LO functionality)
|
|
||||||
if (tsrc != 0) //&& opts->p25_trunk == 0 //should never get here if enc, should be zeroed out, but could potentially slip if HDU is missed and offchance of 02 opcode
|
|
||||||
{
|
|
||||||
for (int x = 0; x < state->group_tally; x++)
|
|
||||||
{
|
|
||||||
if (state->group_array[x].groupNumber == tsrc)
|
|
||||||
{
|
|
||||||
wr = 1; //already in there, so no need to assign it
|
|
||||||
z = x;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if not already in there, so save it there now
|
|
||||||
if (wr == 0)
|
|
||||||
{
|
|
||||||
state->group_array[state->group_tally].groupNumber = tsrc;
|
|
||||||
if (state->payload_algid != 0x80 && opts->trunk_tune_enc_calls == 0 && state->R == 0)
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
|
||||||
else
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "D");
|
|
||||||
sprintf (state->group_array[state->group_tally].groupName, "%s", str);
|
|
||||||
state->group_tally++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if its in there, but doesn't match (bad/partial decode)
|
|
||||||
else if (strcmp(str, state->group_array[z].groupName) != 0)
|
|
||||||
{
|
|
||||||
state->group_array[z].groupNumber = tsrc;
|
|
||||||
if (state->payload_algid != 0x80 && opts->trunk_tune_enc_calls == 0 && state->R == 0)
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
|
||||||
else
|
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "D");
|
|
||||||
sprintf (state->group_array[z].groupName, "%s", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s",KNRM);
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
//reset values
|
|
||||||
state->dmr_alias_format[0] = 0;
|
|
||||||
state->data_block_counter[0] = 0;
|
|
||||||
state->dmr_alias_len[0] = 0;
|
|
||||||
// memset (state->dmr_alias_block_segment, 0, sizeof(state->dmr_alias_block_segment));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
UNUSED2(lsd1_okay, lsd2_okay);
|
|
||||||
fprintf (stderr, "%s",KNRM);
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
#endif //SOFTID
|
|
||||||
|
|
||||||
//run LFSR on the MI if we have irrecoverable errors here
|
//run LFSR on the MI if we have irrecoverable errors here
|
||||||
if (irrecoverable_errors && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
|
if (irrecoverable_errors && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
1327
src/p25p1_mdpu.c
1327
src/p25p1_mdpu.c
File diff suppressed because it is too large
Load Diff
@@ -32,20 +32,9 @@ processTDU (dsd_opts* opts, dsd_state* state)
|
|||||||
int status;
|
int status;
|
||||||
status = getDibit (opts, state) + '0';
|
status = getDibit (opts, state) + '0';
|
||||||
// TODO: do something useful with the status bits...
|
// TODO: do something useful with the status bits...
|
||||||
UNUSED(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
|
|
||||||
//zero out MI, key, alg
|
|
||||||
state->payload_miP = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ void
|
|||||||
processTDULC (dsd_opts* opts, dsd_state* state)
|
processTDULC (dsd_opts* opts, dsd_state* state)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t lcinfo[57], lcformat[9], mfid[9];
|
char lcinfo[57], lcformat[9], mfid[9];
|
||||||
|
|
||||||
int status_count;
|
int status_count;
|
||||||
|
|
||||||
@@ -305,7 +305,6 @@ processTDULC (dsd_opts* opts, dsd_state* state)
|
|||||||
int status;
|
int status;
|
||||||
status = getDibit (opts, state) + '0';
|
status = getDibit (opts, state) + '0';
|
||||||
// TODO: do something useful with the status bits...
|
// TODO: do something useful with the status bits...
|
||||||
UNUSED(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the corrected data into the DSD structures
|
// Put the corrected data into the DSD structures
|
||||||
@@ -447,13 +446,4 @@ 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
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
|
|
||||||
//zero out MI, key, alg
|
|
||||||
state->payload_miP = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
518
src/p25p1_tsbk.c
518
src/p25p1_tsbk.c
@@ -20,13 +20,16 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tsbkbit[196]; //tsbk bit array, 196 trellis encoded bits
|
||||||
|
int tsbk_dibit[98];
|
||||||
|
|
||||||
uint8_t tsbk_dibit[98];
|
memset (tsbkbit, 0, sizeof(tsbkbit));
|
||||||
memset (tsbk_dibit, 0, sizeof(tsbk_dibit));
|
memset (tsbk_dibit, 0, sizeof(tsbk_dibit));
|
||||||
|
|
||||||
int dibit = 0;
|
int dibit = 0;
|
||||||
|
|
||||||
uint8_t tsbk_byte[12]; //12 byte return from p25_12
|
uint8_t tsbk_byte[12]; //12 byte return from bd_bridge (block_deinterleave)
|
||||||
memset (tsbk_byte, 0, sizeof(tsbk_byte));
|
memset (tsbk_byte, 0, sizeof(tsbk_byte));
|
||||||
|
|
||||||
unsigned long long int PDU[24]; //24 byte PDU to send to the tsbk_byte vPDU handler, should be same formats (mostly)
|
unsigned long long int PDU[24]; //24 byte PDU to send to the tsbk_byte vPDU handler, should be same formats (mostly)
|
||||||
@@ -35,20 +38,17 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|||||||
int tsbk_decoded_bits[190]; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
|
int tsbk_decoded_bits[190]; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
|
||||||
memset (tsbk_decoded_bits, 0, sizeof(tsbk_decoded_bits));
|
memset (tsbk_decoded_bits, 0, sizeof(tsbk_decoded_bits));
|
||||||
|
|
||||||
int i, j, k, x;
|
int flushing_bits[196]; //for flushing the trellis state machine
|
||||||
int ec = -2; //error value returned from p25_12
|
memset (flushing_bits, 0, sizeof(flushing_bits));
|
||||||
|
|
||||||
|
int i, j, k, b, x, y;
|
||||||
|
int ec = -2; //error value returned from (block_deinterleave)
|
||||||
int err = -2; //error value returned from crc16_lb_bridge
|
int err = -2; //error value returned from crc16_lb_bridge
|
||||||
|
int skipdibit = 14; //initial status dibit will occur at 14, then add 36 each time it occurs
|
||||||
int protectbit = 0;
|
int protectbit = 0;
|
||||||
int MFID = 0xFF; //Manufacturer ID - Might be beneficial to NOT send anything but standard 0x00 or 0x01 messages
|
int MFID = 0xFF; //Manufacturer ID - Might be beneficial to NOT send anything but standard 0x00 or 0x01 messages
|
||||||
int lb = 0; //last block
|
|
||||||
|
|
||||||
//now using modulus on skipdibit values (this was unneccesary on TSBK, but doing it to keep the two roughly the same code wise)
|
//TODO: Don't Print TSBKs/vPDUs unless verbosity levels set higher
|
||||||
int skipdibit = 36-14; //when we arrive here, we are at this position in the counter after reading FS, NID, DUID, and Parity dibits
|
|
||||||
int status_count = 1; //we have already skipped the Status 1 dibit before arriving here
|
|
||||||
int dibit_count = 0; //number of gathered dibits
|
|
||||||
UNUSED(status_count); //debug counter
|
|
||||||
UNUSED(dibit_count); //debug counter
|
|
||||||
|
|
||||||
//collect three reps of 101 dibits (98 valid dibits with status dibits interlaced)
|
//collect three reps of 101 dibits (98 valid dibits with status dibits interlaced)
|
||||||
for (j = 0; j < 3; j++)
|
for (j = 0; j < 3; j++)
|
||||||
@@ -58,33 +58,32 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
|
|
||||||
dibit = getDibit(opts, state);
|
dibit = getDibit(opts, state);
|
||||||
if ( (skipdibit / 36) == 0)
|
|
||||||
|
if (i+(j*101) != skipdibit) //
|
||||||
{
|
{
|
||||||
dibit_count++;
|
tsbk_dibit[k] = dibit;
|
||||||
tsbk_dibit[k++] = dibit;
|
tsbkbit[k*2] = (dibit >> 1) & 1;
|
||||||
|
tsbkbit[k*2+1] = (dibit & 1);
|
||||||
|
k++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
if (i+(j*101) == skipdibit)
|
||||||
{
|
{
|
||||||
skipdibit = 0;
|
skipdibit += 36;
|
||||||
status_count++;
|
|
||||||
|
|
||||||
// fprintf (stderr, " S:%02d; D:%03d; i:%03d;", status_count, (j*101)+i+57, i); //debug Status Count, Total Dibit Count, and i (compare to symbol rx table)
|
|
||||||
// fprintf (stderr, " S:%02d; CD:%02d; i:%03d; d:%d;", status_count, dibit_count, i, dibit); //debug Status Count, Current Dibit Count, i, and status dibit
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skipdibit++; //increment
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fprintf (stderr, " DC: %d", dibit_count); //debug
|
//flushing the trellis state machine
|
||||||
|
if (j == 0)
|
||||||
|
{
|
||||||
|
bd_bridge(flushing_bits, tsbk_byte);
|
||||||
|
//reset tsbk_byte afterwards
|
||||||
|
memset (tsbk_byte, 0, sizeof(tsbk_byte));
|
||||||
|
}
|
||||||
|
|
||||||
//send to p25_12 and return tsbk_byte
|
//send tsbkbit to block_deinterleave and return tsbk_byte
|
||||||
ec = p25_12 (tsbk_dibit, tsbk_byte);
|
ec = bd_bridge(tsbkbit, tsbk_byte);
|
||||||
|
|
||||||
//debug err tally from 1/2 decoder
|
|
||||||
// if (ec) fprintf (stderr, " #%d ERR = %d;", j+1, ec);
|
|
||||||
|
|
||||||
//too many bit manipulations!
|
//too many bit manipulations!
|
||||||
k = 0;
|
k = 0;
|
||||||
@@ -133,453 +132,21 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
//check the protect bit, don't run if protected
|
//check the protect bit, don't run if protected
|
||||||
protectbit = (tsbk_byte[0] >> 6) & 0x1;
|
protectbit = (tsbk_byte[0] >> 6) & 0x1;
|
||||||
lb = (tsbk_byte[0] >> 7) & 0x1;
|
|
||||||
|
|
||||||
//zero out data calls after returning from a SNDCP data channel
|
//Don't run NET_STS out of this, or will set wrong NAC/CC //&& PDU[1] != 0x49 && PDU[1] != 0x45
|
||||||
if (err == 0)
|
//0x49 is telephone grant, 0x46 Unit to Unit Channel Answer Request (seems bogus) (mfid 90)
|
||||||
sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
// if (MFID < 0x2 && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
|
||||||
|
//running with A4 and 90 causing some false positives when sending to vPDU, issuing bad call grants to nowhere!
|
||||||
//Don't run NET_STS out of this, or will set wrong NAC/CC
|
// if ( (MFID < 0x2 || MFID == 0xA4 || MFID == 0x90) && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
|
||||||
//Note: Running MFID 90 (moto) opcode 9 GRG Delete or Reserve will falsely trigger a telephone interconnect grant
|
if (MFID < 0x2 && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
|
||||||
if (MFID < 0x2 && protectbit == 0 && err == 0 && PDU[1] != 0x7B )
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s",KYEL);
|
fprintf (stderr, "%s",KYEL);
|
||||||
process_MAC_VPDU(opts, state, 0, PDU);
|
process_MAC_VPDU(opts, state, 0, PDU);
|
||||||
fprintf (stderr, "%s",KNRM);
|
fprintf (stderr, "%s",KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
//look at Harris Opcodes and payload portion of TSBK
|
|
||||||
else if (MFID == 0xA4 && protectbit == 0 && err == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
//MFIDA4 Group Regroup Explicit Encryption Command
|
|
||||||
if ( (tsbk_byte[0] & 0x3F) == 0x30)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KYEL);
|
|
||||||
fprintf (stderr, "\n MFID A4 (Harris) Group Regroup Explicit Encryption Command\n");
|
|
||||||
int sg = (tsbk_byte[3] << 8) | tsbk_byte[4];
|
|
||||||
int key = (tsbk_byte[5] << 8) | tsbk_byte[6];
|
|
||||||
int add = (tsbk_byte[7] << 16) | (tsbk_byte[8] << 8) | tsbk_byte[9];
|
|
||||||
int tga = tsbk_byte[2] >> 5; //3 bit TGA from GRG_Options
|
|
||||||
int ssn = tsbk_byte[2] & 0x1F; //5 bit SSN from GRG_Options
|
|
||||||
|
|
||||||
if ( (tga & 0x2) == 2) //WGID or WUID (working group id or working unit id)
|
|
||||||
fprintf (stderr, " SG: %d; KEY: %04X; WGID: %d; ", sg, key, add);
|
|
||||||
else fprintf (stderr, " SG: %d; KEY: %04X; WUID: %d; ", sg, key, add);
|
|
||||||
|
|
||||||
if ( (tga & 0x4) == 4) fprintf (stderr, " Simulselect"); //one-way regroup
|
|
||||||
else fprintf (stderr, " Patch"); //two-way regroup
|
|
||||||
|
|
||||||
if (tga & 1) fprintf (stderr, " Active;"); //activated
|
|
||||||
else fprintf (stderr, " Inactive;"); //deactivated
|
|
||||||
|
|
||||||
//debug
|
|
||||||
// fprintf (stderr, " T:%d G:%d A:%d;", (tga >> 2) & 1, (tga >> 1) & 1, tga & 1);
|
|
||||||
|
|
||||||
fprintf (stderr, " SSN: %02d \n", ssn);
|
|
||||||
fprintf (stderr, " %s",KNRM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, "\n MFID A4 (Harris); Opcode: %02X; ", tsbk_byte[0] & 0x3F);
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
fprintf (stderr, " %s",KNRM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->payload == 1)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, "\n P25 PDU Payload #%d ", j+1);
|
|
||||||
for (i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "[%02X]", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
fprintf (stderr, "\n MFID %02X Protected: %d Last Block: %d", MFID, protectbit, lb);
|
|
||||||
|
|
||||||
if (ec != 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KRED);
|
|
||||||
fprintf (stderr, " ERR = %d", ec);
|
|
||||||
}
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KRED);
|
|
||||||
fprintf (stderr, " (CRC ERR)");
|
|
||||||
}
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//look at Motorola Opcodes and payload portion of TSBK
|
|
||||||
else if (MFID == 0x90 && protectbit == 0 && err == 0)
|
|
||||||
{
|
|
||||||
//group list mode so we can look and see if we need to block tuning any groups, etc
|
|
||||||
char mode[8]; //allow, block, digital, enc, etc
|
|
||||||
sprintf (mode, "%s", "");
|
|
||||||
|
|
||||||
//MFID 90 Group Regroup Channel Grant (MOT_GRG_CN_GRANT) TIA-102.AABH
|
|
||||||
if ( (tsbk_byte[0] & 0x3F) == 0x02 )
|
|
||||||
{
|
|
||||||
int svc = tsbk_byte[2]; //Just the Res, P-bit, and more res bits
|
|
||||||
int channel = (tsbk_byte[3] << 8) | tsbk_byte[4];
|
|
||||||
long int source = (tsbk_byte[7] << 16) |(tsbk_byte[8] << 8) | tsbk_byte[9];
|
|
||||||
int group = (tsbk_byte[5] << 8) | tsbk_byte[6];
|
|
||||||
long int freq1 = 0;
|
|
||||||
UNUSED(source);
|
|
||||||
fprintf (stderr, "%s\n ",KYEL);
|
|
||||||
|
|
||||||
//unsure if this follows for GRG
|
|
||||||
// if (svc & 0x80) fprintf (stderr, " Emergency");
|
|
||||||
|
|
||||||
if (svc & 0x40) fprintf (stderr, " Encrypted"); //P-bit
|
|
||||||
|
|
||||||
//unsure if this follows for GRG
|
|
||||||
// if (opts->payload == 1) //hide behind payload due to len
|
|
||||||
// {
|
|
||||||
// if (svc & 0x20) fprintf (stderr, " Duplex");
|
|
||||||
// if (svc & 0x10) fprintf (stderr, " Packet");
|
|
||||||
// else fprintf (stderr, " Circuit");
|
|
||||||
// if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
|
||||||
// fprintf (stderr, " Priority %d", svc & 0x7); //call priority
|
|
||||||
// }
|
|
||||||
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Group Regroup Channel Grant");
|
|
||||||
fprintf (stderr, "\n SVC [%02X] CHAN [%04X] SG [%d][%04X]", svc, channel, group, group);
|
|
||||||
freq1 = process_channel_to_freq (opts, state, channel);
|
|
||||||
|
|
||||||
//add active channel to string for ncurses display
|
|
||||||
sprintf (state->active_channel[0], "MFID90 Ch: %04X SG: %d ", channel, group);
|
|
||||||
state->last_active_time = time(NULL);
|
|
||||||
|
|
||||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
|
||||||
|
|
||||||
for (int i = 0; i < state->group_tally; i++)
|
|
||||||
{
|
|
||||||
if (state->group_array[i].groupNumber == group)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TG hold on MFID90 GRG -- block non-matching target, allow matching group
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold != group) sprintf (mode, "%s", "B");
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold == group) sprintf (mode, "%s", "A");
|
|
||||||
|
|
||||||
//Skip tuning group calls if group calls are disabled
|
|
||||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
|
||||||
|
|
||||||
//Skip tuning encrypted calls if enc calls are disabled
|
|
||||||
if ( (svc & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
|
||||||
|
|
||||||
//tune if tuning available
|
|
||||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
|
||||||
{
|
|
||||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
|
||||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
|
||||||
{
|
|
||||||
|
|
||||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
|
||||||
if (1 == 1)
|
|
||||||
{
|
|
||||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
|
||||||
{
|
|
||||||
state->samplesPerSymbol = 8;
|
|
||||||
state->symbolCenter = 3;
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
opts->slot1_on = 0;
|
|
||||||
opts->slot2_on = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, freq1);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
|
||||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
|
||||||
state->last_vc_sync_time = time(NULL);
|
|
||||||
}
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
rtl_dev_tune (opts, freq1);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
|
||||||
opts->p25_is_tuned = 1;
|
|
||||||
state->last_vc_sync_time = time(NULL);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (tsbk_byte[0] & 0x3F) == 0x03 )
|
|
||||||
{
|
|
||||||
//MFID 90 Group Regroup Channel Update (MOT_GRG_CN_GRANT_UPDT) TIA-102.AABH
|
|
||||||
int channel1 = (tsbk_byte[2] << 8) | tsbk_byte[3];
|
|
||||||
int group1 = (tsbk_byte[4] << 8) | tsbk_byte[5];
|
|
||||||
int channel2 = (tsbk_byte[6] << 8) | tsbk_byte[7];
|
|
||||||
int group2 = (tsbk_byte[8] << 8) | tsbk_byte[9];
|
|
||||||
|
|
||||||
long int freq1 = 0;
|
|
||||||
long int freq2 = 0;
|
|
||||||
|
|
||||||
int tempg = 0; //temp group
|
|
||||||
int tempc = 0; //temp chan
|
|
||||||
long int tempf = 0; //temp freq
|
|
||||||
|
|
||||||
fprintf (stderr, "%s\n ",KYEL);
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Group Regroup Channel Grant Update");
|
|
||||||
fprintf (stderr, "\n CHAN1 [%04X] SG [%d][%04X] CHAN2 [%04X] SG [%d][%04X]", channel1, group1, group1, channel2, group2, group2);
|
|
||||||
freq1 = process_channel_to_freq (opts, state, channel1);
|
|
||||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
|
||||||
|
|
||||||
//add active channel to string for ncurses display
|
|
||||||
sprintf (state->active_channel[0], "MFID90 Ch: %04X SG: %d; Ch: %04X SG: %d ", channel1, group1, channel2, group2);
|
|
||||||
state->last_active_time = time(NULL);
|
|
||||||
|
|
||||||
tempf = freq1;
|
|
||||||
tempc = channel1;
|
|
||||||
tempg = group1;
|
|
||||||
|
|
||||||
for (int j = 0; j < 2; j++)
|
|
||||||
{
|
|
||||||
if (j == 1)
|
|
||||||
{
|
|
||||||
tempf = freq2;
|
|
||||||
tempc = channel2;
|
|
||||||
tempg = group2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
|
||||||
|
|
||||||
for (int i = 0; i < state->group_tally; i++)
|
|
||||||
{
|
|
||||||
if (state->group_array[i].groupNumber == tempg)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
|
||||||
strcpy (mode, state->group_array[i].groupMode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TG hold on MFID90 GRG -- block non-matching target, allow matching group
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold != tempg) sprintf (mode, "%s", "B");
|
|
||||||
if (state->tg_hold != 0 && state->tg_hold == tempg) sprintf (mode, "%s", "A");
|
|
||||||
|
|
||||||
//Skip tuning group calls if group calls are disabled
|
|
||||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
|
||||||
|
|
||||||
//Skip tuning encrypted calls if enc calls are disabled
|
|
||||||
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
|
||||||
|
|
||||||
//tune if tuning available
|
|
||||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
|
||||||
{
|
|
||||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
|
||||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tempf != 0) //if we aren't already on a VC and have a valid frequency
|
|
||||||
{
|
|
||||||
|
|
||||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
|
||||||
if (1 == 1)
|
|
||||||
{
|
|
||||||
if (state->p25_chan_tdma[tempc >> 12] == 1)
|
|
||||||
{
|
|
||||||
state->samplesPerSymbol = 8;
|
|
||||||
state->symbolCenter = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, tempf);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tempf;
|
|
||||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
|
||||||
state->last_vc_sync_time = time(NULL);
|
|
||||||
}
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
rtl_dev_tune (opts, tempf);
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tempf;
|
|
||||||
opts->p25_is_tuned = 1;
|
|
||||||
state->last_vc_sync_time = time(NULL);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (tsbk_byte[0] & 0x3F) == 0x00)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s",KYEL);
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Group Regroup Add: ");
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (tsbk_byte[0] & 0x3F) == 0x01 )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s",KYEL);
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Group Regroup Delete: ");
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (tsbk_byte[0] & 0x3F) == 0x04 )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s",KYEL);
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Extended Function: ");
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (tsbk_byte[0] & 0x3F) == 0x06 )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s",KYEL);
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Queued Response: ");
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (tsbk_byte[0] & 0x3F) == 0x07 )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s",KYEL);
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Deny Response: ");
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (tsbk_byte[0] & 0x3F) == 0x08 )
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s",KYEL);
|
|
||||||
fprintf (stderr, " MFID 90 (Moto) Acknoledge Response: ");
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Some of these Opcodes that aren't found in any TIA manual come from SDRTrunk (or other sources),
|
|
||||||
//but can't verify the accuracy of their meaning/context
|
|
||||||
// else if ( (tsbk_byte[0] & 0x3F) == 0x05 )
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
// fprintf (stderr, " MFID 90 (Moto) Traffic Channel: "); //not sure about this one, don't understand what it means when its on a control channel (activity? but never seems to change even while call grants in progress)
|
|
||||||
// for (i = 2; i < 10; i++)
|
|
||||||
// fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if ( (tsbk_byte[0] & 0x3F) == 0x09 )
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
// fprintf (stderr, " MFID 90 (Moto) Channel Loading: "); //don't understand the context for this one, waiting on units to arrive on channel?
|
|
||||||
// for (i = 2; i < 10; i++)
|
|
||||||
// fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if ( (tsbk_byte[0] & 0x3F) == 0x0B )
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
// fprintf (stderr, " MFID 90 (Moto) Control Channel: "); //this appears to echo the 16-bit channel number for the main control channel/RFSS
|
|
||||||
// for (i = 2; i < 10; i++)
|
|
||||||
// fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if ( (tsbk_byte[0] & 0x3F) == 0x0E )
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
// fprintf (stderr, " MFID 90 (Moto) Control Channel Planned Shutdown: ");
|
|
||||||
// for (i = 2; i < 10; i++)
|
|
||||||
// fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if ( (tsbk_byte[0] & 0x3F) == 0x10 )
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
// fprintf (stderr, " MFID 90 (Moto) Something: "); //observed, but no idea
|
|
||||||
// for (i = 2; i < 10; i++)
|
|
||||||
// fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if ( (tsbk_byte[0] & 0x3F) == 0x15 ) //noted on RR, but not observed as of yet, this may actualy be a LCW and not a TSBK?
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
// fprintf (stderr, " MFID 90 (Moto) Talker Alias: ");
|
|
||||||
// for (i = 2; i < 10; i++)
|
|
||||||
// fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else if ( (tsbk_byte[0] & 0x3F) == 0x16 )
|
|
||||||
// {
|
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
// fprintf (stderr, " MFID 90 (Moto) Something: "); //observed, but no idea
|
|
||||||
// for (i = 2; i < 10; i++)
|
|
||||||
// fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, "\n MFID 90 (Moto); Opcode: %02X; ", tsbk_byte[0] & 0x3F);
|
|
||||||
for (i = 2; i < 10; i++)
|
|
||||||
fprintf (stderr, "%02X", tsbk_byte[i]);
|
|
||||||
fprintf (stderr, " %s",KNRM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->payload == 1)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KCYN);
|
|
||||||
fprintf (stderr, "\n P25 PDU Payload #%d ", j+1);
|
|
||||||
for (i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "[%02X]", tsbk_byte[i]);
|
|
||||||
}
|
|
||||||
fprintf (stderr, "\n MFID %02X Protected: %d Last Block: %d", MFID, protectbit, lb);
|
|
||||||
|
|
||||||
if (ec != 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KRED);
|
|
||||||
fprintf (stderr, " ERR = %d", ec);
|
|
||||||
}
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s",KRED);
|
|
||||||
fprintf (stderr, " (CRC ERR)");
|
|
||||||
}
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
|
||||||
}
|
|
||||||
|
|
||||||
SKIPCALL: ; //do nothing
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//set our WACN and SYSID here now that we have valid ec and crc/checksum
|
//set our WACN and SYSID here now that we have valid ec and crc/checksum
|
||||||
else if (protectbit == 0 && err == 0 && (tsbk_byte[0] & 0x3F) == 0x3B)
|
else if (protectbit == 0 && err == 0 && ec == 0 && (tsbk_byte[0] & 0x3F) == 0x3B)
|
||||||
{
|
{
|
||||||
long int wacn = (tsbk_byte[3] << 12) | (tsbk_byte[4] << 4) | (tsbk_byte[5] >> 4);
|
long int wacn = (tsbk_byte[3] << 12) | (tsbk_byte[4] << 4) | (tsbk_byte[5] >> 4);
|
||||||
int sysid = ((tsbk_byte[5] & 0xF) << 8) | tsbk_byte[6];
|
int sysid = ((tsbk_byte[5] & 0xF) << 8) | tsbk_byte[6];
|
||||||
@@ -607,7 +174,7 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s",KCYN);
|
fprintf (stderr, "%s",KCYN);
|
||||||
fprintf (stderr, "\n P25 PDU Payload #%d ", j+1);
|
fprintf (stderr, "\n P25 PDU Payload #%d ", j);
|
||||||
for (i = 0; i < 12; i++)
|
for (i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "[%02X]", tsbk_byte[i]);
|
fprintf (stderr, "[%02X]", tsbk_byte[i]);
|
||||||
@@ -628,14 +195,14 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "[%02X]", tsbk_byte[i]);
|
fprintf (stderr, "[%02X]", tsbk_byte[i]);
|
||||||
}
|
}
|
||||||
fprintf (stderr, "\n MFID %02X Protected: %d Last Block: %d", MFID, protectbit, lb);
|
fprintf (stderr, "\n MFID %02X Protected: %d Last Block: %d", MFID, protectbit, (tsbk_byte[0] >> 7) );
|
||||||
|
|
||||||
if (ec != 0)
|
if (ec != 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s",KRED);
|
fprintf (stderr, "%s",KRED);
|
||||||
fprintf (stderr, " ERR = %d", ec);
|
fprintf (stderr, " (FEC ERR)");
|
||||||
}
|
}
|
||||||
if (err != 0)
|
else if (err != 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s",KRED);
|
fprintf (stderr, "%s",KRED);
|
||||||
fprintf (stderr, " (CRC ERR)");
|
fprintf (stderr, " (CRC ERR)");
|
||||||
@@ -651,7 +218,10 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|||||||
MFID = 0xFF;
|
MFID = 0xFF;
|
||||||
|
|
||||||
//check for last block bit
|
//check for last block bit
|
||||||
if (lb) break;
|
if ( (tsbk_byte[0] >> 7) == 1 )
|
||||||
|
{
|
||||||
|
j = 4; //set j to break the loop early
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
//DUID Look Up Table from OP25
|
//DUID Look Up Table from OP25
|
||||||
static const int16_t duid_lookup[256] = { //128 triggers false 4V on bad signal
|
static const int16_t duid_lookup[256] = {
|
||||||
0,0,0,-1,0,-1,-1,1,0,-1,-1,4,-1,8,2,-1,
|
0,0,0,-1,0,-1,-1,1,0,-1,-1,4,-1,8,2,-1,
|
||||||
0,-1,-1,1,-1,1,1,1,-1,3,9,-1,5,-1,-1,1,
|
0,-1,-1,1,-1,1,1,1,-1,3,9,-1,5,-1,-1,1,
|
||||||
0,-1,-1,10,-1,6,2,-1,-1,3,2,-1,2,-1,2,2,
|
0,-1,-1,10,-1,6,2,-1,-1,3,2,-1,2,-1,2,2,
|
||||||
@@ -20,7 +20,7 @@ static const int16_t duid_lookup[256] = { //128 triggers false 4V on bad signal
|
|||||||
-1,13,7,-1,5,-1,-1,1,5,-1,-1,4,5,5,5,-1,
|
-1,13,7,-1,5,-1,-1,1,5,-1,-1,4,5,5,5,-1,
|
||||||
-1,6,7,-1,6,6,-1,6,14,-1,-1,4,-1,6,2,-1,
|
-1,6,7,-1,6,6,-1,6,14,-1,-1,4,-1,6,2,-1,
|
||||||
7,-1,7,7,-1,6,7,-1,-1,3,7,-1,5,-1,-1,15,
|
7,-1,7,7,-1,6,7,-1,-1,3,7,-1,5,-1,-1,15,
|
||||||
-1,-1,-1,10,-1,8,12,-1,-1,8,9,-1,8,8,-1,8, //first value was 0 for 4V, changing to -1 for testing -- 1000 0000 (perfect 4V should be 0000 0000, so is this the correct hamming distance?)
|
0,-1,-1,10,-1,8,12,-1,-1,8,9,-1,8,8,-1,8,
|
||||||
-1,13,9,-1,11,-1,-1,1,9,-1,9,9,-1,8,9,-1,
|
-1,13,9,-1,11,-1,-1,1,9,-1,9,9,-1,8,9,-1,
|
||||||
-1,10,10,10,11,-1,-1,10,14,-1,-1,10,-1,8,2,-1,
|
-1,10,10,10,11,-1,-1,10,14,-1,-1,10,-1,8,2,-1,
|
||||||
11,-1,-1,10,11,11,11,-1,-1,3,9,-1,11,-1,-1,15,
|
11,-1,-1,10,11,11,11,-1,-1,3,9,-1,11,-1,-1,15,
|
||||||
@@ -74,12 +74,11 @@ int p2xbit[4320] = {0}; //bits xored from p2bit and p2lbit
|
|||||||
int dibit = 0;
|
int dibit = 0;
|
||||||
int vc_counter = 0;
|
int vc_counter = 0;
|
||||||
int framing_counter = 0;
|
int framing_counter = 0;
|
||||||
int voice = 0; //if voice in vch 0 or vch 1
|
|
||||||
|
|
||||||
uint64_t isch = 0;
|
unsigned long long int isch = 0;
|
||||||
int isch_decoded = -1;
|
int isch_decoded = -1;
|
||||||
uint8_t p2_duid[8] = {0};
|
int p2_duid[8] = {0};
|
||||||
int16_t duid_decoded = -1;
|
int16_t duid_decoded = 0;
|
||||||
|
|
||||||
int ess_b[2][96] = {0}; //96 bits for 4 - 24 bit ESS_B fields starting bit 168 (RS 44,16,29)
|
int ess_b[2][96] = {0}; //96 bits for 4 - 24 bit ESS_B fields starting bit 168 (RS 44,16,29)
|
||||||
int ess_a[2][168] = {0}; //ESS_A 1 (96 bit) and 2 (72 bit) fields, starting at bit 168 and bit 266 (RS Parity)
|
int ess_a[2][168] = {0}; //ESS_A 1 (96 bit) and 2 (72 bit) fields, starting at bit 168 and bit 266 (RS Parity)
|
||||||
@@ -110,8 +109,6 @@ void p2_dibit_buffer (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void process_Frame_Scramble (dsd_opts * opts, dsd_state * state)
|
void process_Frame_Scramble (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
//The bits of the scramble sequence corresponding to signal bits that are not scrambled or not used are discarded.
|
//The bits of the scramble sequence corresponding to signal bits that are not scrambled or not used are discarded.
|
||||||
//descramble frame scrambled by LFSR of WACN, SysID, and CC(NAC)
|
//descramble frame scrambled by LFSR of WACN, SysID, and CC(NAC)
|
||||||
unsigned long long int seed = 0;
|
unsigned long long int seed = 0;
|
||||||
@@ -357,9 +354,7 @@ void process_SACCHs (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
void process_ISCH (dsd_opts * opts, dsd_state * state)
|
void process_ISCH (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(opts);
|
isch = 0;
|
||||||
|
|
||||||
isch = 0;
|
|
||||||
for (int i = 0; i < 40; i++)
|
for (int i = 0; i < 40; i++)
|
||||||
{
|
{
|
||||||
isch = isch << 1;
|
isch = isch << 1;
|
||||||
@@ -380,7 +375,6 @@ void process_ISCH (dsd_opts * opts, dsd_state * state)
|
|||||||
int free = (isch_decoded >> 2) & 0x1;
|
int free = (isch_decoded >> 2) & 0x1;
|
||||||
int isch_loc = (isch_decoded >> 3) & 0x3;
|
int isch_loc = (isch_decoded >> 3) & 0x3;
|
||||||
int chan_num = (isch_decoded >> 5) & 0x3;
|
int chan_num = (isch_decoded >> 5) & 0x3;
|
||||||
UNUSED2(uf_count, free);
|
|
||||||
state->p2_vch_chan_num = chan_num;
|
state->p2_vch_chan_num = chan_num;
|
||||||
|
|
||||||
//old rules for entire superframe worth
|
//old rules for entire superframe worth
|
||||||
@@ -481,71 +475,20 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
|
#ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
|
||||||
// //Cygwin OSS Slot Preference Pre-emption shim
|
//Cygwin OSS Slot Preference Pre-emption shim
|
||||||
// if (opts->audio_out_type == 5)
|
if (opts->audio_out_type == 5)
|
||||||
// {
|
{
|
||||||
// //set to 21 for MBE OSS shim to preempt audio
|
//set to 21 for MBE OSS shim to preempt audio
|
||||||
// if (state->currentslot == 0) state->dmrburstL = 21;
|
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||||
// else state->dmrburstR = 21;
|
else state->dmrburstR = 21;
|
||||||
// }
|
}
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr4, NULL);
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[3], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[3], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[3], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[3], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,44 +642,18 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// #ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
|
#ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
|
||||||
// //Cygwin OSS Slot Preference Pre-emption shim
|
//Cygwin OSS Slot Preference Pre-emption shim
|
||||||
// if (opts->audio_out_type == 5)
|
if (opts->audio_out_type == 5)
|
||||||
// {
|
{
|
||||||
// //set to 21 for MBE OSS shim to preempt audio
|
//set to 21 for MBE OSS shim to preempt audio
|
||||||
// if (state->currentslot == 0) state->dmrburstL = 21;
|
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||||
// else state->dmrburstR = 21;
|
else state->dmrburstR = 21;
|
||||||
// }
|
}
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
process_ESS(opts, state);
|
process_ESS(opts, state);
|
||||||
|
|
||||||
@@ -757,6 +674,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
int err_counter = 0;
|
int err_counter = 0;
|
||||||
|
|
||||||
//add time to mirror printFrameSync
|
//add time to mirror printFrameSync
|
||||||
|
time_t now;
|
||||||
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);
|
||||||
@@ -774,8 +692,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
for (ts_counter = 0; ts_counter < 4; ts_counter++) //12
|
for (ts_counter = 0; ts_counter < 4; ts_counter++) //12
|
||||||
{
|
{
|
||||||
duid_decoded = -2;
|
|
||||||
int sacch = 0; UNUSED(sacch);
|
|
||||||
p2_duid[0] = p2bit[0+(ts_counter*360)];
|
p2_duid[0] = p2bit[0+(ts_counter*360)];
|
||||||
p2_duid[1] = p2bit[1+(ts_counter*360)];
|
p2_duid[1] = p2bit[1+(ts_counter*360)];
|
||||||
p2_duid[2] = p2bit[74+(ts_counter*360)];
|
p2_duid[2] = p2bit[74+(ts_counter*360)];
|
||||||
@@ -798,42 +715,26 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr,"%s ", getTime());
|
fprintf (stderr,"%s ", getTime());
|
||||||
fprintf (stderr, " P25p2 ");
|
fprintf (stderr, " P25p2 ");
|
||||||
|
|
||||||
if (state->currentslot == 0 && duid_decoded != 3 && duid_decoded != 12 && duid_decoded != 13 && duid_decoded != 4)
|
//print our VCH channel number, or print S for SACCH since its inverted
|
||||||
|
if (state->currentslot == 0 && duid_decoded != 3 && duid_decoded != 12)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "LCH 0 ");
|
fprintf (stderr, "VCH 0 ");
|
||||||
//open MBEout file - slot 1 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
|
//open MBEout file - slot 1 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
|
||||||
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
|
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
|
||||||
{
|
{
|
||||||
voice = 1;
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (state->currentslot == 1 && duid_decoded != 3 && duid_decoded != 12 && duid_decoded != 13 && duid_decoded != 4)
|
else if (state->currentslot == 1 && duid_decoded != 3 && duid_decoded != 12)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "LCH 1 ");
|
fprintf (stderr, "VCH 1 ");
|
||||||
//open MBEout file - slot 2 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
|
//open MBEout file - slot 2 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
|
||||||
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
|
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
|
||||||
{
|
{
|
||||||
voice = 1;
|
|
||||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
|
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//The LCCH may occupy LCH 0 or LCH 1 or both. BBAD 3.3 p8
|
else fprintf (stderr, "VCH S ");
|
||||||
else if (duid_decoded == 13) //MAC_SIGNAL, or clear LCCH
|
|
||||||
{
|
|
||||||
// sacch = 1; //only an 'inverted' slot when its TS index 10 or 11
|
|
||||||
fprintf (stderr, "LCCH ");
|
|
||||||
}
|
|
||||||
else if (duid_decoded == 4) //Scrambled LCCH (TDMA_CC only...look in the manual again)
|
|
||||||
{
|
|
||||||
// sacch = 1; //only an 'inverted' slot when its TS index 10 or 11
|
|
||||||
fprintf (stderr, "LCCHs ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sacch = 1; //always an "inverted" sacch slot
|
|
||||||
fprintf (stderr, "SACCH ");
|
|
||||||
}
|
|
||||||
|
|
||||||
//check to see when last voice activity occurred in order to allow tuning on phase 2
|
//check to see when last voice activity occurred in order to allow tuning on phase 2
|
||||||
//mac_signal or mac_idle when no more voice activity on current channel
|
//mac_signal or mac_idle when no more voice activity on current channel
|
||||||
@@ -849,8 +750,6 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
if (duid_decoded == 0)
|
if (duid_decoded == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " 4V %d", state->fourv_counter[state->currentslot]+1);
|
fprintf (stderr, " 4V %d", state->fourv_counter[state->currentslot]+1);
|
||||||
//debug see which 4V and which 2V randomly pop on Duke P25p2 CC (8 bit binary code)
|
|
||||||
// fprintf (stderr, " DUID: %d", p2_duid_complete);
|
|
||||||
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
|
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
|
||||||
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
|
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
|
||||||
{
|
{
|
||||||
@@ -861,8 +760,6 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
else if (duid_decoded == 6)
|
else if (duid_decoded == 6)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " 2V");
|
fprintf (stderr, " 2V");
|
||||||
//debug see which 4V and which 2V randomly pop on Duke P25p2 CC (8 bit binary code)
|
|
||||||
// fprintf (stderr, " DUID: %d", p2_duid_complete);
|
|
||||||
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
|
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
|
||||||
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
|
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
|
||||||
{
|
{
|
||||||
@@ -901,6 +798,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
else if (duid_decoded == 4)
|
else if (duid_decoded == 4)
|
||||||
{
|
{
|
||||||
|
fprintf (stderr, " LCCH Sc"); //w/ scrambling
|
||||||
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
|
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
|
||||||
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
|
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
|
||||||
{
|
{
|
||||||
@@ -941,24 +839,6 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
//add 360 bits to each counter
|
//add 360 bits to each counter
|
||||||
vc_counter = vc_counter + 360;
|
vc_counter = vc_counter + 360;
|
||||||
|
|
||||||
//debug enable both slots before playback
|
|
||||||
// opts->slot1_on = 1;
|
|
||||||
// opts->slot2_on = 1;
|
|
||||||
|
|
||||||
//NOTE: Could be an issue if MAC_SIGNAL onn LCH 1 and voice in LCH 0? It might Stutter?
|
|
||||||
if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceFS4 (opts, state);
|
|
||||||
|
|
||||||
if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceSS4 (opts, state);
|
|
||||||
|
|
||||||
//debug: fix burst indicator for ncurses if marginal signal
|
|
||||||
// if (voice)
|
|
||||||
// {
|
|
||||||
// if (state->currentslot == 0) state->dmrburstL = 21;
|
|
||||||
// else state->dmrburstR = 21;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//flip slots after each TS processed
|
//flip slots after each TS processed
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
@@ -969,13 +849,12 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|||||||
state->currentslot = 0;
|
state->currentslot = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset voice after each compliment of 2 slots
|
|
||||||
if (ts_counter & 1)
|
|
||||||
voice = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
END:
|
END:
|
||||||
voice = 0; //reset before exit
|
if (1 == 2)
|
||||||
|
{
|
||||||
|
//go directly to END if 2 consecutive DUID errors occur
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,7 +862,6 @@ void processP2 (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
state->dmr_stereo = 1;
|
state->dmr_stereo = 1;
|
||||||
p2_dibit_buffer (opts, state);
|
p2_dibit_buffer (opts, state);
|
||||||
voice = 0;
|
|
||||||
|
|
||||||
//look at our ISCH values and determine location in superframe before running frame scramble
|
//look at our ISCH values and determine location in superframe before running frame scramble
|
||||||
for (framing_counter = 0; framing_counter < 4; framing_counter++)
|
for (framing_counter = 0; framing_counter < 4; framing_counter++)
|
||||||
@@ -1004,7 +882,6 @@ void processP2 (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
//process DUID will run through all collected frames and handle them appropriately
|
//process DUID will run through all collected frames and handle them appropriately
|
||||||
process_P2_DUID (opts, state);
|
process_P2_DUID (opts, state);
|
||||||
|
|
||||||
state->dmr_stereo = 0;
|
state->dmr_stereo = 0;
|
||||||
state->p2_is_lcch = 0;
|
state->p2_is_lcch = 0;
|
||||||
|
|
||||||
|
|||||||
1256
src/p25p2_vpdu.c
1256
src/p25p2_vpdu.c
File diff suppressed because it is too large
Load Diff
224
src/p25p2_xcch.c
224
src/p25p2_xcch.c
@@ -36,22 +36,20 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|||||||
opcode = (payload[0] << 2) | (payload[1] << 1) | (payload[2] << 0);
|
opcode = (payload[0] << 2) | (payload[1] << 1) | (payload[2] << 0);
|
||||||
int mac_offset = 0;
|
int mac_offset = 0;
|
||||||
mac_offset = (payload[3] << 2) | (payload[4] << 1) | (payload[5] << 0);
|
mac_offset = (payload[3] << 2) | (payload[4] << 1) | (payload[5] << 0);
|
||||||
int res = (payload[6] << 1) | (payload[7] << 0);
|
|
||||||
int b = 9;
|
int b = 9;
|
||||||
b = (payload[8] << 1) | (payload[9] << 0); //combined b1 and b2
|
b = (payload[8] << 1) | (payload[9] << 0); //combined b1 and b2
|
||||||
int mco_a = 69;
|
int mco_a = 69;
|
||||||
//mco will tell us the number of octets to use in variable length MAC PDUs, need a table or something
|
//mco will tell us the number of octets to use in variable length MAC PDUs, need a table or something
|
||||||
mco_a = (payload[10] << 5) | (payload[11] << 4) | (payload[12] << 3) | (payload[13] << 2) | (payload[14] << 0) | (payload[15] << 0);
|
mco_a = (payload[10] << 5) | (payload[11] << 4) | (payload[12] << 3) | (payload[13] << 2) | (payload[14] << 0) | (payload[15] << 0);
|
||||||
UNUSED3(mac_offset, b, mco_a);
|
|
||||||
|
|
||||||
//get the second mco after determining first message length, see what second mco is and plan accordingly
|
//get the second mco after determining first message length, see what second mco is and plan accordingly
|
||||||
int mco_b = 69;
|
int mco_b = 69;
|
||||||
UNUSED(mco_b);
|
|
||||||
|
|
||||||
//attempt CRC12 check to validate or reject PDU
|
//attempt CRC12 check to validate or reject PDU
|
||||||
int err = -2;
|
int err = -2;
|
||||||
if (state->p2_is_lcch == 0)
|
if (state->p2_is_lcch == 0)
|
||||||
{
|
{
|
||||||
|
int len =
|
||||||
err = crc12_xb_bridge(payload, 180-12);
|
err = crc12_xb_bridge(payload, 180-12);
|
||||||
if (err != 0) //CRC Failure, warn or skip.
|
if (err != 0) //CRC Failure, warn or skip.
|
||||||
{
|
{
|
||||||
@@ -133,16 +131,6 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|||||||
fprintf (stderr, "TG %d ", state->lasttg);
|
fprintf (stderr, "TG %d ", state->lasttg);
|
||||||
fprintf (stderr, "SRC %d ", state->lastsrc);
|
fprintf (stderr, "SRC %d ", state->lastsrc);
|
||||||
|
|
||||||
/*
|
|
||||||
When the talker radio is initiating an individual call (unit to unit or telephone interconnect), the reserved group ID of zero
|
|
||||||
is used in the group address portion of the MAC_PTT PDU and the source ID is that of the talker radio.
|
|
||||||
|
|
||||||
The outbound SACCH for the talker radio containing the talker ID information is required at the
|
|
||||||
talker radio site and optional at other sites. (So, if its from an external site, then it can be zero?)
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// if (state->lastsrc == 0) fprintf (stderr, "External ");
|
|
||||||
|
|
||||||
state->payload_algid = SMAC[10];
|
state->payload_algid = SMAC[10];
|
||||||
state->payload_keyid = (SMAC[11] << 8) | SMAC[12];
|
state->payload_keyid = (SMAC[11] << 8) | SMAC[12];
|
||||||
@@ -161,10 +149,6 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|||||||
// fprintf (stderr, "ENC");
|
// fprintf (stderr, "ENC");
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
@@ -183,7 +167,6 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|||||||
fprintf (stderr, "TG %d ", state->lasttgR);
|
fprintf (stderr, "TG %d ", state->lasttgR);
|
||||||
fprintf (stderr, "SRC %d ", state->lastsrcR);
|
fprintf (stderr, "SRC %d ", state->lastsrcR);
|
||||||
|
|
||||||
// if (state->lastsrcR == 0) fprintf (stderr, "External ");
|
|
||||||
|
|
||||||
state->payload_algidR = SMAC[10];
|
state->payload_algidR = SMAC[10];
|
||||||
state->payload_keyidR = (SMAC[11] << 8) | SMAC[12];
|
state->payload_keyidR = (SMAC[11] << 8) | SMAC[12];
|
||||||
@@ -202,22 +185,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|||||||
// fprintf (stderr, "ENC");
|
// fprintf (stderr, "ENC");
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gainR = opts->audio_gain;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->payload == 1)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n MAC_PTT_PAYLOAD_S OFFSET: %d RES: %d \n ", mac_offset, res);
|
|
||||||
for (int i = 0; i < 24; i++)
|
|
||||||
{
|
|
||||||
if (i == 12) fprintf (stderr, "\n ");
|
|
||||||
fprintf (stderr, "[%02llX]", SMAC[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
//do not permit MAC_PTT_END with CRC errs, help prevent false positives on calls
|
//do not permit MAC_PTT_END with CRC errs, help prevent false positives on calls
|
||||||
@@ -247,11 +215,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|||||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||||
|
|
||||||
//blank the call string here -- slot variable is already flipped accordingly for sacch
|
//blank the call string here -- slot variable is already flipped accordingly for sacch
|
||||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces -- wrong placement!
|
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
@@ -273,92 +237,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|||||||
|
|
||||||
//close any open MBEout files
|
//close any open MBEout files
|
||||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||||
|
|
||||||
//blank the call string here -- slot variable is already flipped accordingly for sacch
|
|
||||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces -- wrong placement!
|
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gainR = opts->audio_gain;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return to CC on MAC_END_PTT if other slot is idle
|
|
||||||
//TODO: Look at the source address of the END_PTT, if it is 0xFFFFFF, then its from the FNE?
|
|
||||||
//if from the FNE, that may be when we know channel teardown will really occur vs using MAC_END_PTT directly
|
|
||||||
|
|
||||||
/*
|
|
||||||
Upon receipt of a MAC_END_PTT PDU on the assigned VCH, and having verified it contains the
|
|
||||||
correct color code, the SU shall return to the idle state on the control channel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//NOTE: Disable return later on if not desirable to use
|
|
||||||
|
|
||||||
//end_ptt in this slot, idle in the other slot (Normal Slots)
|
|
||||||
if ( ((state->currentslot == 0) && (state->dmrburstL == 24)) ||
|
|
||||||
((state->currentslot == 1) && (state->dmrburstR == 24)) )
|
|
||||||
{
|
|
||||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
|
||||||
if (state->p25_cc_is_tdma == 0)
|
|
||||||
{
|
|
||||||
state->samplesPerSymbol = 10;
|
|
||||||
state->symbolCenter = 4;
|
|
||||||
//re-enable both slots
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
opts->slot2_on = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
state->lasttg = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->lasttgR = 0;
|
|
||||||
state->lastsrcR = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
state->payload_keyidR = 0;
|
|
||||||
// state->payload_miP = 0;
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[0], "%s", "");
|
|
||||||
sprintf (state->active_channel[1], "%s", "");
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
|
||||||
}
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
state->lasttg = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->lasttgR = 0;
|
|
||||||
state->lastsrcR = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
state->payload_keyidR = 0;
|
|
||||||
// state->payload_miP = 0;
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[0], "%s", "");
|
|
||||||
sprintf (state->active_channel[1], "%s", "");
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
if (opcode == 0x3 && err == 0)
|
if (opcode == 0x3 && err == 0)
|
||||||
@@ -455,8 +334,6 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
opcode = (payload[0] << 2) | (payload[1] << 1) | (payload[2] << 0);
|
opcode = (payload[0] << 2) | (payload[1] << 1) | (payload[2] << 0);
|
||||||
int mac_offset = 0;
|
int mac_offset = 0;
|
||||||
mac_offset = (payload[3] << 2) | (payload[4] << 1) | (payload[5] << 0);
|
mac_offset = (payload[3] << 2) | (payload[4] << 1) | (payload[5] << 0);
|
||||||
int res = (payload[6] << 1) | (payload[7] << 0);
|
|
||||||
UNUSED(mac_offset);
|
|
||||||
|
|
||||||
//attempt CRC check to validate or reject PDU
|
//attempt CRC check to validate or reject PDU
|
||||||
int err = -2;
|
int err = -2;
|
||||||
@@ -509,7 +386,6 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
fprintf (stderr, "TG %d ", state->lasttg);
|
fprintf (stderr, "TG %d ", state->lasttg);
|
||||||
fprintf (stderr, "SRC %d ", state->lastsrc);
|
fprintf (stderr, "SRC %d ", state->lastsrc);
|
||||||
|
|
||||||
// if (state->lastsrc == 0) fprintf (stderr, "External ");
|
|
||||||
|
|
||||||
state->payload_algid = FMAC[10];
|
state->payload_algid = FMAC[10];
|
||||||
state->payload_keyid = (FMAC[11] << 8) | FMAC[12];
|
state->payload_keyid = (FMAC[11] << 8) | FMAC[12];
|
||||||
@@ -528,10 +404,6 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
// fprintf (stderr, "ENC");
|
// fprintf (stderr, "ENC");
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
@@ -549,7 +421,6 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
fprintf (stderr, "TG %d ", state->lasttgR);
|
fprintf (stderr, "TG %d ", state->lasttgR);
|
||||||
fprintf (stderr, "SRC %d ", state->lastsrcR);
|
fprintf (stderr, "SRC %d ", state->lastsrcR);
|
||||||
|
|
||||||
// if (state->lastsrcR == 0) fprintf (stderr, "External ");
|
|
||||||
|
|
||||||
state->payload_algidR = FMAC[10];
|
state->payload_algidR = FMAC[10];
|
||||||
state->payload_keyidR = (FMAC[11] << 8) | FMAC[12];
|
state->payload_keyidR = (FMAC[11] << 8) | FMAC[12];
|
||||||
@@ -568,20 +439,6 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
// fprintf (stderr, "ENC");
|
// fprintf (stderr, "ENC");
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gainR = opts->audio_gain;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->payload == 1)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n MAC_PTT_PAYLOAD_F OFFSET: %d RES: %d \n ", mac_offset, res);
|
|
||||||
for (int i = 0; i < 24; i++)
|
|
||||||
{
|
|
||||||
if (i == 12) fprintf (stderr, "\n ");
|
|
||||||
fprintf (stderr, "[%02llX]", FMAC[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
@@ -612,10 +469,6 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
|
|
||||||
//blank the call string here
|
//blank the call string here
|
||||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain; //reset
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
@@ -637,80 +490,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|||||||
|
|
||||||
//close any open MBEout files
|
//close any open MBEout files
|
||||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||||
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gainR = opts->audio_gain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return to CC on MAC_END_PTT if other slot is idle
|
|
||||||
//NOTE: Disable return later on if not desirable to use
|
|
||||||
|
|
||||||
//end_ptt in this slot, idle in the other slot (Normal Slots)
|
|
||||||
if ( ((state->currentslot == 0) && (state->dmrburstR == 24)) ||
|
|
||||||
((state->currentslot == 1) && (state->dmrburstL == 24)) )
|
|
||||||
{
|
|
||||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
|
||||||
if (state->p25_cc_is_tdma == 0)
|
|
||||||
{
|
|
||||||
state->samplesPerSymbol = 10;
|
|
||||||
state->symbolCenter = 4;
|
|
||||||
//re-enable both slots
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
opts->slot2_on = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
state->lasttg = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->lasttgR = 0;
|
|
||||||
state->lastsrcR = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
state->payload_keyidR = 0;
|
|
||||||
// state->payload_miP = 0;
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[0], "%s", "");
|
|
||||||
sprintf (state->active_channel[1], "%s", "");
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
|
||||||
}
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
state->lasttg = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->lasttgR = 0;
|
|
||||||
state->lastsrcR = 0;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
state->payload_keyidR = 0;
|
|
||||||
// state->payload_miP = 0;
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[0], "%s", "");
|
|
||||||
sprintf (state->active_channel[1], "%s", "");
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
if (opcode == 0x3 && err == 0)
|
if (opcode == 0x3 && err == 0)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
uint8_t spacer_bit[8]; //check this value to see if its a status thing (like P25 P1)
|
uint8_t spacer_bit[8]; //check this value to see if its a status thing (like P25 P1)
|
||||||
memset (spacer_bit, 0, sizeof (spacer_bit));
|
memset (spacer_bit, 0, sizeof (spacer_bit));
|
||||||
|
uint8_t spacer = 0;
|
||||||
uint16_t bf = 0; //the 16-bit value in-between imbe 2 and imbe 3 that is usually 2175
|
uint16_t bf = 0; //the 16-bit value in-between imbe 2 and imbe 3 that is usually 2175
|
||||||
|
|
||||||
fprintf (stderr," VOICE");
|
fprintf (stderr," VOICE");
|
||||||
@@ -40,7 +41,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KGRN);
|
fprintf (stderr, "%s", KGRN);
|
||||||
fprintf (stderr, " Site: %lld AFS: %d-%d LCN: %d ",
|
fprintf (stderr, " Site: %lld AFS: %d-%d LCN: %d ",
|
||||||
state->edacs_site_id, (state->lastsrc >> 7) & 0xF, state->lastsrc & 0x7F, state->edacs_tuned_lcn);
|
state->edacs_site_id, (state->lasttg >> 7) & 0xF, state->lasttg & 0x7F, state->edacs_tuned_lcn);
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,15 +214,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||||
if (opts->floating_point == 0)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||||
if (opts->floating_point == 0)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
|
|
||||||
// spacer bits
|
// spacer bits
|
||||||
dibit = getDibit (opts, state);
|
dibit = getDibit (opts, state);
|
||||||
@@ -391,15 +384,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||||
if (opts->floating_point == 0)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||||
if (opts->floating_point == 0)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
|
|
||||||
// spacer bits
|
// spacer bits
|
||||||
dibit = getDibit (opts, state);
|
dibit = getDibit (opts, state);
|
||||||
|
|||||||
@@ -464,11 +464,10 @@ void dc_block_filter(struct demod_state *fm)
|
|||||||
fm->dc_avg = avg;
|
fm->dc_avg = avg;
|
||||||
}
|
}
|
||||||
|
|
||||||
long int rms(int16_t *samples, int len, int step)
|
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;
|
||||||
|
|
||||||
@@ -482,10 +481,7 @@ long 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;
|
||||||
|
|
||||||
rms = (long int)sqrt((p-err) / len);
|
return (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; }
|
|
||||||
return rms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void full_demod(struct demod_state *d)
|
void full_demod(struct demod_state *d)
|
||||||
@@ -734,8 +730,6 @@ int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
|||||||
|
|
||||||
static void optimal_settings(int freq, int rate)
|
static void optimal_settings(int freq, int rate)
|
||||||
{
|
{
|
||||||
UNUSED(rate);
|
|
||||||
|
|
||||||
// giant ball of hacks
|
// giant ball of hacks
|
||||||
// seems unable to do a single pass, 2:1
|
// seems unable to do a single pass, 2:1
|
||||||
int capture_freq, capture_rate;
|
int capture_freq, capture_rate;
|
||||||
@@ -815,34 +809,6 @@ void dongle_init(struct dongle_state *s)
|
|||||||
s->demod_target = &demod;
|
s->demod_target = &demod;
|
||||||
}
|
}
|
||||||
|
|
||||||
void demod_init_ro2(struct demod_state *s)
|
|
||||||
{
|
|
||||||
s->rate_in = rtl_bandwidth;
|
|
||||||
s->rate_out = rtl_bandwidth;
|
|
||||||
s->squelch_level = 0;
|
|
||||||
s->conseq_squelch = 10;
|
|
||||||
s->terminate_on_squelch = 0;
|
|
||||||
s->squelch_hits = 11;
|
|
||||||
s->downsample_passes = 0;
|
|
||||||
s->comp_fir_size = 0;
|
|
||||||
s->prev_index = 0;
|
|
||||||
s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either
|
|
||||||
s->custom_atan = 0;
|
|
||||||
s->deemph = 0;
|
|
||||||
s->rate_out2 = rtl_bandwidth; // -1 flag for disabled -- this enables low_pass_real, seems to work okay
|
|
||||||
s->mode_demod = &fm_demod;
|
|
||||||
s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
|
|
||||||
s->prev_lpr_index = 0;
|
|
||||||
s->deemph_a = 0;
|
|
||||||
s->now_lpr = 0;
|
|
||||||
s->dc_block = 1; //enabling by default, but offset tuning is also enabled, so center spike shouldn't be an issue
|
|
||||||
s->dc_avg = 0;
|
|
||||||
pthread_rwlock_init(&s->rw, NULL);
|
|
||||||
pthread_cond_init(&s->ready, NULL);
|
|
||||||
pthread_mutex_init(&s->ready_m, NULL);
|
|
||||||
s->output_target = &output;
|
|
||||||
}
|
|
||||||
|
|
||||||
void demod_init(struct demod_state *s)
|
void demod_init(struct demod_state *s)
|
||||||
{
|
{
|
||||||
s->rate_in = rtl_bandwidth;
|
s->rate_in = rtl_bandwidth;
|
||||||
@@ -857,7 +823,7 @@ void demod_init(struct demod_state *s)
|
|||||||
s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either
|
s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either
|
||||||
s->custom_atan = 0;
|
s->custom_atan = 0;
|
||||||
s->deemph = 0;
|
s->deemph = 0;
|
||||||
s->rate_out2 = -1; // -1 flag for disabled -- this enables low_pass_real, seems to work okay
|
s->rate_out2 = rtl_bandwidth; // -1 flag for disabled -- this enables low_pass_real, seems to work okay
|
||||||
s->mode_demod = &fm_demod;
|
s->mode_demod = &fm_demod;
|
||||||
s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
|
s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
|
||||||
s->prev_lpr_index = 0;
|
s->prev_lpr_index = 0;
|
||||||
@@ -942,12 +908,12 @@ static unsigned int chars_to_int(unsigned char* buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void *socket_thread_fn(void *arg) {
|
static void *socket_thread_fn(void *arg) {
|
||||||
UNUSED(arg);
|
struct demod_state *d = static_cast<demod_state*>(arg);
|
||||||
|
int r, n;
|
||||||
int n;
|
int sockfd, newsockfd, portno;
|
||||||
int sockfd;
|
socklen_t clilen;
|
||||||
unsigned char buffer[5];
|
unsigned char buffer[5];
|
||||||
struct sockaddr_in serv_addr;
|
struct sockaddr_in serv_addr, cli_addr;
|
||||||
|
|
||||||
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
|
||||||
@@ -969,7 +935,7 @@ static void *socket_thread_fn(void *arg) {
|
|||||||
|
|
||||||
fprintf (stderr, "Main socket started! :-) Tuning enabled on UDP/%d \n", port);
|
fprintf (stderr, "Main socket started! :-) Tuning enabled on UDP/%d \n", port);
|
||||||
|
|
||||||
int new_freq;
|
int new_freq, demod_type, new_squelch, new_gain, agc_mode;
|
||||||
|
|
||||||
while((n = read(sockfd,buffer,5)) != 0) {
|
while((n = read(sockfd,buffer,5)) != 0) {
|
||||||
if(buffer[0] == 0) {
|
if(buffer[0] == 0) {
|
||||||
@@ -996,16 +962,14 @@ void rtlsdr_sighandler()
|
|||||||
|
|
||||||
void open_rtlsdr_stream(dsd_opts *opts)
|
void open_rtlsdr_stream(dsd_opts *opts)
|
||||||
{
|
{
|
||||||
|
struct sigaction sigact;
|
||||||
int r;
|
int r;
|
||||||
rtl_bandwidth = opts->rtl_bandwidth * 1000; //reverted back to straight value
|
rtl_bandwidth = opts->rtl_bandwidth * 1000; //reverted back to straight value
|
||||||
bandwidth_multiplier = (bandwidth_divisor / rtl_bandwidth);
|
bandwidth_multiplier = (bandwidth_divisor / rtl_bandwidth);
|
||||||
|
|
||||||
//this needs to be initted first, then we set the parameters
|
//this needs to be initted first, then we set the parameters
|
||||||
dongle_init(&dongle);
|
dongle_init(&dongle);
|
||||||
//init with low pass if decoding P25 or EDACS/Provoice
|
demod_init(&demod);
|
||||||
if (opts->frame_p25p1 == 1 || opts->frame_p25p2 == 1 || opts->frame_provoice == 1)
|
|
||||||
demod_init_ro2(&demod);
|
|
||||||
else demod_init(&demod);
|
|
||||||
output_init(&output);
|
output_init(&output);
|
||||||
controller_init(&controller);
|
controller_init(&controller);
|
||||||
|
|
||||||
@@ -1111,30 +1075,16 @@ void cleanup_rtlsdr_stream()
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
//find way to modify this function to allow hopping (tuning) while squelched and send 0 sample?
|
//find way to modify this function to allow hopping (tuning) while squelched and send 0 sample?
|
||||||
int 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)
|
||||||
{
|
{
|
||||||
UNUSED2(opts, state);
|
if (output.queue.empty())
|
||||||
|
|
||||||
while (output.queue.empty())
|
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
safe_cond_wait(&output.ready, &output.ready_m);
|
||||||
clock_gettime(CLOCK_REALTIME, &ts);
|
|
||||||
ts.tv_nsec += 10e6;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&output.ready_m);
|
|
||||||
pthread_cond_timedwait(&output.ready, &output.ready_m, &ts);
|
|
||||||
pthread_mutex_unlock(&output.ready_m);
|
|
||||||
|
|
||||||
if (exitflag)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pthread_rwlock_wrlock(&output.rw);
|
pthread_rwlock_wrlock(&output.rw);
|
||||||
*sample = output.queue.front() * volume_multiplier;
|
*sample = output.queue.front() * volume_multiplier;
|
||||||
output.queue.pop();
|
output.queue.pop();
|
||||||
pthread_rwlock_unlock(&output.rw);
|
pthread_rwlock_unlock(&output.rw);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//function may lag since it isn't running as its own thread
|
//function may lag since it isn't running as its own thread
|
||||||
@@ -1158,18 +1108,13 @@ 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
|
||||||
long int rtl_return_rms()
|
int rtl_return_rms()
|
||||||
{
|
{
|
||||||
long int sr = 0;
|
int sr = 0;
|
||||||
// #ifdef __arm__
|
sr = rms(demod.lowpassed, demod.lp_len, 1);
|
||||||
// sr = 100;
|
// 'Fix' potential negative value overflow from the rms function -- Observed in Windows builds
|
||||||
// #else
|
sr = abs(sr);
|
||||||
//debug -- on main machine, lp_len is around 6420, so this probably contributes to very high CPU usage
|
if (sr > 9999) sr = 9999;
|
||||||
// fprintf (stderr, "LP_LEN: %d \n", demod.lp_len);
|
|
||||||
//I've found that just using a sample size of 160 will give us a good approximation without killing the CPU
|
|
||||||
// sr = rms(demod.lowpassed, demod.lp_len, 1);
|
|
||||||
sr = rms(demod.lowpassed, 160, 1); //I wonder what a reasonable value would be for #2 (input len) there
|
|
||||||
// #endif
|
|
||||||
return (sr);
|
return (sr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
538
src/trellis.cpp
Normal file
538
src/trellis.cpp
Normal file
@@ -0,0 +1,538 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
//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);
|
||||||
|
}
|
||||||
@@ -29,7 +29,6 @@ processX2TDMAdata (dsd_opts * opts, dsd_state * state)
|
|||||||
char cc[4];
|
char cc[4];
|
||||||
int aiei;
|
int aiei;
|
||||||
char bursttype[5];
|
char bursttype[5];
|
||||||
UNUSED4(syncdata, cachdata, cc, aiei);
|
|
||||||
|
|
||||||
#ifdef X2TDMA_DUMP
|
#ifdef X2TDMA_DUMP
|
||||||
int k;
|
int k;
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ processX2TDMAvoice (dsd_opts * opts, dsd_state * state)
|
|||||||
int mutecurrentslot;
|
int mutecurrentslot;
|
||||||
int algidhex, kidhex;
|
int algidhex, kidhex;
|
||||||
int msMode;
|
int msMode;
|
||||||
UNUSED5(lcformat, mfid, lcinfo, cachdata, parity);
|
|
||||||
|
|
||||||
#ifdef X2TDMA_DUMP
|
#ifdef X2TDMA_DUMP
|
||||||
int k;
|
int k;
|
||||||
@@ -511,8 +510,8 @@ processX2TDMAvoice (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
soft_mbe (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
soft_mbe (opts, state, NULL, ambe_fr2, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +532,7 @@ processX2TDMAvoice (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
if (mutecurrentslot == 0)
|
if (mutecurrentslot == 0)
|
||||||
{
|
{
|
||||||
soft_mbe (opts, state, NULL, ambe_fr3, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CACH
|
// CACH
|
||||||
|
|||||||
95
src/ysf.c
95
src/ysf.c
@@ -132,7 +132,7 @@ const int vd2Interleave[104] = {
|
|||||||
25, 51, 77, 103
|
25, 51, 77, 103
|
||||||
};
|
};
|
||||||
|
|
||||||
void ysf_dch_decode (dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint8_t ft, uint8_t cm, uint8_t input[])
|
void ysf_dch_decode (dsd_opts * opts, dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint8_t ft, uint8_t cm, uint8_t input[])
|
||||||
{
|
{
|
||||||
//TODO: Per Call WAV files using these strings
|
//TODO: Per Call WAV files using these strings
|
||||||
int i;
|
int i;
|
||||||
@@ -143,8 +143,6 @@ void ysf_dch_decode (dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint
|
|||||||
char rem1[6];
|
char rem1[6];
|
||||||
char rem2[6];
|
char rem2[6];
|
||||||
|
|
||||||
UNUSED3(bt, fn, ft);
|
|
||||||
|
|
||||||
for (i = 0; i < 20; i++)
|
for (i = 0; i < 20; i++)
|
||||||
dch_bytes[i] = (char)ConvertBitIntoBytes(&input[i*8], 8);
|
dch_bytes[i] = (char)ConvertBitIntoBytes(&input[i*8], 8);
|
||||||
|
|
||||||
@@ -240,7 +238,7 @@ void ysf_dch_decode (dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ysf_dch_decode2 (dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint8_t ft, uint8_t cm, uint8_t input[])
|
void ysf_dch_decode2 (dsd_opts * opts, dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uint8_t ft, uint8_t cm, uint8_t input[])
|
||||||
{
|
{
|
||||||
//TODO: Per Call WAV files using these strings
|
//TODO: Per Call WAV files using these strings
|
||||||
int i;
|
int i;
|
||||||
@@ -250,8 +248,6 @@ void ysf_dch_decode2 (dsd_state * state, uint8_t bn, uint8_t bt, uint8_t fn, uin
|
|||||||
char rem1[6];
|
char rem1[6];
|
||||||
char rem2[6];
|
char rem2[6];
|
||||||
|
|
||||||
UNUSED4(bn, bt, fn, ft);
|
|
||||||
|
|
||||||
for (i = 0; i < 10; i++)
|
for (i = 0; i < 10; i++)
|
||||||
dch_bytes[i] = (char)ConvertBitIntoBytes(&input[i*8], 8);
|
dch_bytes[i] = (char)ConvertBitIntoBytes(&input[i*8], 8);
|
||||||
|
|
||||||
@@ -448,7 +444,7 @@ int ysf_conv_dch2 (dsd_opts * opts, dsd_state * state, uint8_t bn, uint8_t bt, u
|
|||||||
|
|
||||||
//decode the callsign, etc, found in the DCH when no errors
|
//decode the callsign, etc, found in the DCH when no errors
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
ysf_dch_decode2 (state, bn, bt, fn, ft, cm, trellis_buf);
|
ysf_dch_decode2 (opts, state, bn, bt, fn, ft, cm, trellis_buf);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
@@ -541,7 +537,7 @@ int ysf_conv_dch (dsd_opts * opts, dsd_state * state, uint8_t bn, uint8_t bt, ui
|
|||||||
|
|
||||||
//decode the callsign, etc, found in the DCH when no errors
|
//decode the callsign, etc, found in the DCH when no errors
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
ysf_dch_decode (state, bn, bt, fn, ft, cm, trellis_buf);
|
ysf_dch_decode (opts, state, bn, bt, fn, ft, cm, trellis_buf);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
@@ -622,7 +618,7 @@ int ysf_conv_fich (uint8_t input[], uint8_t dest[32])
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t fich_bits[12*4];
|
uint8_t fich_bits[12*4];
|
||||||
uint8_t temp_b[24];
|
char temp_b[24];
|
||||||
bool g[4];
|
bool g[4];
|
||||||
|
|
||||||
// run golay 24_12 error correction
|
// run golay 24_12 error correction
|
||||||
@@ -729,32 +725,6 @@ void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t dbuf[180], int start,
|
|||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
|
|
||||||
if (opts->floating_point == 0)
|
|
||||||
{
|
|
||||||
// processAudio(opts, state); //needed here? -- nothign to test it with
|
|
||||||
|
|
||||||
if (opts->wav_out_f != NULL)
|
|
||||||
writeSynthesizedVoice (opts, state);
|
|
||||||
|
|
||||||
if (opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->floating_point == 1) //float audio is really quiet now (look into it)
|
|
||||||
{
|
|
||||||
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
|
|
||||||
if (opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
@@ -842,7 +812,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
//print some useful decoded stuff
|
//print some useful decoded stuff
|
||||||
if (dt == 0 && err == 0) fprintf (stderr, "V/D1 "); //Voice/Data Type 1
|
if (dt == 0 && err == 0) fprintf (stderr, "V/D1 "); //Voice/Data Type 1
|
||||||
if (dt == 1 && err == 0) fprintf (stderr, "DATA "); //Full Rate Data
|
if (dt == 1 && err == 0) fprintf (stderr, "DATA "); //Full Rate Voice
|
||||||
if (dt == 2 && err == 0) fprintf (stderr, "V/D2 "); //Voice/Data Type 2
|
if (dt == 2 && err == 0) fprintf (stderr, "V/D2 "); //Voice/Data Type 2
|
||||||
if (dt == 3 && err == 0) fprintf (stderr, "VWFR "); //Full Rate Voice
|
if (dt == 3 && err == 0) fprintf (stderr, "VWFR "); //Full Rate Voice
|
||||||
|
|
||||||
@@ -1012,37 +982,14 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
state->errs2 = vech_bits[103]; //should be zero, but if it isn't, then its an error
|
state->errs2 = vech_bits[103]; //should be zero, but if it isn't, then its an error
|
||||||
|
|
||||||
state->debug_audio_errors += state->errs2;
|
|
||||||
|
|
||||||
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
|
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
|
||||||
ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
PrintAMBEData (opts, state, ambe_d);
|
PrintAMBEData (opts, state, ambe_d);
|
||||||
|
|
||||||
if (opts->floating_point == 0)
|
processAudio(opts, state);
|
||||||
{
|
playSynthesizedVoice (opts, state);
|
||||||
processAudio(opts, state);
|
|
||||||
|
|
||||||
if (opts->wav_out_f != NULL)
|
|
||||||
writeSynthesizedVoice (opts, state);
|
|
||||||
if (opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
{
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
|
|
||||||
if (opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1139,32 +1086,6 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
|||||||
processMbeFrame(opts, state, imbe_fr, NULL, NULL);
|
processMbeFrame(opts, state, imbe_fr, NULL, NULL);
|
||||||
state->synctype = st;
|
state->synctype = st;
|
||||||
|
|
||||||
if (opts->floating_point == 0)
|
|
||||||
{
|
|
||||||
// processAudio(opts, state); //needed here? -- seems to be running from within mbelib
|
|
||||||
|
|
||||||
if (opts->wav_out_f != NULL)
|
|
||||||
writeSynthesizedVoice (opts, state);
|
|
||||||
|
|
||||||
if (opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoice(opts, state);
|
|
||||||
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceSS(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->floating_point == 1) //float audio is really quiet now (look into it)
|
|
||||||
{
|
|
||||||
|
|
||||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
|
||||||
|
|
||||||
if (opts->pulse_digi_out_channels == 1)
|
|
||||||
playSynthesizedVoiceFM(opts, state);
|
|
||||||
|
|
||||||
if(opts->pulse_digi_out_channels == 2)
|
|
||||||
playSynthesizedVoiceFS(opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ft == 1 && fn == 0)
|
if (ft == 1 && fn == 0)
|
||||||
|
|||||||
BIN
tone24.wav
Normal file
BIN
tone24.wav
Normal file
Binary file not shown.
BIN
tone48.wav
Normal file
BIN
tone48.wav
Normal file
Binary file not shown.
Reference in New Issue
Block a user