mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
846b202192 | ||
|
|
330ebe2bf3 | ||
|
|
79b4a5e720 | ||
|
|
8186b62a91 | ||
|
|
20f0c852aa | ||
|
|
9e4ae23c0b | ||
|
|
585f6f2fa5 | ||
|
|
a4fba3b19c | ||
|
|
a2180eb5d3 | ||
|
|
514161fefa | ||
|
|
bba059f35f | ||
|
|
5977f865e3 | ||
|
|
ade7c0477f | ||
|
|
a2fded8340 | ||
|
|
005e15c45f | ||
|
|
e9962a8923 | ||
|
|
c6611eae9c | ||
|
|
261193959c | ||
|
|
e7a71eabb6 | ||
|
|
afba84e584 | ||
|
|
96faff7711 | ||
|
|
94166b493c | ||
|
|
6a0b1b2dcf | ||
|
|
5c8e3d95a7 | ||
|
|
4c91588af6 | ||
|
|
35c05654a5 | ||
|
|
fbc9b5fab8 | ||
|
|
1126ab6578 | ||
|
|
0842613b24 | ||
|
|
bf4a4b574c | ||
|
|
380657679e | ||
|
|
0a214af29b | ||
|
|
b008122149 | ||
|
|
7b6feb9e4f | ||
|
|
e4861bf94c | ||
|
|
587a3f01a2 | ||
|
|
8d5c82356e | ||
|
|
df039ab1c1 | ||
|
|
f5e3c6eddd | ||
|
|
fc01712132 | ||
|
|
7ec0bf83b4 | ||
|
|
504476c5db | ||
|
|
f78dbd57bc | ||
|
|
d2b27fdf25 | ||
|
|
3aa20f82b9 | ||
|
|
402b2f0264 | ||
|
|
4dd2328e10 | ||
|
|
98bcdd203e | ||
|
|
741ed51d08 | ||
|
|
5d8e07228e | ||
|
|
4a43a48b2e | ||
|
|
0ef3b4ab4b | ||
|
|
00e0f00974 | ||
|
|
91181f9e93 | ||
|
|
5c42c50a40 | ||
|
|
36399386c5 | ||
|
|
8eee4cd699 | ||
|
|
1410e8bd81 | ||
|
|
915375fb1c | ||
|
|
52fff28dc4 | ||
|
|
bd035622b8 | ||
|
|
44163710f9 | ||
|
|
44b1ccdeae | ||
|
|
34113cb782 | ||
|
|
2a336a9275 | ||
|
|
5c08a9193c | ||
|
|
2cae7f9c18 | ||
|
|
e056c97d9d | ||
|
|
dc49e0d08b | ||
|
|
b639f6af28 | ||
|
|
6b45c4ba9b | ||
|
|
2062502a59 | ||
|
|
a490d9ead2 | ||
|
|
c73832ac2c |
@@ -1,11 +1,64 @@
|
||||
project(dsd-fme-aero)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
#Ubuntu 20.04 uses 3.16.3
|
||||
#Ubuntu 22.04 uses 3.22.1
|
||||
#Arch currently on 3.26.3
|
||||
#Cygwin currently using 3.23.2 (or newer)
|
||||
cmake_minimum_required(VERSION 3.10.2)
|
||||
project(dsd-fme)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
#Set curses to ncurses, and wide true for ascii
|
||||
set(CURSES_NEED_NCURSES TRUE)
|
||||
set(CURSES_NEED_WIDE TRUE)
|
||||
|
||||
#use cmake option -DAERO=ON to enable Aero Builds (OSS support and specific tweaks)
|
||||
option(AERO
|
||||
"Build for Aero Environments (Cygwin)" OFF)
|
||||
if (AERO)
|
||||
add_definitions(-DAERO_BUILD)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DCOLORS=OFF to disable color output
|
||||
option(COLORS
|
||||
"Build with Colors Enabled" ON)
|
||||
if (COLORS)
|
||||
add_definitions(-DPRETTY_COLORS)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DPVC=ON to enable Provoice Conventional Frame Sync
|
||||
option(PVC
|
||||
"Build with Provoice Conventional Frame Sync Enabled" OFF)
|
||||
if (PVC)
|
||||
add_definitions(-DPVCONVENTIONAL)
|
||||
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
|
||||
option(LZ
|
||||
"Build with new LimaZulu Requested NXDN Tweaks Enabled" OFF)
|
||||
if (LZ)
|
||||
add_definitions(-DLIMAZULUTWEAKS)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DTONES to change default location of the tones.wav files (lwvmobile precompiled 'Aero' releases only)
|
||||
option(NXDN
|
||||
"Build with tone wav files in the dsd-fme folder and not in /usr/share/" OFF)
|
||||
if (TN)
|
||||
add_definitions(-DTONES)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DZDEV to change designation of this build from MAIN to zDEV
|
||||
option(NXDN
|
||||
"change designation of this build from MAIN to zDEV" OFF)
|
||||
if (ZDEV)
|
||||
add_definitions(-DZDEV_BUILD)
|
||||
endif ()
|
||||
|
||||
include(git_revision)
|
||||
git_describe(GIT_TAG)
|
||||
|
||||
@@ -14,7 +67,7 @@ find_package(MBE REQUIRED)
|
||||
find_package(ITPP REQUIRED)
|
||||
find_package(RTLSDR)
|
||||
find_package(Curses REQUIRED)
|
||||
find_package(PULSEAUDIO REQUIRED)
|
||||
find_package(PulseAudio REQUIRED)
|
||||
|
||||
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR})
|
||||
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
|
||||
@@ -38,24 +91,24 @@ list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c")
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
ADD_EXECUTABLE(dsd-fme-aero ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme-aero ${LIBS})
|
||||
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS dsd-fme-aero DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# man page
|
||||
find_program(HELP2MAN_FOUND help2man)
|
||||
if (HELP2MAN_FOUND)
|
||||
add_custom_command(TARGET dsd-fme-aero POST_BUILD
|
||||
add_custom_command(TARGET dsd-fme POST_BUILD
|
||||
COMMAND help2man
|
||||
ARGS -n "Digital Speech Decoder"
|
||||
--version-string=${GIT_TAG}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-aero.1
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1
|
||||
--no-info
|
||||
$<TARGET_FILE:dsd-fme-aero>
|
||||
$<TARGET_FILE:dsd-fme>
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-aero.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
|
||||
16
README.md
16
README.md
@@ -1,6 +1,18 @@
|
||||
## Notice
|
||||
|
||||
This branch is for modifications to make a Windows 32-bit binary to be precompiled, please DO NOT use this branch if you are a Linux User, or copy any contents out of here to modify your existing setup!
|
||||
# Digital Speech Decoder - Florida Man Edition
|
||||
|
||||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, 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, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thank you everybody.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Information
|
||||
|
||||
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/main/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/main/examples/trunking.sh "trunking examples").
|
||||
|
||||
## License
|
||||
Copyright (C) 2010 DSD Author
|
||||
|
||||
23
download-and-install-nodeps.sh
Normal file
23
download-and-install-nodeps.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||
echo This will clone, build, and install DSD-FME only.
|
||||
echo If you need dependencies installed, please run download-and-install.sh instead.
|
||||
echo
|
||||
|
||||
read -p "Press enter to continue"
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
67
download-and-install.sh
Normal file
67
download-and-install.sh
Normal file
@@ -0,0 +1,67 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
|
||||
echo MBELib is considered a requirement on this build.
|
||||
echo You must view this notice prior to continuing.
|
||||
echo The Patent Notice can be found at the site below.
|
||||
echo https://github.com/lwvmobile/mbelib#readme
|
||||
echo Please confirm that you have viewed the patent notice by entering y below.
|
||||
echo
|
||||
echo y/N
|
||||
read ANSWER
|
||||
Y='y'
|
||||
if [[ $Y == $ANSWER ]]; then
|
||||
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev
|
||||
|
||||
echo ITPP Manual Build and Install has been temporarily removed from this script due to issues with older versions of Ubuntu.
|
||||
echo Please check to see that libitpp-dev has successfully been downloaded and installed from the repo.
|
||||
read -p "Press enter to continue"
|
||||
|
||||
#wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
||||
#tar xjf itpp*
|
||||
#if you can't cd into this folder, double check folder name first
|
||||
#cd itpp-4.3.1
|
||||
#mkdir build
|
||||
#cd build
|
||||
#cmake ..
|
||||
#make -j `nproc`
|
||||
#sudo make install
|
||||
#sudo ldconfig
|
||||
#cd ..
|
||||
#cd ..
|
||||
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
else
|
||||
echo
|
||||
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
|
||||
fi
|
||||
|
||||
|
||||
|
||||
BIN
dsd-fme2.png
Normal file
BIN
dsd-fme2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
BIN
dsd-fme3.png
Normal file
BIN
dsd-fme3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 251 KiB |
193
examples/Example_Usage.md
Normal file
193
examples/Example_Usage.md
Normal file
@@ -0,0 +1,193 @@
|
||||
### Example Usage and Notes!
|
||||
|
||||
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25. To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
|
||||
|
||||
```
|
||||
-ft XDMA decoder class (P25 1 and 2, and DMR Stereo)
|
||||
-fs DMR Stereo, also may need to use -xr if inverted DMR
|
||||
-fa Legacy Auto (not recommended)
|
||||
-fi NXDN48
|
||||
-fn NXDN96
|
||||
-fp ProVoice
|
||||
-fm dPMR, also may need to use -xd if inverted dPMR.
|
||||
-fr DMR Mono, also may need to use -xr if inverted DMR.
|
||||
-f1 P25P1
|
||||
-f2 P25P2 (may need to specify wacn/sys/nac manually)
|
||||
-fx X2-TDMA
|
||||
```
|
||||
|
||||
## Conventional Frequency "Fast Scanner"
|
||||
This feature is used to allow DSD-FME to use RIGCTL or RTL input and cycle through frequencies as fast as possible to attain a frame sync.
|
||||
|
||||
This works almost identically to how the trunkng methods work, but instead of locking onto a control channel and tuning based on its decoding, it rapidly tunes through all loaded frequencies in a CSV file and stops when it finds a frame sync. This method is meant for loading a bunch of conventional non-trunking frequencies that signal only when voice or short data bursts are present (DMR T2, Conventional P25 P1, Conventional NXDN, etc) and decode them until the frame sync stops and then resume its scan. This method uses SDR++ RIGCTL, or RTL internal handling to go through signal. -Y is the fast scanner switch.
|
||||
|
||||
To scan through a mixture of DMR and P25 Conventional, use:
|
||||
`dsd-fme -i tcp -C channel_map.csv -G group.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
To scan through NXDN48 only conventional, use:
|
||||
`dsd-fme -fi -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
To scan through NXDN96 only conventional, use:
|
||||
`dsd-fme -fn -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
The Channel Map setup will be identical to any of the channel maps found for trunking systems, channel numbers do not matter and can be arbitrarily organized, and frequencies can be duplicated to be 'scanned' more frequently in larger CSV files. Scan speed by default is 1 second, and is most stable at that speed. This can be adjusted by using the `-t 2` option, for example, to specify 2 seconds of hang time per frequency. ~~If activity occurs on a frequency, an additional 2 seconds of 'hangtime' will occur on that frequency for any follow up voice activity.~~
|
||||
|
||||
Please Note: DMR Simplex may not behave well on fast scan, I have not been able to test it as such, but given the nature of the on-off timeslot signalling on DMR Simplex, missed frame syncs and skipping/resuming scan may occur.
|
||||
|
||||
## Trunking Examples
|
||||
Please see trunking.sh for sample start up scripts or scroll down to the bottom for more explanation.
|
||||
|
||||
## Example Usage - Default Decoder, Ncurses Terminal, Pulse Input/Output, and Log Console to file
|
||||
`dsd-fme -N 2> voice.log`
|
||||
|
||||
and in a second terminal tab, same folder, run
|
||||
|
||||
`tail -n 40 -f voice.log`
|
||||
|
||||
Then you can open up your pavucontrol "Pulse Audio Volume Control" or "Volume Control" application and route input into DSD-FME from any application and DSD-FME output to the left and right speakers respectively. (unlock the channel in the application stream and adjust left and right independently)
|
||||
|
||||
### Input ###
|
||||
|
||||
--TCP Direct Audio Link with SDR++
|
||||
|
||||
`dsd-fme -i tcp` Currently defaults to localhost:7355 (SDR++ defaults)
|
||||
|
||||
`dsd-fme -i tcp:192.168.7.5:7356` (remote host and custom port)
|
||||
|
||||
--48000/9600 Mono Wav File Input
|
||||
|
||||
`dsd-fme -i filename.wav` 48k/1 Audio (SDR++, GQRX wav recordings)
|
||||
|
||||
`dsd-fme -i filename.wav -s 96000` 96k/1 (DSDPlus Raw Signal Wav Files)
|
||||
|
||||
Wav File Input Note: Due to 96000 rate audio requiring me to double the symbol rate and center, be sure to use the -s 96000 at the very end of the startup command. Also, some NXDN48/96 may have difficulties decoding properly with wav file input.
|
||||
|
||||
## Example Usage - RTL2832 Dongle Input
|
||||
Short Setup (all default values):
|
||||
|
||||
`dsd-fme -i rtl`
|
||||
|
||||
Detailed Setup:
|
||||
|
||||
`dsd-fme -ft -i rtl:0:154.9875M:26:-2:8:0:6020 `
|
||||
|
||||
```
|
||||
RTL-SDR options:
|
||||
Usage: rtl:dev:freq:gain:ppm:bw:sq:udp
|
||||
NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended
|
||||
dev <num> RTL-SDR Device Index Number
|
||||
freq <num> RTL-SDR Frequency (851800000 or 851.8M)
|
||||
gain <num> RTL-SDR Device Gain (0-49)(default = 0; Hardware AGC recommended)
|
||||
ppm <num> RTL-SDR PPM Error (default = 0)
|
||||
bw <num> RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24)
|
||||
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
|
||||
udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)
|
||||
Example: dsd-fme-zdev -fs -i rtl -C cap_plus_channel.csv -T
|
||||
Example: dsd-fme-zdev -fp -i rtl:0:851.375M:22:-2:24:0:6021
|
||||
|
||||
```
|
||||
|
||||
## Example Usage - Extra Payload/PDU Logging
|
||||
|
||||
`dsd-fme -Z -N 2> log.ans`
|
||||
|
||||
and in a second terminal tab, same folder, run
|
||||
|
||||
`tail -n 40 -f log.ans`
|
||||
|
||||
### EDACS/P25/NXDN/DMR Simple/Single VFO Trunking ###
|
||||
|
||||
EDACS Trunking (w/ channel map import)
|
||||
|
||||
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (Tested and Working on EDACS/EDACS-EA with Provoice only, no analog voice monitoring)
|
||||
|
||||
`dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--NXDN48 Trunking (standard band plan) with SDR++ (untested for frequency accuracy)
|
||||
|
||||
`dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--NXDN48 Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 in channel_map.csv)
|
||||
|
||||
`dsd-fme -fi -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
|
||||
|
||||
--DMR Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 (TIII and Con+) in channel_map.csv)
|
||||
|
||||
`dsd-fme -fs -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
|
||||
|
||||
--P25 Trunking P1 and P2 (C4FM) with SDR++
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--P25 Trunking (QPSK) with P1 Control Channel (Should switch symbol rate and center on Phase 2 audio channels)
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N -mq 2> log.ans`
|
||||
|
||||
--P25 Trunking Phase 2 TDMA Control Channel systems with QPSK (non Phase 1 systems)
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N -f2 -m2 2> log.ans`
|
||||
|
||||
Trunking Note1: All samples above can also be run with the RTL input method and setting of RTL UDP remote port. In terms of performance, however, SDR++ will do a much better job on weaker/marginal signal compared to the RTL input. RTL input should only be used on strong signal.
|
||||
|
||||
`dsd-fme -fp -i rtl:0:851.8M:22:-2:24:0:6020 -T -C channel_map.csv -G group.csv -N 2> log.ans`
|
||||
|
||||
Trunking Note2: QPSK Phase 1 and Phase 2 Systems may be subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
|
||||
|
||||
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but setting a fake channel number (i.e. 999) first with the CC frequency will result in finding the CC faster on startup if desired. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus channel numbering (as best as I can figure it, but they seem consistent) into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the Cd (channel decimal) values from the log, and not the C+ (dsdplus) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
|
||||
|
||||
```
|
||||
Talkgroup Voice Channel Grant (TV_GRANT) - Logical
|
||||
Ch [036] Cd [0054] C+ [0110] - TS [1] - Target [01900500] - Source [01900505]
|
||||
```
|
||||
|
||||
Use channel 54 in your import file, which would correspond to dsdplus channels 109 and 110 (109 = TS0 / 110 = TS1).
|
||||
|
||||
For Connect Plus, enumerate your list from 1 to the last channel and add the frequency. For Capacity Plus, LSN 1 and 2 will share the same frequency, 3 and 4 will share, 5 and 6 will share, and 7-8 will share, as Capacity Plus counts each 'channel' as two seperate channels (LSN), one for each time slot. Capacity Plus Quirk: DSD-FME makes its best effort to follow the rest channel in the event that the sync is lost for longer than the hangtime, but occassionally, DSD-FME may lose the rest channel and will have to hunt through all frequencies to find it again.
|
||||
|
||||
Trunking Note4: NXDN Trunking v1 will require a channel map. Please see the example folder for an appropriate channel map. NOTICE: NXDN trunking has been fixed on the RTL (rtl_fm) input method and works correctly now using a soft squelch value to determine when to look for frame sync. Tests show this works very well, but squelch adjustments may be required to differentiate the noise floor from the signal.
|
||||
|
||||
NXDN Trunking Update: NXDN DFA (Direct Frequency Assignment) has been coded from the v2 documents, so using a channel map may not be required, as long as the DFA is configured with standard values, and not 'system definable' values. This will only work on trunking systems that use DFA (newer systems) in accordance to the v2 CAI document NXDN TS 1-A Version 2.0 September 2016. If the system uses 'system definable' values, then make sure to put the channels in a channel map csv file as as the 16-bit OFN values for proper tuning.
|
||||
|
||||
NXDN Type-D/IDAS Update: Type-D or IDAS decoding/trunking has been coded now and tested on a small two channel system. Set up a channel map much like Type-C trunking. If preferred, insert channel 31 at the top of your channel map for the 'home repeater' or go to channel of choice during a TX_REL or DISC message. Extensive testing of Type-D has not been conducted. Some cavaets may currently include iffy per call wav file saving and potentially shifting SRC and TGT ID values due to how SCCH messages are handled and how Busy Repeater Messages are handled. Private calls will need to be enabled by enabling 'data calls', if desired. During testing, only data calls came on private calls, so this was set to disabled by default, but can be enabled with data calls enabled. Also, note that some home repeater channels may or may not carry calls from all systems.
|
||||
|
||||
Channel Map and Group CSV Note: Leave the top line of the channel_map.csv and group.csv as the label, do not delete the line, if no line is there, dsd_import skips the first line so it will not import the first channel or first group in those files if there is something there that isn't a label.
|
||||
|
||||
Hytera XPT: Code has been added for XPT system slco/flco/csbk decoding and trunking. The setup will be similar to Capacity Plus trunking in the csv file, listing each LSN channel to a frequency (see examples/hytera_xpt_chan.csv). Currently, this set up is working with smaller XPT systems that I have been able to test with.
|
||||
|
||||
## NCurses Keyboard Shortcuts ##
|
||||
|
||||
Some Keyboard Shortcuts have been implemented for testing to see how users like them. Just hope nobody pushes a key on accident and doesn't know which one it was or what it does. The current list of keyboard shortcuts include:
|
||||
|
||||
```
|
||||
esc or arrow keys - ncurses menu
|
||||
q - quit
|
||||
c - toggle compact mode
|
||||
h - toggle call history
|
||||
z - toggle console payloads
|
||||
a - toggle call alert beep
|
||||
4 - force privacy/scrambler key assertion over enc identifiers (dmr and nxdn)
|
||||
6 - force rc4 key assertion over missing pi header/le enc identifiers (dmr)
|
||||
i - toggle signal inversion on types that can't auto detect (dmr, dpmr)
|
||||
m - toggle c4fm/qpsk 10/4 (everything but phase 2 signal)
|
||||
M - toggle c4fm/qpsk 8/3 (phase 2 tdma control channel)
|
||||
R - start capturing symbol capture bin (date/time name file)
|
||||
r - stop capturing symbol capture bin
|
||||
spacebar - replay last symbol capture bin (captures must be stopped first)
|
||||
s - stop playing symbol capture bin or wav input file
|
||||
P - start per call decoded wav files (Capital P)
|
||||
p - stop per call decoded wav files (Lower p)
|
||||
t - toggle trunking (needs either rtl input, or rigctl connection)
|
||||
y - toggle scanner (needs either rtl input, or rigctl connection)
|
||||
1 - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
||||
2 - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
||||
0 - Toggle Audio Smoothing - May produce crackling if enabled on RTL/TCP or wav/bin files
|
||||
w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode
|
||||
g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN)
|
||||
u - Toggle Trunking Tuning to Private Calls (DMR T3, Cap+, P25)
|
||||
d - Toggle Trunking Tuning to Data Calls (DMR T3, NXDN)
|
||||
e - Toggle Trunking Tuning to Encrypted Calls (P25)
|
||||
8 - Connect to SDR++ TCP Audio Sink with Defaults/Retry Sink Connection on Disconnect
|
||||
9 - Connect to SDR++ RIGCTL Server with Defaults/Retry RIGCTL Connection
|
||||
D - Reset DMR Site Parms/Call Strings, etc.
|
||||
Z - Simulate NoCarrier/No VC/CC sync (capital Z)
|
||||
```
|
||||
164
examples/Install_Notes.md
Normal file
164
examples/Install_Notes.md
Normal file
@@ -0,0 +1,164 @@
|
||||
## How to clone and build this branch
|
||||
|
||||
### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer:
|
||||
|
||||
Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 23.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately.
|
||||
|
||||
If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install.sh
|
||||
chmod +x download-and-install.sh
|
||||
./download-and-install.sh
|
||||
```
|
||||
f
|
||||
If you have dependencies already installed (i.e. need a fresh clean install on a system with DSD-FME already or using system other than Debian/Ubuntu, etc), please run this instead:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install-nodeps.sh
|
||||
chmod +x download-and-install-nodeps.sh
|
||||
./download-and-install-nodeps.sh
|
||||
```
|
||||
|
||||
## Manual Install
|
||||
|
||||
First, install dependency packages. This guide will assume you are using Debian/Ubuntu based distros. Check your package manager for equivalent packages if different.
|
||||
|
||||
Debian/Mint/Ubuntu/Pi
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev
|
||||
```
|
||||
|
||||
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||
|
||||
```
|
||||
sudo dnf install libsndfile-devel fftw-devel lapack-devel rtl-sdr-devel pulseaudio-libs-devel libusb-devel cmake git ncurses ncurses-devel gcc wget pavucontrol gcc-c++
|
||||
```
|
||||
## Headless Ubuntu Server/Pi
|
||||
|
||||
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
|
||||
|
||||
```
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev pulsemixer pulseaudio
|
||||
```
|
||||
|
||||
### Build and Install ITPP - ONLY IF NOT IN REPO!!
|
||||
|
||||
```
|
||||
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
||||
tar xjf itpp*
|
||||
#if you can't cd into this folder, double check folder name first
|
||||
cd itpp-4.3.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
```
|
||||
|
||||
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice") This version of MBELib is 1.3.2 and prints to STDERR, using the stock 1.3.0 MBElib may cause problems with print alignments if paired with this version of DSD-FME, or cause future compatibility issues.
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
```
|
||||
|
||||
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
|
||||
`sudo cp libmbe* /usr/lib`
|
||||
|
||||
Finish by running these steps to clone and build DSD-FME.
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
```
|
||||
|
||||
### Windows Cygwin Builds
|
||||
|
||||
If using RTL input support, you must install libusb-win32 before proceeding with Cygwin installation. You will also need to build and compile a version of librtlsdr, but this can be tricky, and personally, I had to resort to using a much older version of the source code to get it to build at all with the rtl support in the precompiled 'Aero' builds.
|
||||
|
||||
Then install all dependencies available in the repo prior to building, either directly selecting them during setup with the setup-x86.exe or setup-x64.exe or by issuing a command similar to this:
|
||||
|
||||
```
|
||||
setup-x64.exe --packages libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,xfce-pulseaudio-plugin,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,unzip,wget,gcc-g++,libsndfile-devel
|
||||
```
|
||||
|
||||
Then manually install ITPP and MBElib, see above install notes. Be sure to run `cp libmbe* /usr/lib` after compiling MBElib.
|
||||
|
||||
Then you can build and install using
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
cp tone8.wav /usr/share/
|
||||
cp tone24.wav /usr/share/
|
||||
cp tone48.wav /usr/share/
|
||||
chmod 777 /usr/share/tone8.wav
|
||||
chmod 777 /usr/share/tone24.wav
|
||||
chmod 777 /usr/share/tone48.wav
|
||||
mkdir build
|
||||
cd build
|
||||
# -DAERO=ON is optional, but recommended if you want the older OSS support as well
|
||||
cmake -DAERO=ON ..
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
### Virtual Sinks
|
||||
|
||||
You may wish to direct sound into DSD-FME via Virtual Sinks. You may set up a Virtual Sink or two on your machine for routing audio in and out of applications to other applications using the following command, and opening up pavucontrol "PulseAudio Volume Control" in the menu (or `pulsemixer` in headless mode) to change line out of application to virtual sink, and line in of DSD-FME to monitor of virtual sink. This command will not persist past a reboot, so you will need to invoke them each time you reboot, or search for how to add this to your conf files for persistency if desired. Note: This setup is completely optional if using TCP Network Sink Audio and/or RTL Input.
|
||||
|
||||
```
|
||||
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||
pactl load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||
```
|
||||
|
||||
Already have this branch, and just want to pull the latest build? You can run the rebuild.sh file in the dsd-fme folder, or manually do the pull with the commands:
|
||||
|
||||
```
|
||||
##Open your clone folder##
|
||||
git pull
|
||||
##cd into your build folder##
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
```
|
||||
|
||||
If the call alert wav files aren't playing, then make sure to run the following in the dsd-fme folder to copy the wav files to the /usr/share/ folder and give them adequate permission to be accessed.
|
||||
|
||||
```
|
||||
sudo cp tone8.wav /usr/share/
|
||||
sudo cp tone24.wav /usr/share/
|
||||
sudo cp tone48.wav /usr/share/
|
||||
sudo chmod 777 /usr/share/tone8.wav
|
||||
sudo chmod 777 /usr/share/tone24.wav
|
||||
sudo chmod 777 /usr/share/tone48.wav
|
||||
```
|
||||
10
examples/capacity_plus_chan.csv
Normal file
10
examples/capacity_plus_chan.csv
Normal file
@@ -0,0 +1,10 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,858606250
|
||||
2,858606250
|
||||
3,859606250
|
||||
4,859606250
|
||||
5,860606250
|
||||
6,860606250
|
||||
7,861606250
|
||||
8,861606250
|
||||
|
||||
|
19
examples/connect_plus_chan.csv
Normal file
19
examples/connect_plus_chan.csv
Normal file
@@ -0,0 +1,19 @@
|
||||
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
999,862093750,default cc (come here first), optional use non-existent channel as first entry
|
||||
1,863093750
|
||||
2,862093750
|
||||
3,861093750
|
||||
4,860093750
|
||||
5,859093750
|
||||
6,863593750
|
||||
7,862593750
|
||||
8,861593750
|
||||
9,860593750
|
||||
10,859593750
|
||||
11,863393750
|
||||
12,862393750
|
||||
13,861393750
|
||||
14,860393750
|
||||
15,859393750
|
||||
|
||||
|
||||
|
8
examples/dmr_t3_chan.csv
Normal file
8
examples/dmr_t3_chan.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
999,456318750,default cc (come here first), optional use non-existent channel as first entry
|
||||
36,455756250
|
||||
54,455981250
|
||||
81,456318750
|
||||
|
||||
|
||||
|
||||
|
6
examples/edacs_channel_map.csv
Normal file
6
examples/edacs_channel_map.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,851375000
|
||||
2,851800000
|
||||
3,855987500
|
||||
4,858487500
|
||||
5,852312500
|
||||
|
5
examples/group.csv
Normal file
5
examples/group.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
DEC,Mode(A- Allow, B - Block, DE - Digital Enc),Name of Group,Tag (do not delete this line or won't import properly)
|
||||
100,B,Example Name,Tag
|
||||
1449,A,Fire Dispatch,Fire
|
||||
929,A,Fire Tac,Fire
|
||||
22033,DE,Law Dispatch,Law
|
||||
|
10
examples/hytera_xpt_chan.csv
Normal file
10
examples/hytera_xpt_chan.csv
Normal file
@@ -0,0 +1,10 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,858606250
|
||||
2,858606250
|
||||
3,859606250
|
||||
4,859606250
|
||||
5,860606250
|
||||
6,860606250
|
||||
7,861606250
|
||||
8,861606250
|
||||
|
||||
|
6
examples/multi_key.csv
Normal file
6
examples/multi_key.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
key id or tg id (dec), key number or value (dec) //NXDN Scrambler, BP, 10-char Hytera BP only
|
||||
2,70
|
||||
1,123
|
||||
100,70
|
||||
12,48713912656
|
||||
672560,254
|
||||
|
5
examples/multi_key_hex.csv
Normal file
5
examples/multi_key_hex.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
key id(hex), key value (hex) //10-char Hytera BP, RC4
|
||||
1,1234567890
|
||||
2,ABCDEF1234
|
||||
C,0B57935150
|
||||
64,0B57935150
|
||||
|
8
examples/nxdn_chan_map.csv
Normal file
8
examples/nxdn_chan_map.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
channel(dec), freq(Hz)
|
||||
141,423862500
|
||||
142,424337500
|
||||
143,424912500
|
||||
203,424100000
|
||||
204,424625000
|
||||
271,422650000
|
||||
302,423287500
|
||||
|
5
examples/nxdn_sc_key.csv
Normal file
5
examples/nxdn_sc_key.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
key(dec) or tg(dec), value(dec), load any single keys as key 0
|
||||
0,23466
|
||||
1,12345
|
||||
2,32700
|
||||
63,32767
|
||||
|
45
examples/trunking.sh
Normal file
45
examples/trunking.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
#example trunking sh scripts (SDR++ with RIGCTL and RTL Input)
|
||||
#make sure to put a # in front of all lines except the one you wish to use
|
||||
|
||||
#P25 P1 FDMA CC with C4FM
|
||||
#dsd-fme -i tcp -U 4532 -T -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:850M:0:-2:12 -T -N 2> log.ans
|
||||
|
||||
#P25 P1 FDMA CC with QPSK (Simulcast)
|
||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -mq -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -mq -N 2> log.ans
|
||||
|
||||
#P25 P2 TDMA CC with QPSK (Simulcast)
|
||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -m2 -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
|
||||
|
||||
#DMR TIII, Con+, Cap+, XPT
|
||||
dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans
|
||||
#dsd-fme -fs -i rtl:0:450M:44:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#EDACS/EDACS-EA Digital Only
|
||||
#dsd-fme -fp -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
#dsd-fme -fp -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#NXDN48 Type-C or Type-D Trunking with Channel Map
|
||||
#dsd-fme -fi -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
||||
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -C nxdn_channel_map.csv -N 2> log.ans
|
||||
|
||||
#NXDN48 Type-C Trunking with DFA
|
||||
#dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans
|
||||
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -N 2> log.ans
|
||||
|
||||
#NXDN96 Trunking with Channel Map
|
||||
#dsd-fme -fn -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
||||
#dsd-fme -fn -i rtl -T -C nxdn_channel_map.csv -N 2> log.ans
|
||||
|
||||
#Notes: parameters after -i tcp can be omitted if using localhost as the default hostname to connect
|
||||
#and 7355 as the default port number. -U is the port number for RIGCTL and will mirror the tcp hostname
|
||||
#running under the assumption that the user will be connnecting the VFO to the same instance of SDR++
|
||||
#You can also specify an ip address to connect to a remote SDR++ instance, make sure that the settings
|
||||
#inside of SDR++ match, i.e., change in SDR++ from 'localhost' to an IP to bind to (machine's IP address)
|
||||
|
||||
#Note2: RTL input should only be used on strong signal, the SDR++ VFO will perform much better on marginal signal
|
||||
#paramters after -i rtl can also be omitted now if using the default configurations
|
||||
|
||||
#Having a -G group.csv is purely optional, but useful if you want to block groups, or give groups names
|
||||
@@ -17,7 +17,8 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
//pretty pretty colors
|
||||
//defined by CMakeLists.txt -- Disable by using cmake -DCOLORS=OFF ..
|
||||
#ifdef PRETTY_COLORS
|
||||
#define KNRM "\x1B[0m"
|
||||
#define KRED "\x1B[31m"
|
||||
#define KGRN "\x1B[32m"
|
||||
@@ -26,6 +27,16 @@
|
||||
#define KMAG "\x1B[35m"
|
||||
#define KCYN "\x1B[36m"
|
||||
#define KWHT "\x1B[37m"
|
||||
#else
|
||||
#define KNRM ""
|
||||
#define KRED ""
|
||||
#define KGRN ""
|
||||
#define KYEL ""
|
||||
#define KBLU ""
|
||||
#define KMAG ""
|
||||
#define KCYN ""
|
||||
#define KWHT ""
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
@@ -259,6 +270,7 @@ typedef struct
|
||||
int rtl_udp_port;
|
||||
int rtl_bandwidth;
|
||||
int rtl_started;
|
||||
int rtl_rms;
|
||||
int monitor_input_audio;
|
||||
int pulse_raw_rate_in;
|
||||
int pulse_raw_rate_out;
|
||||
@@ -358,13 +370,19 @@ typedef struct
|
||||
//Trunking - Tune Data Calls
|
||||
uint8_t trunk_tune_data_calls;
|
||||
|
||||
//Trunking - Tune Enc Calls (P25 only on applicable grants with svc opts)
|
||||
uint8_t trunk_tune_enc_calls;
|
||||
|
||||
//OSS audio - slot preference
|
||||
uint8_t slot_preference;
|
||||
int slot_preference;
|
||||
|
||||
//'DSP' Format Output
|
||||
uint8_t use_dsp_output;
|
||||
char dsp_out_file[2048];
|
||||
|
||||
//Use P25p1 heuristics
|
||||
uint8_t use_heuristics;
|
||||
|
||||
} dsd_opts;
|
||||
|
||||
typedef struct
|
||||
@@ -540,8 +558,8 @@ typedef struct
|
||||
//new stuff below here
|
||||
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
|
||||
uint8_t dmr_pdu_sf[2][288]; //unified pdu 'superframe' //[slot][byte]
|
||||
uint8_t cap_plus_csbk_bits[12*8*8]; //CSBK Cap+ FL initial and appended block bit storage
|
||||
uint8_t cap_plus_block_num; //received block number storage
|
||||
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 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)
|
||||
|
||||
@@ -556,6 +574,7 @@ typedef struct
|
||||
char dmr_lrrp_gps[2][200]; //2 slots by 99 char string for string lrrp gps
|
||||
char dmr_site_parms[200]; //string for site/net info depending on type of DMR system (TIII or Con+)
|
||||
char call_string[2][200]; //string for call information
|
||||
char active_channel[31][200]; //string for storing and displaying active trunking channels
|
||||
|
||||
|
||||
dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame;
|
||||
@@ -643,6 +662,7 @@ typedef struct
|
||||
int lcn_freq_roll; //number we have 'rolled' to in search of the CC
|
||||
time_t last_cc_sync_time; //use this to start hunting for CC after signal lost
|
||||
time_t last_vc_sync_time; //flag for voice activity bursts, tune back on con+ after more than x seconds no voice
|
||||
time_t last_active_time; //time the a 'call grant' was received, used to clear the active_channel strings after x seconds
|
||||
int is_con_plus; //con_plus flag for knowing its safe to skip payload channel after x seconds of no voice sync
|
||||
|
||||
//new nxdn stuff
|
||||
@@ -654,13 +674,21 @@ typedef struct
|
||||
uint8_t nxdn_sacch_frame_segcrc[4];
|
||||
uint8_t nxdn_alias_block_number;
|
||||
char nxdn_alias_block_segment[4][4][8];
|
||||
|
||||
//site/srv/cch info
|
||||
char nxdn_location_category[14];
|
||||
uint32_t nxdn_location_sys_code;
|
||||
uint16_t nxdn_location_site_code;
|
||||
|
||||
//channel access information
|
||||
uint8_t nxdn_rcn;
|
||||
uint8_t nxdn_base_freq;
|
||||
uint8_t nxdn_step;
|
||||
uint8_t nxdn_bw;
|
||||
|
||||
//multi-key array
|
||||
unsigned long long int rkey_array[0xFFFF];
|
||||
int keyloader; //let us know the keyloader is active
|
||||
|
||||
//dmr late entry mi
|
||||
uint64_t late_entry_mi_fragment[2][7][3];
|
||||
@@ -733,6 +761,26 @@ typedef struct
|
||||
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
|
||||
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
|
||||
|
||||
//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
|
||||
#define PROVOICE_CONV "00000000000000000000000000000000" //all zeroes should be unobtainable string in the frame_sync synctests
|
||||
#define INV_PROVOICE_CONV "00000000000000000000000000000000" //all zeroes should be unobtainable string in the frame_sync synctests
|
||||
#else
|
||||
#define PROVOICE_CONV "13131333111311311313131313131313" //TX 85 RX 85 (default programming value)
|
||||
#define INV_PROVOICE_CONV "31313111333133133131313131313131" //TX 85 RX 85 (default programming value)
|
||||
#endif
|
||||
//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 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)
|
||||
//same pattern //TX //RX
|
||||
// Sync Pattern = 3131311133313313 31331131 31331131 TX/RX 77 -- 31331131 symbol = 01001101 binary = 77 decimal
|
||||
// Sync Pattern = 3131311133313313 33333333 33333333 TX/RX 0 -- 33333333 symbol = 00000000 binary = 0 decimal
|
||||
// Sync Pattern = 3131311133313313 33333331 33333331 TX/RX 1 -- 33333331 symbol = 00000001 binary = 1 decimal
|
||||
// Sync Pattern = 3131311133313313 13131133 13131133 TX/RX 172 -- 13131133 symbol = 10101100 binary = 172 decimal
|
||||
// Sync Pattern = 3131311133313313 11333111 11333111 TX/RX 199 -- 11333111 symbol = 11000111 binary = 199 decimal
|
||||
// Sync Pattern = 3131311133313313 31313131 31313131 TX/RX 85 -- 31313131 symbol = 01010101 binary = 85 decimal
|
||||
|
||||
#define EDACS_SYNC "313131313131313131313111333133133131313131313131"
|
||||
#define INV_EDACS_SYNC "131313131313131313131333111311311313131313131313"
|
||||
|
||||
@@ -836,8 +884,7 @@ short nxdn_filter(short sample);
|
||||
short dpmr_filter(short sample);
|
||||
|
||||
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr);
|
||||
/* Global functions */
|
||||
uint32_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 ncursesPrinter (dsd_opts * opts, dsd_state * state);
|
||||
@@ -846,10 +893,15 @@ void ncursesClose ();
|
||||
//new NXDN Functions start here!
|
||||
void nxdn_frame (dsd_opts * opts, dsd_state * state);
|
||||
void nxdn_descramble (uint8_t dibits[], int len);
|
||||
//nxdn deinterleaving/depuncturing functions
|
||||
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_cac (dsd_opts * opts, dsd_state * state, uint8_t bits[300]);
|
||||
void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[348]);
|
||||
void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type);
|
||||
//type-d 'idas' deinterleaving/depuncturing functions
|
||||
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction);
|
||||
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type);
|
||||
//end
|
||||
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]);
|
||||
|
||||
@@ -859,6 +911,7 @@ static uint8_t crc6(const uint8_t buf[], int len);
|
||||
static uint16_t crc12f(const uint8_t buf[], int len);
|
||||
static uint16_t crc15(const uint8_t buf[], int len);
|
||||
static uint16_t crc16cac(const uint8_t buf[], int len);
|
||||
static uint8_t crc7_scch(uint8_t bits[], int len); //converted from op25 crc6
|
||||
|
||||
/* NXDN Convolution functions */
|
||||
void CNXDNConvolution_start(void);
|
||||
@@ -881,7 +934,9 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||
void NXDN_decode_srv_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||
void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||
void nxdn_location_id_handler (dsd_state * state, uint32_t location_id);
|
||||
void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||
//Type-D SCCH Message Decoder
|
||||
void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uint8_t direction);
|
||||
|
||||
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
|
||||
|
||||
@@ -957,8 +1012,10 @@ uint8_t crc8(uint8_t bits[], unsigned int len);
|
||||
bool crc8_ok(uint8_t bits[], unsigned int len);
|
||||
uint8_t crc7(uint8_t bits[], unsigned int len);
|
||||
|
||||
//LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
//LFSR and LFSRP code courtesy of https://github.com/mattames/LFSR/
|
||||
void LFSR(dsd_state * state);
|
||||
void LFSRP(dsd_state * state);
|
||||
|
||||
void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state);
|
||||
void LFSR64(dsd_state * state);
|
||||
|
||||
@@ -1000,6 +1057,7 @@ bool QR_16_7_6_decode(unsigned char *rxBits);
|
||||
|
||||
void InitAllFecFunction(void);
|
||||
void resetState (dsd_state * state);
|
||||
void reset_dibit_buffer(dsd_state * state);
|
||||
void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660]);
|
||||
|
||||
//P25 PDU Handler
|
||||
@@ -1045,7 +1103,8 @@ unsigned long long int edacs_bch (unsigned long long int message);
|
||||
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvLCNImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvChanImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvKeyImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvKeyImportDec(dsd_opts * opts, dsd_state * state);
|
||||
int csvKeyImportHex(dsd_opts * opts, dsd_state * state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -1056,6 +1115,9 @@ void open_rtlsdr_stream(dsd_opts *opts);
|
||||
void cleanup_rtlsdr_stream();
|
||||
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state);
|
||||
void rtlsdr_sighandler();
|
||||
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
||||
int rtl_return_rms();
|
||||
void rtl_clean_queue();
|
||||
#endif
|
||||
//DMR TRELLIS
|
||||
void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload);
|
||||
|
||||
16
rebuild.sh
Normal file
16
rebuild.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
echo DSD-FME Digital Speech Decoder - Florida Man Edition
|
||||
echo Automatic Git Pull and Rebuild
|
||||
echo
|
||||
sleep 1
|
||||
##Open your clone folder##
|
||||
git pull
|
||||
sleep 2
|
||||
##cd into your build folder##
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
@@ -34,6 +34,35 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid
|
||||
|
||||
//extra tgt/src handling for XPT
|
||||
uint8_t target_hash[24];
|
||||
uint8_t tg_hash = 0;
|
||||
uint8_t is_xpt = 0;
|
||||
//set flag if XPT
|
||||
if (strcmp (state->dmr_branding_sub, "XPT ") == 0) is_xpt = 1;
|
||||
|
||||
//truncate tgt/src to 16-bit values if XPT
|
||||
if (is_xpt == 1)
|
||||
{
|
||||
target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[24], 16); //destination llid
|
||||
source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 16); //source llid
|
||||
if (gi == 0)
|
||||
{
|
||||
for (int i = 0; i < 16; i++) target_hash[i] = dheader_bits[24+i];
|
||||
tg_hash = crc8 (target_hash, 16);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t is_cap = 0;
|
||||
if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0) is_cap = 1;
|
||||
|
||||
if (is_cap)
|
||||
{
|
||||
//truncate tg on group? or just on private/individual data?
|
||||
if (gi == 0) target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[24], 16);
|
||||
source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 16);
|
||||
}
|
||||
|
||||
//store source for dmr pdu packet handling (lrrp) when not available in completed message
|
||||
if (dpf != 15) state->dmr_lrrp_source[slot] = source;
|
||||
|
||||
@@ -97,8 +126,8 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Slot %d Data Header - ", slot+1);
|
||||
|
||||
if (gi == 1 && dpf != 15) fprintf(stderr, "GROUP - ");
|
||||
if (gi == 0 && dpf != 15) fprintf(stderr, "INDIV - ");
|
||||
if (gi == 1 && dpf != 15) fprintf(stderr, "Group - ");
|
||||
if (gi == 0 && dpf != 15) fprintf(stderr, "Indiv - ");
|
||||
|
||||
if (dpf == 0) fprintf (stderr, "Unified Data Transport (UDT) ");
|
||||
else if (dpf == 1) fprintf (stderr, "Response Packet ");
|
||||
@@ -112,6 +141,9 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
|
||||
if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested ");
|
||||
if (dpf != 15) fprintf (stderr, "- Source: %d Target: %d ", source, target);
|
||||
|
||||
//include the hash value if this is an XPT and if its IND data
|
||||
if (dpf != 15 && is_xpt == 1 && gi == 0) fprintf (stderr, "Hash: %d ", tg_hash);
|
||||
|
||||
//sap string handling
|
||||
if (dpf == 15) sap = p_sap;
|
||||
|
||||
@@ -741,11 +773,12 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
||||
memset (state->dmr_lrrp_source, 0, sizeof(state->dmr_lrrp_source));
|
||||
memset (state->dmr_cach_fragment, 1, sizeof (state->dmr_cach_fragment));
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
memset (state->cap_plus_block_num, 0, sizeof(state->cap_plus_block_num));
|
||||
memset (state->data_header_valid, 0, sizeof(state->data_header_valid));
|
||||
memset (state->data_header_format, 7, sizeof(state->data_header_format));
|
||||
//reset some strings
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
//reset some strings -- resetting call string here causes random blink on ncurses terminal (cap+)
|
||||
// sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
// sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
||||
sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
||||
}
|
||||
18
src/dmr_bs.c
18
src/dmr_bs.c
@@ -339,8 +339,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity
|
||||
dmr_sbrc (opts, state, power);
|
||||
//check the single burst/reverse channel opportunity -- moved
|
||||
// dmr_sbrc (opts, state, power);
|
||||
|
||||
}
|
||||
|
||||
if (internalslot == 1 && vc2 == 6)
|
||||
@@ -348,8 +349,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity
|
||||
dmr_sbrc (opts, state, power);
|
||||
//check the single burst/reverse channel opportunity -- moved
|
||||
// dmr_sbrc (opts, state, power);
|
||||
|
||||
}
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||
@@ -379,7 +381,11 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
fprintf (stderr, "\n");
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
||||
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
||||
if (internalslot == 1 && vc2 == 6) dmr_sbrc (opts, state, power);
|
||||
|
||||
// run alg refresh after vc6 ambe processing
|
||||
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
|
||||
@@ -724,7 +730,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
fprintf (stderr, "\n");
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
//update voice sync time for trunking purposes (particularly Con+)
|
||||
if (opts->p25_is_tuned == 1) state->last_vc_sync_time = time(NULL);
|
||||
|
||||
596
src/dmr_csbk.c
596
src/dmr_csbk.c
@@ -45,7 +45,12 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
|
||||
if(IrrecoverableErrors == 0 && CRCCorrect == 1)
|
||||
{
|
||||
|
||||
//clear stale Active Channel messages here
|
||||
if ( ((time(NULL) - state->last_active_time) > 3) && ((time(NULL) - state->last_vc_sync_time) > 3))
|
||||
{
|
||||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||
}
|
||||
|
||||
//update time to prevent random 'Control Channel Signal Lost' hopping
|
||||
//in the middle of voice call on current Control Channel (con+ and t3)
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
@@ -73,7 +78,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//all of these messages share the same format (thankfully)
|
||||
if (csbk_o == 48) fprintf (stderr, " Private Voice Channel Grant (PV_GRANT)");
|
||||
if (csbk_o == 49) fprintf (stderr, " Talkgroup Voice Channel Grant (TV_GRANT)");
|
||||
if (csbk_o == 50) fprintf (stderr, " Private Broadcast Voice Channel Grant (BTV_GRANT)");
|
||||
if (csbk_o == 50) fprintf (stderr, " Broadcast Voice Channel Grant (BTV_GRANT)"); //listed as private in the appendix (error?)
|
||||
if (csbk_o == 51) fprintf (stderr, " Private Data Channel Grant: Single Item (PD_GRANT)");
|
||||
if (csbk_o == 52) fprintf (stderr, " Talkgroup Data Channel Grant: Single Item (TD_GRANT)");
|
||||
if (csbk_o == 53) fprintf (stderr, " Duplex Private Voice Channel Grant (PV_GRANT_DX)");
|
||||
@@ -99,6 +104,21 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
|
||||
//move mbc variables out of if statement
|
||||
uint8_t mbc_lb = 0; //
|
||||
uint8_t mbc_pf = 0;
|
||||
uint8_t mbc_csbko = 0;
|
||||
uint8_t mbc_res = 0;
|
||||
uint8_t mbc_cc = 0;
|
||||
uint8_t mbc_cdeftype = 0;
|
||||
uint8_t mbc_res2 = 0;
|
||||
unsigned long long int mbc_cdefparms = 0;
|
||||
uint16_t mbc_lpchannum = 0;
|
||||
uint16_t mbc_abs_tx_int = 0;
|
||||
uint16_t mbc_abs_tx_step = 0;
|
||||
uint16_t mbc_abs_rx_int = 0;
|
||||
uint16_t mbc_abs_rx_step = 0;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
//added my best guess as to how dsdplus arrives at a dmr channel value (seems pretty consistent) as C+
|
||||
fprintf (stderr, " Ch [%03X] Cd [%04d] C+ [%04d] - TS [%d] - Target [%08d] - Source [%08d]", lpchannum, lpchannum, pluschannum, lcn, target, source);
|
||||
@@ -107,36 +127,33 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
|
||||
if (lpchannum == 0xFFF) //This is from an MBC, signalling an absolute and not a logical
|
||||
{
|
||||
|
||||
//7.1.1.1.2 Channel Grant Absolute Parameters CG_AP appended MBC PDU
|
||||
uint8_t mbc_lb = cs_pdu_bits[96]; //
|
||||
uint8_t mbc_pf = cs_pdu_bits[97];
|
||||
uint8_t mbc_csbko = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[98], 6);
|
||||
uint8_t mbc_res = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[104], 4);
|
||||
uint8_t mbc_cc = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[108], 4);
|
||||
uint8_t mbc_cdeftype = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[112], 4); //see 7.2.19.7 = 0 for channel parms, 1 through FFFF reserved
|
||||
uint8_t mbc_res2 = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[116], 2);
|
||||
uint64_t mbc_cdefparms = (uint64_t)ConvertBitIntoBytes(&cs_pdu_bits[118], 58); //see 7.2.19.7.1
|
||||
mbc_lb = cs_pdu_bits[96]; //
|
||||
mbc_pf = cs_pdu_bits[97];
|
||||
mbc_csbko = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[98], 6);
|
||||
mbc_res = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[104], 4);
|
||||
mbc_cc = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[108], 4);
|
||||
mbc_cdeftype = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[112], 4); //see 7.2.19.7 = 0 for channel parms, 1 through FFFF reserved
|
||||
mbc_res2 = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[116], 2);
|
||||
long long int mbc_cdefparms = (unsigned long long int)ConvertBitIntoBytes(&cs_pdu_bits[118], 58); //see 7.2.19.7.1
|
||||
|
||||
//this is how you read the 58 parm bits according to the appendix 7.2.19.7.1
|
||||
if (mbc_cdeftype == 0) //if 0, then absolute channel parms
|
||||
{
|
||||
uint16_t mbc_lpchannum = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[118], 12);
|
||||
uint16_t mbc_abs_tx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[130], 10);
|
||||
uint16_t mbc_abs_tx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[140], 13);
|
||||
uint16_t mbc_abs_rx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[153], 10);
|
||||
uint16_t mbc_abs_rx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[163], 13);
|
||||
mbc_lpchannum = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[118], 12);
|
||||
mbc_abs_tx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[130], 10);
|
||||
mbc_abs_tx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[140], 13);
|
||||
mbc_abs_rx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[153], 10);
|
||||
mbc_abs_rx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[163], 13);
|
||||
|
||||
//tx_int (Mhz) + (tx_step * 125) = tx_freq
|
||||
//rx_int (Mhz) + (rx_step * 125) = rx_freq
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " ABS-CHAN [%03X][%04d] - RX INT [%d][%X] - RX STEP [%d][%X]", mbc_lpchannum, mbc_lpchannum, mbc_abs_rx_int, mbc_abs_rx_int, mbc_abs_rx_step, mbc_abs_rx_step );
|
||||
//DOULBE CHECK APPENDIX C - C.1.1.2 Fixed Channel Plan for accurate information (found it after figuring out calc, so might be worth double checking)
|
||||
//The Frequency we want to tune is the RX Frequency
|
||||
freq = (mbc_abs_rx_int * 1000000 ) + (mbc_abs_rx_step * 125);
|
||||
//tx_freq = (mbc_abs_tx_int * 1000000 ) + (mbc_abs_tx_step * 125);
|
||||
|
||||
}
|
||||
else fprintf (stderr, "\n MBC Channel Grant - Unknown Parms: %015llX", mbc_cdefparms); //for any reserved values
|
||||
}
|
||||
|
||||
//print frequency from absolute
|
||||
@@ -149,8 +166,26 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
(stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
}
|
||||
|
||||
//add active channel string to display
|
||||
if (lpchannum != 0 && lpchannum != 0xFFF)
|
||||
{
|
||||
if (csbk_o == 49 || csbk_o == 50) sprintf (state->active_channel[lcn], "Active Group Ch: %d TG: %d; ", lpchannum, target);
|
||||
else if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54) sprintf (state->active_channel[lcn], "Active Data Ch: %d TG: %d; ", lpchannum, target);
|
||||
else sprintf (state->active_channel[lcn], "Active Private Ch: %d TG: %d; ", lpchannum, target);
|
||||
}
|
||||
else if (lpchannum == 0xFFF)
|
||||
{
|
||||
if (csbk_o == 49 || csbk_o == 50) sprintf (state->active_channel[lcn], "Active Group Ch: %d TG: %d; ", mbc_lpchannum, target);
|
||||
else if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54) sprintf (state->active_channel[lcn], "Active Data Ch: %d TG: %d; ", mbc_lpchannum, target);
|
||||
else sprintf (state->active_channel[lcn], "Active Private Ch: %d TG: %d; ", mbc_lpchannum, target);
|
||||
}
|
||||
//update last active channel time
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0 && csbk_o == 49) goto SKIPCALL;
|
||||
if (opts->trunk_tune_group_calls == 0 && csbk_o == 49) goto SKIPCALL; //TV_GRANT
|
||||
if (opts->trunk_tune_group_calls == 0 && csbk_o == 50) goto SKIPCALL; //BTV_GRANT
|
||||
if (csbk_o == 50) csbk_o = 49; //flip to normal group call for group tuning
|
||||
|
||||
//Allow tuning of data calls if user wishes by flipping the csbk_o to a group voice call
|
||||
if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54)
|
||||
@@ -214,13 +249,15 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -615,13 +652,44 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
|
||||
uint8_t target_hash[24];
|
||||
uint8_t tg_hash = 0;
|
||||
|
||||
if (gi == 0) fprintf (stderr, "Individual ");
|
||||
else fprintf (stderr, "Group ");
|
||||
|
||||
if (content == 0) fprintf (stderr, "CSBK - ");
|
||||
else fprintf (stderr, "Data - ");
|
||||
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
// check to see if this is XPT
|
||||
if (strcmp (state->dmr_branding_sub, "XPT ") == 0)
|
||||
{
|
||||
//get 16-bit truncated target and source ids
|
||||
target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16); //40, or 32?
|
||||
source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[64], 16); //56, or 64?
|
||||
|
||||
//check to see if this is indiv data (private) then we will need to report the hash value as well
|
||||
if (gi == 0)
|
||||
{
|
||||
//the crc8 hash is the value represented in the Hytera XPT Site Status CSBK when dealing with indiv data
|
||||
for (int i = 0; i < 16; i++) target_hash[i] = cs_pdu_bits[40+i];
|
||||
tg_hash = crc8 (target_hash, 16);
|
||||
fprintf (stderr, "Source: %d - Target: %d - Hash: %d ", source, target, tg_hash);
|
||||
}
|
||||
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
|
||||
|
||||
}
|
||||
// check to see if this is Cap+
|
||||
else if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0)
|
||||
{
|
||||
//truncate tg on group? or just on private/individual data?
|
||||
if (gi == 0) target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
|
||||
source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[64], 16);
|
||||
int rest = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[60], 4);
|
||||
fprintf (stderr, "Source: %d - Target: %d - Rest Channel: %d", source, target, rest);
|
||||
}
|
||||
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
|
||||
|
||||
}
|
||||
//end tier 2 csbks
|
||||
|
||||
@@ -656,7 +724,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
|
||||
}
|
||||
|
||||
//Cap+ Neighbors
|
||||
//Cap+ Adjacent Sites
|
||||
if (csbk_o == 0x3B)
|
||||
{
|
||||
|
||||
@@ -664,10 +732,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
fprintf (stderr, " Capacity Plus Neighbor List ");
|
||||
fprintf (stderr, " Capacity Plus Adjacent Sites\n ");
|
||||
|
||||
uint8_t nl[6]; //neighbors numerical value
|
||||
uint8_t nr[6]; //neighbors current rest channel
|
||||
uint8_t nl[6]; //adjacet site numerical value
|
||||
uint8_t nr[6]; //adjacent site current rest channel
|
||||
memset (nl, 0, sizeof (nl));
|
||||
memset (nr, 0, sizeof (nr));
|
||||
|
||||
@@ -675,12 +743,12 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
{
|
||||
nl[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[32+(i*8)], 4);
|
||||
nr[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[36+(i*8)], 4);
|
||||
if (nl[i]) fprintf (stderr, "S: %d R(%d) ", nl[i], nr[i]);
|
||||
if (nl[i]) fprintf (stderr, "Site: %d Rest: %d; ", nl[i], nr[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Cap+ Channel Status
|
||||
|
||||
//Cap+ Channel Status -- Expanded for up to 16 LSNs and private voice/data calls and dual slot csbk_bit storage
|
||||
if (csbk_o == 0x3E)
|
||||
{
|
||||
|
||||
@@ -690,47 +758,53 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
|
||||
uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
|
||||
uint8_t ts = cs_pdu_bits[18]; //timeslot this PDU occurs in
|
||||
uint8_t res = cs_pdu_bits[19]; //unknown, always seems to be 0 -- could be used in larger Cap+? like a bank switch?
|
||||
uint8_t res = cs_pdu_bits[19]; //unknown or unused bit value
|
||||
uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
|
||||
uint8_t group_tally = 0; //set this to the number of active group channels tallied
|
||||
|
||||
uint8_t block_num = state->cap_plus_block_num;
|
||||
uint8_t group_tally = 0; //set this to the number of active channels tallied
|
||||
uint8_t bank_one = 0;
|
||||
uint8_t bank_two = 0;
|
||||
uint8_t b2_start = 0;
|
||||
uint8_t block_num = state->cap_plus_block_num[ts];
|
||||
uint8_t pdflag = 0;
|
||||
uint8_t pdflag2 = 0;
|
||||
uint16_t private_target = 0;
|
||||
uint8_t pd_b2 = 0;
|
||||
uint8_t start = 8;
|
||||
uint8_t end = 8;
|
||||
uint8_t fl_bytes = 0;
|
||||
uint8_t ch[24]; //one bit per channel
|
||||
uint8_t pch[24]; //private or data call channel bits
|
||||
uint16_t tg = 0;
|
||||
int i, j, k, x;
|
||||
//tg and channel info for trunking purposes
|
||||
uint16_t t_tg[24];
|
||||
char cap_active[20]; //local string to concantenate to active channel stuff
|
||||
|
||||
//sanity check
|
||||
if (block_num > 6)
|
||||
{
|
||||
state->cap_plus_block_num = 6;
|
||||
state->cap_plus_block_num[ts] = 6;
|
||||
block_num = 6;
|
||||
}
|
||||
|
||||
uint8_t ch[8]; //one bit per channel
|
||||
uint8_t pch[8]; //private or data call channel bits
|
||||
uint8_t tg = 0;
|
||||
int i, j, k;
|
||||
|
||||
//tg and channel info for trunking purposes
|
||||
uint8_t t_tg[9];
|
||||
//init some arrays
|
||||
memset (t_tg, 0, sizeof(t_tg));
|
||||
|
||||
//initialize group ch and private/data channel bit arrays
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
ch[i] = 0;
|
||||
pch[i] = 0;
|
||||
}
|
||||
memset (ch, 0, sizeof(ch));
|
||||
memset (pch, 0, sizeof(pch));
|
||||
|
||||
//treating FL as a form of LCSS
|
||||
if (fl == 2 || fl == 3) //initial or single block (fl2 or fl3)
|
||||
{
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
for (i = 0; i < 10*8; i++) state->cap_plus_csbk_bits[i] = cs_pdu_bits[i];
|
||||
state->cap_plus_block_num = 0;
|
||||
//NOTE: this has been changed to store per slot
|
||||
memset (state->cap_plus_csbk_bits[ts], 0, sizeof(state->cap_plus_csbk_bits[ts]));
|
||||
for (i = 0; i < 10*8; i++) state->cap_plus_csbk_bits[ts][i] = cs_pdu_bits[i];
|
||||
state->cap_plus_block_num[ts] = 0;
|
||||
}
|
||||
else //appended block (fl0) or final block (fl1)
|
||||
else //appended block (fl 0) or final block (fl 1)
|
||||
{
|
||||
for (i = 0; i < 7*8; i++) state->cap_plus_csbk_bits[i+80+(7*8*block_num)] = cs_pdu_bits[i+24];
|
||||
for (i = 0; i < 7*8; i++) state->cap_plus_csbk_bits[ts][i+80+(7*8*block_num)] = cs_pdu_bits[i+24];
|
||||
block_num++;
|
||||
state->cap_plus_block_num++;
|
||||
state->cap_plus_block_num[ts]++;
|
||||
}
|
||||
|
||||
if (rest_channel != state->dmr_rest_channel)
|
||||
@@ -750,94 +824,204 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
if (fl == 0) fprintf (stderr, " - Appended Block"); //have not yet observed a system use this fl value
|
||||
if (fl == 1) fprintf (stderr, " - Final Block");
|
||||
if (fl == 2) fprintf (stderr, " - Initial Block");
|
||||
if (fl == 3) fprintf (stderr, " - Single Block"); //still considering a single, and not a final
|
||||
if (fl == 3) fprintf (stderr, " - Single Block");
|
||||
|
||||
//look at each group channel bit -- run this PRIOR to checking private or data calls
|
||||
//or else we will overwrite the ch bits we set below for private calls with zeroes
|
||||
//these also seem to indicate data calls -- can't find a distinction of which is which
|
||||
bank_one = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][24], 8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
ch[i] = state->cap_plus_csbk_bits[i+24];
|
||||
if (ch[i] == 1) group_tally++; //figure out where to start looking in the byte stream for the 0x80 flag
|
||||
}
|
||||
ch[i] = state->cap_plus_csbk_bits[ts][i+24];
|
||||
if (ch[i] == 1) group_tally++; //figure out where to start looking in the byte stream for the 0next bank of calls
|
||||
}
|
||||
|
||||
//check for private/data calls -- user will neeed to enable 'data' call tuning in order to tune them
|
||||
uint8_t pdflag = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[40+(group_tally*8)], 8); //seems to be 0x80 (last block flag?) on samples I have
|
||||
uint16_t private_target = 0;
|
||||
//Expanded to cover larger systems up to 16 slots.
|
||||
bank_two = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][32+(group_tally*8)], 8); //32
|
||||
b2_start = group_tally;
|
||||
if (bank_two)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
ch[i+8] = state->cap_plus_csbk_bits[ts][i+32+(b2_start*8)];
|
||||
if (ch[i+8] == 1) group_tally++;
|
||||
}
|
||||
}
|
||||
|
||||
//first, check to see if we have a completed PDU
|
||||
//check flag for appended private and/or data calls
|
||||
pdflag = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][40+(group_tally*8)], 8);
|
||||
|
||||
//check for private activity on LSNs 1-8
|
||||
if (fl == 1 || fl == 3)
|
||||
{
|
||||
//then check to see if this byte has a value, should be 0x80
|
||||
//this bytes location seems to shift depending on level of activity
|
||||
if (pdflag == 0x80) //now looking to see if any appended data was added
|
||||
if (pdflag) //== 0x80 //testing denny's 0x80 or 0x90 flag discovery
|
||||
{
|
||||
k = 0; //= 0
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " F%X Private or Data Call", pdflag);
|
||||
fprintf (stderr, " Bank One F%X Private or Data Call(s) - ", pdflag);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
pch[i] = state->cap_plus_csbk_bits[i+48+(group_tally*8)];
|
||||
pch[i] = state->cap_plus_csbk_bits[ts][i+48+(group_tally*8)];
|
||||
if (pch[i] == 1)
|
||||
{
|
||||
fprintf (stderr, " Ch%d:", i+1);
|
||||
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[56+(k*16)+(group_tally*8)], 16);
|
||||
fprintf (stderr, " LSN %02d:", i+1);
|
||||
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][56+(k*16)+(group_tally*8)], 16);
|
||||
fprintf (stderr, " TGT %d;", private_target);
|
||||
if (opts->trunk_tune_data_calls == 1) t_tg[i] = private_target; //set here for tuning allow/block
|
||||
k++;
|
||||
if (bank_one == 0) bank_one = 0xFF; //set all bits on so we can atleast parse all of them below in listing/display
|
||||
}
|
||||
}
|
||||
//save for starting point of the next private call bank
|
||||
pd_b2 = k;
|
||||
}
|
||||
}
|
||||
//end private/data call check on LSNs 1-8
|
||||
|
||||
//check flag for appended private and/or data calls -- flag two still needs work or testing, double checking, etc, disable if issues arise
|
||||
pdflag2 = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][56+(group_tally*8)+(pd_b2*16)], 8); //48 -- had wrong value here (atleast in the one sample with the false positive)
|
||||
|
||||
//check for private activity on LSNs 9-16
|
||||
if (fl == 1 || fl == 3)
|
||||
{
|
||||
//then check to see if this byte has a value, should be 0x80, could be other?
|
||||
//this bytes location shifts depending on level of activity -- see banks above
|
||||
if (pdflag2) //== 0x80 //testing denny's 0x80 or 0x90 flag discovery
|
||||
{
|
||||
k = 0;
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Bank Two F%02X Private or Data Call(s) - ", pdflag2);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
pch[i+8] = state->cap_plus_csbk_bits[ts][i+64+(group_tally*8)+(pd_b2*16)]; //56
|
||||
if (pch[i+8] == 1)
|
||||
{
|
||||
fprintf (stderr, " LSN %02d:", i+1);
|
||||
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][64+(k*16)+(group_tally*8)+(pd_b2*16)], 16); //56 -- had wrong value here (atleast in the one sample with the false positive)
|
||||
fprintf (stderr, " TGT %d;", private_target);
|
||||
k++;
|
||||
if (bank_two == 0) bank_two = 0xFF; //set all bits on so we can atleast parse all of them below in listing/display
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//end private/data call check
|
||||
//end private/data call check on LSNs 9-16
|
||||
|
||||
// if (fl != 2)
|
||||
if (fl == 1 || fl == 3)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
//additive strings for active channels
|
||||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||
sprintf (state->active_channel[0], "Cap+ ");
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
x = 0;
|
||||
|
||||
//NOTE: New start and end positions will allow the status print
|
||||
//to contract and expand as needed to prevent this from
|
||||
//being a four liner CSBK when there is little or no activity
|
||||
|
||||
//start position;
|
||||
start = 0;
|
||||
if (bank_one & 0xF0) start = 0;
|
||||
else if (rest_channel < 5) start = 0;
|
||||
|
||||
else if (bank_one & 0xF) start = 4;
|
||||
else if (rest_channel > 4 && rest_channel < 9) start = 4;
|
||||
|
||||
else if (bank_two & 0xF0) start = 8;
|
||||
else if (rest_channel > 8 && rest_channel < 13) start = 8;
|
||||
|
||||
else if (bank_two & 0xF) start = 12;
|
||||
else if (rest_channel > 12) start = 12;
|
||||
|
||||
//end position;
|
||||
end = 16;
|
||||
if (bank_two & 0xF) end = 16;
|
||||
else if (rest_channel > 12) end = 16;
|
||||
|
||||
else if (bank_two & 0xF0) end = 12;
|
||||
else if (rest_channel > 9 && rest_channel < 13) end = 12;
|
||||
|
||||
else if (bank_one & 0xF) end = 8;
|
||||
else if (rest_channel > 4 && rest_channel < 9) end = 8;
|
||||
|
||||
else if (bank_one & 0xF0) end = 4;
|
||||
else if (rest_channel < 5) end = 4;
|
||||
|
||||
//start parsing info and listing active LSNs
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
fprintf (stderr, "Ch%d: ", i+1);
|
||||
//skip an additional k value per bank
|
||||
if (i == 8) k++;
|
||||
|
||||
if (start < 1 && i == 4)
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
if (start < 5 && i == 8)
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
if (start < 9 && i == 12)
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
fprintf (stderr, "LSN %02d: ", i+1);
|
||||
if (ch[i] == 1) //group voice channels
|
||||
{
|
||||
tg = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[k*8+32], 8);
|
||||
if (tg != 0) fprintf (stderr, " %03d ", tg);
|
||||
else fprintf (stderr, "Actv ");
|
||||
//add values to trunking tg/channel potentials
|
||||
t_tg[i] = tg;
|
||||
if (tg != 0) k++;
|
||||
|
||||
tg = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][(k*8)+32], 8);
|
||||
if (tg != 0) fprintf (stderr, "%5d; ", tg);
|
||||
else fprintf (stderr, "Group; ");
|
||||
//flag as available for tuning if group calls enabled
|
||||
if (opts->trunk_tune_group_calls == 1) t_tg[i] = tg;
|
||||
if (tg != 0) k++;
|
||||
|
||||
//add active channel to display string
|
||||
sprintf (cap_active, "LSN:%d TG:%d; ", i+1, tg);
|
||||
strcat (state->active_channel[i+1], cap_active);
|
||||
}
|
||||
else if (pch[i] == 1) //private or data channels
|
||||
{
|
||||
fprintf (stderr, "P||D ");
|
||||
//flag as available for tuning if enabled
|
||||
if (opts->trunk_tune_data_calls == 1) ch[i] = 1;
|
||||
}
|
||||
else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
|
||||
else fprintf (stderr, "Idle ");
|
||||
tg = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][(group_tally*8)+(x*16)+56], 16); //don't change this AGAIN!, this is correct!
|
||||
if (tg != 0) fprintf (stderr, "%5d; ", tg);
|
||||
else fprintf (stderr, " P||D; ");
|
||||
//flag as available for tuning if data calls enabled
|
||||
if (opts->trunk_tune_data_calls == 1) t_tg[i] = tg; //ch[i] = 1;
|
||||
if (tg != 0) x++;
|
||||
|
||||
//add active channel to display string
|
||||
|
||||
//NOTE: Consider only adding this if user toggled or else
|
||||
//lots of short data bursts blink in and out
|
||||
if (1 == 1) //opts->trunk_tune_data_calls
|
||||
{
|
||||
sprintf (cap_active, "LSN:%d PC:%d; ", i+1, tg);
|
||||
strcat (state->active_channel[i+1], cap_active);
|
||||
}
|
||||
|
||||
}
|
||||
else if (i+1 == rest_channel) fprintf (stderr, " Rest; ");
|
||||
else fprintf (stderr, " Idle; ");
|
||||
|
||||
if (i == 3) fprintf (stderr, "\n ");
|
||||
}
|
||||
|
||||
|
||||
state->dmr_mfid = 0x10;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
|
||||
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
|
||||
//nullify any previous site_parm data
|
||||
sprintf(state->dmr_site_parms, "%s", "");
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
|
||||
//Skip tuning group calls if group calls are disabled -- moved to individual switches in the parsing phase
|
||||
// if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
|
||||
|
||||
//don't tune if vc on the current channel
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
for (j = 0; j < 8; j++) //go through the channels stored looking for active ones to tune to
|
||||
for (j = start; j < end; j++) //go through the channels stored looking for active ones to tune to
|
||||
{
|
||||
char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
@@ -857,6 +1041,9 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//without priority, this will tune the first one it finds (if group isn't blocked)
|
||||
if (t_tg[j] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
|
||||
{
|
||||
//debug print for tuning verification
|
||||
fprintf (stderr, "\n LSN/TG to tune to: %d - %d", j+1, t_tg[j]);
|
||||
|
||||
if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
|
||||
{
|
||||
//RIGCTL
|
||||
@@ -870,14 +1057,16 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
j = 11; //break loop
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -892,20 +1081,21 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
{
|
||||
fprintf (stderr, "%s\n", KYEL);
|
||||
fprintf (stderr, " CAP+ Multi Block PDU \n ");
|
||||
uint8_t fl_bytes = 0;
|
||||
fl_bytes = 0;
|
||||
for (i = 0; i < (10+(block_num*7)); i++)
|
||||
{
|
||||
fl_bytes = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[i*8], 8);
|
||||
fl_bytes = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][i*8], 8);
|
||||
fprintf (stderr, "[%02X]", fl_bytes);
|
||||
if (i == 17 || i == 35) fprintf (stderr, "\n ");
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
state->cap_plus_block_num = 0;
|
||||
memset (state->cap_plus_csbk_bits[ts], 0, sizeof(state->cap_plus_csbk_bits[ts]));
|
||||
state->cap_plus_block_num[ts] = 0;
|
||||
|
||||
} //if (fl == 1 || fl == 3)
|
||||
} //opcode == 0x3E
|
||||
|
||||
} //fid == 0x10
|
||||
|
||||
//Connect+ Section
|
||||
@@ -947,19 +1137,23 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
|
||||
//add active channel string for display
|
||||
sprintf (state->active_channel[0], "Active Ch: %d TG: %d; ", lcn, grpAddr);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCON;
|
||||
|
||||
//if using rigctl we can set an unknown or updated cc frequency
|
||||
//by polling rigctl for the current frequency
|
||||
if (opts->use_rigctl == 1 && opts->p25_is_tuned == 0) //&& state->p25_cc_freq == 0
|
||||
if (opts->use_rigctl == 1 && opts->p25_is_tuned == 0)
|
||||
{
|
||||
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
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) //&& state->p25_cc_freq == 0
|
||||
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;
|
||||
@@ -1008,15 +1202,17 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[lcn]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_chan_map[lcn]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[lcn];
|
||||
opts->p25_is_tuned = 1;
|
||||
state->is_con_plus = 1; //flag on
|
||||
state->last_vc_sync_time = time(NULL); //bugfix: set sync here so we don't immediately tune back to CC constantly.
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1031,60 +1227,103 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
|
||||
} //end Connect+
|
||||
|
||||
//Hytera XPT
|
||||
//Hytera XPT -- Experimental, but values now seem very consistent and trunking is working on systems tested with
|
||||
if (csbk_fid == 0x68)
|
||||
{
|
||||
//XPT Site Status -- Very Very Experimental, WIP, Don't be surprised by bad decodes or broken trunking
|
||||
//XPT Site Status
|
||||
if (csbk_o == 0x0A)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
uint8_t xpt_ch[6]; //one tg/call per timeslot
|
||||
uint16_t tg = 0; //8-bit TG value or hash
|
||||
uint8_t xpt_ch[6]; //one tg/call per LSN
|
||||
uint16_t tg = 0; //8-bit TG value or TGT hash
|
||||
int i, j;
|
||||
|
||||
//tg and channel info for trunking purposes
|
||||
uint8_t t_tg[24];
|
||||
uint8_t t_tg[6];
|
||||
memset (t_tg, 0, sizeof(t_tg));
|
||||
|
||||
uint8_t xpt_seq = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[0], 2); //this replaces the CSBK lb and pf
|
||||
uint8_t xpt_free = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 4); //free repeater channel
|
||||
uint8_t xpt_free = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 4); //free repeater channel LCN
|
||||
uint8_t xpt_bank = 0;
|
||||
uint8_t xpt_lcn = 1;
|
||||
|
||||
if (xpt_seq) xpt_bank = xpt_seq*6;
|
||||
//determine starting position of LCN value
|
||||
if (xpt_seq == 1) xpt_lcn = 4;
|
||||
if (xpt_seq == 2) xpt_lcn = 7;
|
||||
|
||||
//get 2-bit status values for each 6 channels (timeslots)
|
||||
//determine xpt_bank value for LSN value/tuning
|
||||
if (xpt_seq) xpt_bank = xpt_seq*6;
|
||||
|
||||
//get 2-bit status values for each 6 LSNs
|
||||
for (i = 0; i < 6; i++) xpt_ch[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20+(i*2)], 2);
|
||||
|
||||
fprintf (stderr, " Hytera XPT Site Status - Free RPT: %d SN: %d\n ", xpt_free, xpt_seq);
|
||||
fprintf (stderr, " Hytera XPT Site Status - Free LCN: %d SN: %d", xpt_free, xpt_seq);
|
||||
|
||||
//Print List of Channels and Activity
|
||||
//strings for active channels
|
||||
char xpt_active[20];
|
||||
if (xpt_seq == 0) sprintf (state->active_channel[0], "XPT "); //add initial if sequence 0
|
||||
else sprintf (state->active_channel[xpt_seq], "%s", ""); //blank current sequence to re-write to
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Print List of LCN with LSN Activity
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
fprintf (stderr, "Ch%02d: ", i+xpt_bank+1); //(xpt_seq*6)
|
||||
tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[i*8+32], 8);
|
||||
//add LCN value for each LSN pair to help users differentiate between the two when seeing LCN on FLC
|
||||
if (i == 0 || i == 2 || i == 4)
|
||||
{
|
||||
fprintf (stderr, "\n LCN %d - ", xpt_lcn);
|
||||
xpt_lcn++;
|
||||
}
|
||||
|
||||
//LSN value here is logical slot, in flco, we get the logical channel (which is the repeater, does not include the slot value)
|
||||
fprintf (stderr, "LSN %02d: ", i+xpt_bank+1); //swapped out xpt_bank for all (xpt_seq*6) to simplify things
|
||||
tg = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[i*8+32], 8);
|
||||
fprintf (stderr, "ST-%X", xpt_ch[i]); //status bits value 0,1,2, or 3
|
||||
if (tg != 0) fprintf (stderr, " %03d ", tg);
|
||||
if (tg != 0) fprintf (stderr, " %03d; ", tg);
|
||||
else
|
||||
{
|
||||
if (xpt_ch[i] == 3) fprintf (stderr, " Null "); //offline?, free? but also group call if the TG value is populated? Wut? Null should cover both cases...maybe
|
||||
else if (xpt_ch[i] == 2) fprintf (stderr, " Priv "); //This seems to be used on both private data and private calls, but one or the other has a 0 TG value?
|
||||
else if (xpt_ch[i] == 1) fprintf (stderr, " Unk "); //the 01 value has not been observed as of yet, group data?
|
||||
else if (xpt_ch[i] == 0) fprintf (stderr, " Idle "); //Idle appears to always be a 0, or could indicate Group Data (including status CSBK and VLC/TLC)
|
||||
if (xpt_ch[i] == 3) fprintf (stderr, " Null; "); //NULL on ST-3 indicates repeater is not active for the LSNs that would be covered by these bits
|
||||
else if (xpt_ch[i] == 2) fprintf (stderr, " Priv; "); //This seems to be used on both private data and private voice calls, but occassionally has a 0 TGT value
|
||||
else if (xpt_ch[i] == 1) fprintf (stderr, " Unk; "); //the 01 value has not been observed as of yet
|
||||
else if (xpt_ch[i] == 0) fprintf (stderr, " Idle; "); //Idle
|
||||
|
||||
//if Priv/Unk occurs, add t_tg value to it for tuning purposes
|
||||
if (xpt_ch[i] == 2)
|
||||
{
|
||||
if (opts->trunk_tune_private_calls == 1) t_tg[i] = 1;
|
||||
}
|
||||
|
||||
//could cause erroneous tuning since we don't yet know what the unk value really is (never observed)
|
||||
if (xpt_ch[i] == 1)
|
||||
{
|
||||
// if (opts->trunk_tune_data_calls == 1) t_tg[i] = 1; //disabled
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (i == 2) fprintf (stderr, "\n ");
|
||||
|
||||
// if (i == 2) fprintf (stderr, "\n ");
|
||||
|
||||
//add values to trunking tg/channel potentials
|
||||
if (tg != 0) t_tg[i+(xpt_seq*6)] = tg;
|
||||
if (tg != 0) t_tg[i+xpt_bank] = tg;
|
||||
|
||||
//concantenate string to active channels for ncurses display
|
||||
if (tg != 0)
|
||||
{
|
||||
if (xpt_ch[i] == 3) sprintf (xpt_active, "LSN:%d TG:%d; ", i+xpt_bank+1, tg);
|
||||
if (xpt_ch[i] == 2) sprintf (xpt_active, "LSN:%d PC:%d; ", i+xpt_bank+1, tg);
|
||||
//last two are unknown status but have an associated target value
|
||||
if (xpt_ch[i] == 1) sprintf (xpt_active, "LSN:%d UK:%d; ", i+xpt_bank+1, tg);
|
||||
if (xpt_ch[i] == 0) sprintf (xpt_active, "LSN:%d UK:%d; ", i+xpt_bank+1, tg);
|
||||
strcat (state->active_channel[xpt_seq], xpt_active); //add string to active channel seq
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//add string for ncurses terminal display
|
||||
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free);
|
||||
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
|
||||
|
||||
//assign to cc freq to follow during no sync
|
||||
long int ccfreq = 0;
|
||||
@@ -1116,7 +1355,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPXPT;
|
||||
|
||||
//don't tune if vc on the current channel
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
if ( (time(NULL) - state->last_vc_sync_time) > 2 ) //parenthesis error fixed
|
||||
{
|
||||
for (j = 0; j < 6; j++) //go through the channels stored looking for active ones to tune to
|
||||
{
|
||||
@@ -1131,7 +1370,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//and hope it doesn't clash with other normal TG values
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == t_tg[j+(xpt_seq*6)])
|
||||
if (state->group_array[i].groupNumber == t_tg[j+xpt_bank])
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
@@ -1139,29 +1378,40 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
}
|
||||
|
||||
//without priority, this will tune the first one it finds (if group isn't blocked)
|
||||
if (t_tg[j+(xpt_seq*6)+1] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
|
||||
if (t_tg[j+xpt_bank] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
|
||||
{
|
||||
if (state->trunk_chan_map[j+(xpt_seq*6)+1] != 0) //if we have a valid frequency
|
||||
//debug print for tuning verification
|
||||
fprintf (stderr, "\n LSN/TG to tune to: %d - %d", j+xpt_bank+1, t_tg[j+xpt_bank]);
|
||||
|
||||
if (state->trunk_chan_map[j+xpt_bank+1] != 0) //if we have a valid frequency
|
||||
{
|
||||
//RIGCTL
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
//debug
|
||||
fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
|
||||
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+(xpt_seq*6)+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+(xpt_seq*6)+1];
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+xpt_bank+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+xpt_bank+1];
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+(xpt_seq*6)+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+(xpt_seq*6)+1];
|
||||
#ifdef USE_RTLSDR
|
||||
//debug
|
||||
fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
|
||||
|
||||
rtl_dev_tune (opts, state->trunk_chan_map[j+xpt_bank+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+xpt_bank+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away
|
||||
j = 11; //break loop
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1174,20 +1424,17 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
|
||||
sprintf (state->dmr_branding_sub, "XPT ");
|
||||
|
||||
//Trunking Note: My understanding is that XPT calls always start on the 'home' repeater, and then expand
|
||||
//outward to the free repeaters, so its probably easiest for a user to load the frequencies in a csv file
|
||||
//and let FME scan through them as opposed to actively trunking, it will spend most of the time on the home repeater
|
||||
//and if calls occur on the home repeater, it'll be too busy with those to go to the free repeater
|
||||
//DSD-FME doesn't have any sort of TG priority, so its first come first served, just block or allow
|
||||
//Notes: I had a few issues to fix in this CSBK, but it does appear that this is trunking on a few small systems now,
|
||||
//albeit a very quiet systems that makes it difficult to know for certain if every aspect is working correctly
|
||||
|
||||
//Additional Notes: I've set XPT to set a CC frequency to whichever frequency its tuned to currently and getting
|
||||
//Notes: I've set XPT to set a CC frequency to whichever frequency its tuned to currently and getting
|
||||
//this particular CSBK, if the status portion does work correctly, then it shouldn't matter which frequency it is on
|
||||
//as long as this CSBK comes in and we can tune to other repeater lcns if they have activity and the frequency mapping
|
||||
//is correct in the csv file, assuming the current frequency doesn't have voice activity
|
||||
|
||||
} //end 0x0A
|
||||
|
||||
//XPT Site Information - Adj Site Info??
|
||||
//XPT Adjacent Site Information -- Have yet to find a consistent indication of 'current site' identification in any CSBK/FLC/SLC payload
|
||||
if (csbk_o == 0x0B)
|
||||
{
|
||||
|
||||
@@ -1195,58 +1442,35 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
fprintf (stderr, " Hytera XPT CSBK 0x0B ");
|
||||
int i;
|
||||
uint8_t xpt_site_id[4];
|
||||
uint8_t xpt_site_rp[4];
|
||||
uint8_t xpt_site_u1[4];
|
||||
uint8_t xpt_site_u2[4];
|
||||
|
||||
//wraithe's theory -- seems pretty good to me
|
||||
//still only a theory though until can be verified
|
||||
//by having a system with precisely known variables
|
||||
uint8_t xpt_sn = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[0], 2);
|
||||
|
||||
//new samples show this doesn't always quite work, there seems to be
|
||||
//more than one data set transmitted in this CSBK
|
||||
//one set works, the other doesn't fit the pattern
|
||||
|
||||
// Site ID [5 bits]
|
||||
// Unknown_3 [3 bits]
|
||||
// Free Repeater on site [4 bits]
|
||||
// Unknown_4 [4 bits]
|
||||
|
||||
// 11:44:58 Sync: +DMR slot1 [slot2] | Color Code=01 | CSBK
|
||||
// Hytera XPT CSBK 0x0B
|
||||
// DMR PDU Payload [0B][68][10][20][18][10][20][10][28][20][EF][DA]
|
||||
|
||||
// repeat x3 (for total of 4 sites)
|
||||
|
||||
// int i;
|
||||
// uint8_t xpt_site_id[4];
|
||||
// uint8_t xpt_site_rp[4];
|
||||
// uint8_t xpt_site_u1[4];
|
||||
// uint8_t xpt_site_u2[4];
|
||||
|
||||
// for (i = 0; i < 4; i++)
|
||||
// {
|
||||
// xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5);
|
||||
// xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3);
|
||||
// xpt_site_rp[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24+(i*16)], 4);
|
||||
// xpt_site_u2[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28+(i*16)], 4);
|
||||
// }
|
||||
|
||||
// fprintf (stderr, " Hytera XPT Site Id: %d - Free RPT: %d", xpt_site_id[0], xpt_site_rp[0]);
|
||||
// // fprintf (stderr, " RS1: %d RS2: %d", xpt_site_u1[0], xpt_site_u2[1]); //debug
|
||||
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, " XPT Adj Site(s): ");
|
||||
// for (i = 1; i < 4; i++)
|
||||
// {
|
||||
// if (xpt_site_id[i] != 0)
|
||||
// {
|
||||
// fprintf (stderr, "%d (%d) ", xpt_site_id[i], xpt_site_rp[i]);
|
||||
// // fprintf (stderr, "RS1: %d RS2: %d - ", xpt_site_u1[i], xpt_site_u2[i]); //debug
|
||||
// }
|
||||
// }
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
xpt_site_id[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16+(i*16)], 5);
|
||||
xpt_site_u1[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[21+(i*16)], 3);
|
||||
xpt_site_rp[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24+(i*16)], 4);
|
||||
xpt_site_u2[i] = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28+(i*16)], 4);
|
||||
}
|
||||
|
||||
fprintf (stderr, " Hytera XPT CSBK 0x0B - SN: %d", xpt_sn);
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " XPT Adjacent ");
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (xpt_site_id[i] != 0)
|
||||
{
|
||||
fprintf (stderr, "Site:%d Free:%d; ", xpt_site_id[i], xpt_site_rp[i]);
|
||||
// fprintf (stderr, "RS1: %d RS2: %d - ", xpt_site_u1[i], xpt_site_u2[i]); //debug
|
||||
}
|
||||
}
|
||||
sprintf (state->dmr_branding_sub, "XPT ");
|
||||
|
||||
|
||||
} //end 0x0B
|
||||
|
||||
} //end Hytera XPT section
|
||||
|
||||
@@ -336,13 +336,15 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
else if (opts->audio_in_type == 3) //rtl_fm tuning
|
||||
{
|
||||
//UDP command to tune the RTL dongle
|
||||
rtl_udp_tune(opts, state, state->p25_cc_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune(opts, state->p25_cc_freq);
|
||||
#endif
|
||||
}
|
||||
opts->p25_is_tuned = 0;
|
||||
//zero out vc frequencies
|
||||
state->p25_vc_freq[0] = 0;
|
||||
state->p25_vc_freq[1] = 0;
|
||||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
state->is_con_plus = 0; //con+ flag off
|
||||
}
|
||||
|
||||
156
src/dmr_flco.c
156
src/dmr_flco.c
@@ -172,7 +172,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
|
||||
//look for any Hytera XPT system, adjust TG to 16-bit allocation
|
||||
//Groups use only 8 out of 16, but 16 always seems to be allocated
|
||||
//private calls use 16-bit target values hased to 8-bit in the site status csbk
|
||||
//private calls use 16-bit target values hashed to 8-bit in the site status csbk
|
||||
//the TLC preceeds the VLC for a 'handshake' call setup in XPT
|
||||
|
||||
//truncate if XPT is set
|
||||
@@ -186,11 +186,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
tg_hash = crc8 (target_hash, 16);
|
||||
}
|
||||
|
||||
//XPT Call 'Grant' Setup Occurs in TLC (TermLC Handshake) with a flco 0x09
|
||||
//XPT Call 'Grant/Alert' Setup Occurs in TLC with a flco 0x09
|
||||
if (fid == 0x68 && flco == 0x09)
|
||||
{
|
||||
//The CSBK always uses an 8-bit TG; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing
|
||||
//It seems that private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK
|
||||
//The CSBK always uses an 8-bit TG/TGT; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing
|
||||
//private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK
|
||||
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //This is consistent with an LCN value, not an LSN value
|
||||
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 4); //24 and 4 on 0x09
|
||||
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[28], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
|
||||
|
||||
@@ -198,86 +199,69 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16); //16-bit allocation
|
||||
|
||||
//the bits that are left behind
|
||||
xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //Where the SVC bits would usually be
|
||||
xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //after the xpt_int channel, before the free repeater channel -- call being established = 7; call connected = 0; ??
|
||||
xpt_res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 8); //where the first 8 bits of the SRC would be
|
||||
xpt_res_c = (uint8_t)ConvertBitIntoBytes(&lc_bits[72], 8); //some unknown 8 bit value after the SRC
|
||||
|
||||
//speculation: 16,4 may be the current repeater channel this call will occur on? or the channel to interrupt?, could also be 8 bits?
|
||||
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //not sure about this value for this FLCO
|
||||
|
||||
//the crc8 hash is the value represented in the CSBK when dealing with private calls
|
||||
for (int i = 0; i < 16; i++) target_hash[i] = lc_bits[32+i];
|
||||
tg_hash = crc8 (target_hash, 16); //This is a different poly, but using as placeholder
|
||||
tg_hash = crc8 (target_hash, 16);
|
||||
|
||||
fprintf (stderr, "%s \n", KGRN);
|
||||
fprintf (stderr, " SLOT %d ", state->currentslot+1);
|
||||
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
|
||||
|
||||
// Here are some of the RIDs with hash address seen in that sample:
|
||||
// 930 = 88
|
||||
// 9317 = 198
|
||||
// 10002 = 187
|
||||
|
||||
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
|
||||
// if (opts->payload == 1) fprintf(stderr, "HSK [%X] ", xpt_hand);
|
||||
|
||||
// if (opts->payload == 1) fprintf(stderr, "CH=%d ", xpt_int);
|
||||
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
|
||||
|
||||
// if (opts->payload == 1) fprintf(stderr, "RS [%02X][%02X][%02X] ", xpt_res_a, xpt_res_b, xpt_res_c);
|
||||
fprintf (stderr, " SLOT %d ", state->currentslot+1);
|
||||
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
|
||||
fprintf (stderr, "TGT=%u SRC=%u ", target, source);
|
||||
|
||||
fprintf (stderr, "Hytera XPT ");
|
||||
if (reserved == 1) fprintf (stderr, "Group "); //according to observation
|
||||
else fprintf (stderr, "Private "); //according to observation
|
||||
fprintf (stderr, "Call Alert "); //sounds more reasonable than 'protect'
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "F-Rpt %d", xpt_free);
|
||||
//Group ID ranges from 1 to 240; emergency group call ID ranges from 250 to 254; all call ID is 255.
|
||||
if (reserved == 1)
|
||||
{
|
||||
fprintf (stderr, "Group "); //according to observation
|
||||
if (target > 248 && target < 255) fprintf (stderr, "Emergency ");
|
||||
if (target == 255) fprintf (stderr, "All ");
|
||||
}
|
||||
else fprintf (stderr, "Private "); //according to observation
|
||||
fprintf (stderr, "Call Alert "); //Alert or Grant
|
||||
|
||||
//reorganized all the 'extra' data to a second line and added extra verbosity
|
||||
if (opts->payload == 1) fprintf (stderr, "\n ");
|
||||
if (opts->payload == 1) fprintf (stderr, "%s", KYEL);
|
||||
//only display the hashed tgt value if its a private call and not a group call
|
||||
if (reserved == 0 && opts->payload == 1) fprintf(stderr, "TGT Hash=%d; ", tg_hash);
|
||||
if (opts->payload == 1) fprintf(stderr, "HSK=%X; ", xpt_hand);
|
||||
//extra verbosity on handshake types found in the patent
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "Handshake - ");
|
||||
if (xpt_hand == 0) fprintf (stderr, "Ordinary; ");
|
||||
else if (xpt_hand == 1) fprintf (stderr, "Callback/Alarm Interrupt; ");
|
||||
else if (xpt_hand == 2) fprintf (stderr, "Release Channel Interrupt; ");
|
||||
else fprintf (stderr, "Reserved; ");
|
||||
}
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// if (xpt_res_a == 0) fprintf (stderr, "Call Connected; ");
|
||||
// if (xpt_res_a == 1) fprintf (stderr, "Data Call Request; ");
|
||||
// if (xpt_res_a == 7) fprintf (stderr, "Voice Call Request; ");
|
||||
// if (xpt_res_a == 2) fprintf (stderr, "Unknown Status; ");
|
||||
// }
|
||||
|
||||
//logical repeater channel, not the logical slot value in the CSBK
|
||||
if (opts->payload == 1) fprintf(stderr, "Call on LCN %d; ", xpt_int); //LCN channel call or 'interrupt' will occur on
|
||||
// if (opts->payload == 1) fprintf(stderr, "RS A[%01X]B[%02X]C[%02X]; ", xpt_res_a, xpt_res_b, xpt_res_c); //leftover bits
|
||||
if (opts->payload == 1) fprintf (stderr, "Free LCN %d; ", xpt_free); //current free repeater LCN channel
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
|
||||
//add string for ncurses terminal display
|
||||
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free);
|
||||
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
|
||||
|
||||
is_xpt = 1;
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//XPT 'Handshake' -- not observed as of yet on any samples
|
||||
if ( fid == 0x68 && (flco == 0x2E || flco == 0x2F) )
|
||||
{
|
||||
|
||||
//all below is according to the patent, but never observed on any samples I have
|
||||
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //24-bit values according to patent
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 24); //24-bit values according to patent
|
||||
|
||||
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //16 and 4 on 2E and 2F
|
||||
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
|
||||
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 8); //Interrupt Designated Channel (No idea?)
|
||||
|
||||
fprintf (stderr, "%s \n", KGRN);
|
||||
fprintf (stderr, " SLOT %d ", state->currentslot+1);
|
||||
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
|
||||
|
||||
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
|
||||
// if (opts->payload == 1) fprintf(stderr, "HSK=[%X] ", xpt_hand);
|
||||
|
||||
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
|
||||
fprintf (stderr, "Hytera XPT ");
|
||||
if (reserved == 1) fprintf (stderr, "Group ");
|
||||
else fprintf (stderr, "Private ");
|
||||
|
||||
fprintf (stderr, "Call ");
|
||||
if (flco == 0x2E) fprintf (stderr, "Request ");
|
||||
if (flco == 0x2F) fprintf (stderr, "Response ");
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
is_xpt = 1;
|
||||
goto END_FLCO;
|
||||
|
||||
}
|
||||
|
||||
//Hytera XPT "something" -- seen on Embedded
|
||||
if (fid == 0x68 && flco == 0x13)
|
||||
//Hytera XPT 'Others' -- moved the patent opcodes here as well for now
|
||||
if ( fid == 0x68 && (flco == 0x13 || flco == 0x31 || flco == 0x2E || flco == 0x2F) )
|
||||
{
|
||||
if (type == 1) fprintf (stderr, "%s \n", KCYN);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KCYN);
|
||||
@@ -358,6 +342,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
state->payload_miR = 0;
|
||||
state->payload_keyidR = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -377,7 +362,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
|
||||
fprintf (stderr, " SLOT %d ", state->currentslot+1);
|
||||
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
|
||||
if (opts->payload == 1 && is_xpt == 1) fprintf(stderr, "HASH=%d ", tg_hash);
|
||||
if (opts->payload == 1 && is_xpt == 1 && flco == 0x3) fprintf(stderr, "HASH=%d ", tg_hash);
|
||||
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
||||
|
||||
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
|
||||
@@ -403,7 +388,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
fprintf (stderr, "Private ");
|
||||
}
|
||||
}
|
||||
else if (flco == 0x3) //UU_V_Ch_Usr -- still valid on hytera VLC
|
||||
else if (flco == 0x3) //UU_V_Ch_Usr
|
||||
{
|
||||
sprintf (state->call_string[slot], " Private ");
|
||||
fprintf (stderr, "Private ");
|
||||
@@ -536,20 +521,38 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
|
||||
if (state->K1 != 0 && fid == 0x68 && so & 0x40)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
if (state->K2 != 0) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Key %010llX ", state->K1);
|
||||
fprintf (stderr, "Key %010llX ", state->K1);
|
||||
if (state->K2 != 0) fprintf (stderr, "%016llX ", state->K2);
|
||||
if (state->K4 != 0) fprintf (stderr, "%016llX %016llX", state->K3, state->K4);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == 0 && state->payload_algid == 0x21 && state->R != 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %010llX ", state->R);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (slot == 1 && state->payload_algidR == 0x21 && state->RR != 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %010llX ", state->RR);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
END_FLCO:
|
||||
|
||||
//blank the call string here if its a TLC
|
||||
if (type == 2) sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
if (unk == 1 || pf == 1)
|
||||
{
|
||||
fprintf(stderr, " FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
||||
fprintf(stderr, " FLCO=0x%02X FID=0x%02X ", flco, fid);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
@@ -905,13 +908,13 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
else if (slco == 0x08)
|
||||
{
|
||||
//The Priority Repeater and Priority Hash values stem from SDRTrunk, but I've never seen these values not be zeroes
|
||||
// fprintf (stderr, " SLCO Hytera XPT - Free RPT %d - PRI RPT %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash);
|
||||
fprintf (stderr, " SLCO Hytera XPT - Free LCN %d - PRI LCN %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash);
|
||||
//NOTE: on really busy systems, this free repeater assignment can lag due to the 4 TS requirment to get SLC
|
||||
fprintf (stderr, " SLCO Hytera XPT - Free RPT %d ", xpt_free);
|
||||
// fprintf (stderr, " SLCO Hytera XPT - Free LCN %d ", xpt_free);
|
||||
sprintf (state->dmr_branding_sub, "XPT ");
|
||||
|
||||
//add string for ncurses terminal display
|
||||
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free);
|
||||
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
|
||||
}
|
||||
|
||||
else fprintf (stderr, " SLCO Unknown - %d ", slco);
|
||||
@@ -923,6 +926,7 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
{
|
||||
fprintf (stderr, "[%02X]", slco_bytes[i]);
|
||||
}
|
||||
fprintf (stderr, "\n"); //if its a voice frame, we need the line break
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
157
src/dmr_le.c
157
src/dmr_le.c
@@ -13,6 +13,23 @@ void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc,
|
||||
{
|
||||
|
||||
uint8_t slot = state->currentslot;
|
||||
|
||||
//enforce RC4 due to missing PI header, but with valid SVC Opts
|
||||
//ideally, this would be handled by VC-F single burst, but its not fully reliable compared to this
|
||||
//due to multiple signalling occurring inside of it, depending on system type
|
||||
if (state->M == 0x21)
|
||||
{
|
||||
if (slot == 0 && state->dmr_so & 0x40)
|
||||
{
|
||||
state->payload_algid = 0x21;
|
||||
state->payload_keyid = 0xFF;
|
||||
}
|
||||
if (slot == 1 && state->dmr_soR & 0x40)
|
||||
{
|
||||
state->payload_algidR = 0x21;
|
||||
state->payload_keyidR = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
//collect our fragments and place them into storage
|
||||
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
|
||||
@@ -183,7 +200,6 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
|
||||
//RC Channel CRC 7 Mask = 0x7A; CRC bits are used as privacy indicators on
|
||||
//Single Voice Burst F (see below), other moto values seem to exist there as well
|
||||
//unknown what the other values are (see Cap+ 0x313 and 0x643)
|
||||
if (power == 1) //RC
|
||||
{
|
||||
crc_extracted = 0;
|
||||
@@ -198,17 +214,19 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
}
|
||||
else crc_okay = 1; //SB
|
||||
|
||||
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people right now
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
sbrc_hex = sbrc_hex << 1;
|
||||
sbrc_hex |= sbrc_return[i] & 1; //sbrc_return
|
||||
}
|
||||
|
||||
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people
|
||||
{
|
||||
fprintf (stderr, "\n %s", KCYN);
|
||||
if (power == 0) fprintf (stderr, " SB: ");
|
||||
if (power == 1) fprintf (stderr, " RC: ");
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
sbrc_hex = sbrc_hex << 1;
|
||||
sbrc_hex |= sbrc_return[i] & 1; //sbrc_return
|
||||
fprintf (stderr, "%d", sbrc_return[i]);
|
||||
}
|
||||
fprintf (stderr, " - %03X", sbrc_hex);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
@@ -217,82 +235,73 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
if (opts->payload == 1) fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
|
||||
fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
|
||||
}
|
||||
}
|
||||
|
||||
//Disabling the lower portion until this can be completely ironed out
|
||||
|
||||
//sbrc_hex value of 0x313 seems to be some Cap+ Thing,
|
||||
//also observed 0x643 on another cap+ system (site id, status? something?)
|
||||
// uint8_t sbrc_opcode = sbrc_hex;
|
||||
// uint8_t alg = sbrc_hex & 0x7;
|
||||
// uint8_t key = (sbrc_hex >> 3) & 0xFF;
|
||||
|
||||
uint8_t sbrc_opcode = sbrc_hex;
|
||||
uint8_t alg = sbrc_hex & 0x7;
|
||||
uint8_t key = (sbrc_hex >> 3) & 0xFF;
|
||||
uint8_t cap_site = (sbrc_hex >> 4) & 0x7; //signalling on Cap+ when voice errors (non voice VC6 is present)
|
||||
|
||||
//this pattern seems to fit the multiple cap+ systems I've observed
|
||||
//test on site '7' to make sure (works on 1 and 4)
|
||||
// uint8_t cap_site = (sbrc_hex >> 4) & 0x7;
|
||||
if (1 == 1) //opts->payload == 1
|
||||
{
|
||||
if (irr_err != 0) ; //fprintf (stderr, "\n %s SLOT %d SB/RC (FEC ERR) %d %s \n", KRED, slot, irr_err, KNRM);
|
||||
if (irr_err == 0)
|
||||
{
|
||||
if (sbrc_hex == 0) ; //NULL
|
||||
//else if (placeholder for future conditions)
|
||||
// {
|
||||
// placeholder for future conditions
|
||||
// }
|
||||
else //Finally have a consistent set-up for this
|
||||
{
|
||||
//the signalling here is always presents on good voice frames, if errs are [3][2] then its not a VC6 voice frame, but some other 'hidden' frame
|
||||
if (slot == 0 && state->errs < 3)
|
||||
{
|
||||
if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
|
||||
{
|
||||
//if we aren't forcing a particular alg or privacy key set
|
||||
if (state->M == 0)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, " Slot 1");
|
||||
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// if (irr_err != 0) fprintf (stderr, "%s (FEC ERR) %d %s", KRED, irr_err, KNRM);
|
||||
// if (irr_err == 0)
|
||||
// {
|
||||
// if (sbrc_hex == 0) ; //NULL
|
||||
// else if (sbrc_hex == 0x313) //sbrc_hex == 0x313 and 0x643 (cap+ things)
|
||||
// {
|
||||
// //Cap+ Site ID seems to fit here on samples I've seen with the alternate SB signalling
|
||||
// fprintf (stderr, "%s ", KYEL);
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, " Capacity Plus Site %d", cap_site);
|
||||
// fprintf (stderr, "%s ", KNRM);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
state->payload_keyid = key;
|
||||
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
}
|
||||
|
||||
// if (slot == 0)
|
||||
// {
|
||||
// //key and alg only present SOME times, not all,
|
||||
// //also, intermixed with other signalling
|
||||
// //needs more study first!
|
||||
// if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
|
||||
// {
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s ", KYEL);
|
||||
// fprintf (stderr, "\n Slot 1");
|
||||
// fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
// fprintf (stderr, "%s ", KNRM);
|
||||
// }
|
||||
|
||||
// //needs more study before assignment
|
||||
// // state->payload_keyid = key;
|
||||
// // state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// if (slot == 1)
|
||||
// {
|
||||
// if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
|
||||
// {
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s ", KYEL);
|
||||
// fprintf (stderr, "\n Slot 2");
|
||||
// fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
// fprintf (stderr, "%s ", KNRM);
|
||||
// }
|
||||
|
||||
// //needs more study before assignment
|
||||
// // state->payload_keyidR = key;
|
||||
// // state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
// }
|
||||
// }
|
||||
//the signalling here is always presents on good voice frames, if errs are [3][2] then its not a VC6 voice frame, but some other 'hidden' frame
|
||||
if (slot == 1 && state->errsR < 3)
|
||||
{
|
||||
if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
|
||||
{
|
||||
//if we aren't forcing a particular alg or privacy key set
|
||||
if (state->M == 0)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, " Slot 1");
|
||||
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
|
||||
// }
|
||||
state->payload_keyidR = key;
|
||||
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
}
|
||||
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
SBRC_END:
|
||||
|
||||
|
||||
11
src/dmr_pi.c
11
src/dmr_pi.c
@@ -116,7 +116,7 @@ void LFSR(dsd_state * state)
|
||||
void LFSR64(dsd_state * state)
|
||||
{
|
||||
{
|
||||
uint64_t lfsr = 0;
|
||||
unsigned long long int lfsr = 0;
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
@@ -128,19 +128,16 @@ void LFSR64(dsd_state * state)
|
||||
|
||||
for(cnt=0;cnt<32;cnt++)
|
||||
{
|
||||
uint64_t bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
|
||||
unsigned long long int bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
|
||||
lfsr = (lfsr << 1) | bit;
|
||||
}
|
||||
|
||||
// if (state->currentslot == 0) state->payload_miP = lfsr;
|
||||
// else state->payload_miN = lfsr;
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Slot 1");
|
||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
|
||||
fprintf (stderr, " MI: 0x%016lX", lfsr);
|
||||
fprintf (stderr, " MI: 0x%016llX", lfsr);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
state->payload_mi = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
|
||||
}
|
||||
@@ -150,7 +147,7 @@ void LFSR64(dsd_state * state)
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Slot 2");
|
||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
|
||||
fprintf (stderr, " MI: 0x%016lX", lfsr);
|
||||
fprintf (stderr, " MI: 0x%016llX", lfsr);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
state->payload_miR = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
|
||||
}
|
||||
|
||||
@@ -325,15 +325,15 @@ uint8_t ComputeCrc5Bit(uint8_t * DMRData)
|
||||
return CRC;
|
||||
} /* End ComputeCrc5Bit() */
|
||||
|
||||
uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
|
||||
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
|
||||
{
|
||||
uint32_t Output = 0;
|
||||
uint64_t Output = 0;
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < BitLength; i++)
|
||||
{
|
||||
Output <<= 1;
|
||||
Output |= (uint32_t)(BufferIn[i] & 1);
|
||||
Output |= (uint64_t)(BufferIn[i] & 1);
|
||||
}
|
||||
|
||||
return Output;
|
||||
|
||||
@@ -545,6 +545,9 @@ openAudioInDevice (dsd_opts * opts)
|
||||
const char ch = '.';
|
||||
extension = strrchr(opts->audio_in_dev, ch); //return extension if this is a .wav or .bin file
|
||||
|
||||
//if no extension set, give default of .wav -- bugfix for github issue #105
|
||||
// if (extension == NULL) extension = ".wav";
|
||||
|
||||
// get info of device/file
|
||||
if (strncmp(opts->audio_in_dev, "-", 1) == 0)
|
||||
{
|
||||
@@ -597,7 +600,15 @@ openAudioInDevice (dsd_opts * opts)
|
||||
}
|
||||
else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
opts->audio_in_type = 3;
|
||||
#elif AERO_BUILD
|
||||
opts->audio_in_type = 5;
|
||||
sprintf (opts->audio_in_dev, "/dev/dsp");
|
||||
#else
|
||||
opts->audio_in_type = 0;
|
||||
sprintf (opts->audio_in_dev, "pulse");
|
||||
#endif
|
||||
}
|
||||
else if(strncmp(opts->audio_in_dev, "pulse", 5) == 0)
|
||||
{
|
||||
@@ -607,6 +618,25 @@ openAudioInDevice (dsd_opts * opts)
|
||||
{
|
||||
opts->audio_in_type = 5;
|
||||
}
|
||||
|
||||
//if no extension set, treat as named pipe or extensionless wav file -- bugfix for github issue #105
|
||||
else if (extension == NULL)
|
||||
{
|
||||
opts->audio_in_type = 2;
|
||||
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->channels = 1;
|
||||
opts->audio_in_file_info->seekable = 0;
|
||||
opts->audio_in_file_info->format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
|
||||
|
||||
if (opts->audio_in_file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error, couldn't open file/pipe with libsndfile: %s\n", sf_strerror(NULL));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strncmp(extension, ".bin", 3) == 0)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
|
||||
@@ -283,12 +283,12 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||
|
||||
valid = 0;
|
||||
|
||||
//disabling again, causing issues with trunking P25
|
||||
if (state->synctype == 1 && opts->p25_trunk == 1)
|
||||
{
|
||||
// Use the P25 heuristics if available
|
||||
// valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
||||
if (state->synctype == 1 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
||||
{
|
||||
// Use the P25p1 heuristics if available
|
||||
valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
|
||||
if (valid == 0)
|
||||
{
|
||||
@@ -347,12 +347,12 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||
|
||||
valid = 0;
|
||||
|
||||
//disabling again, causing issues with trunking P25
|
||||
if (state->synctype == 0 && opts->p25_trunk == 1)
|
||||
{
|
||||
// Use the P25 heuristics if available
|
||||
// valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
//testing again, either on Voice channels only (when tuned) or with trunk disabled
|
||||
if (state->synctype == 0 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
|
||||
{
|
||||
// Use the P25p1 heuristics if available
|
||||
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
|
||||
}
|
||||
|
||||
if (valid == 0)
|
||||
{
|
||||
|
||||
@@ -189,10 +189,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
}
|
||||
//rtludp
|
||||
//rtl
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
#endif
|
||||
}
|
||||
|
||||
fprintf (stderr, "Tuning to Frequency: %.06lf MHz\n",
|
||||
@@ -231,10 +233,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
t_max = 12; //based on Frame_Sync_2 pattern
|
||||
}
|
||||
//if Phase 2 (or YSF in future), then only 20
|
||||
//if Phase 2 (or YSF in future), then only 19
|
||||
else if (state->lastsynctype == 35 || state->lastsynctype == 36) //P2
|
||||
{
|
||||
t_max = 20;
|
||||
t_max = 19; //Phase 2 S-ISCH is only 19
|
||||
}
|
||||
else t_max = 24; //24 for everything else
|
||||
|
||||
@@ -446,6 +448,21 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->minref = state->min;
|
||||
}
|
||||
|
||||
|
||||
//if using an rtl input method, do not look for sync patterns if the rms value is lower than our 'soft squelch' level
|
||||
if (opts->audio_in_type == 3 && opts->rtl_rms < opts->rtl_squelch_level) //tests show floor level around 40, and signal breaking 100, default is 100 for level
|
||||
{
|
||||
if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1 || opts->frame_dpmr == 1)
|
||||
{
|
||||
//should we update min/max here? yes or no?
|
||||
|
||||
// state->max = ((state->max) + lmax) / 2;
|
||||
// state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
goto SYNC_TEST_END;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy (synctest, (synctest_p - 23), 24);
|
||||
if (opts->frame_p25p1 == 1)
|
||||
{
|
||||
@@ -1276,7 +1293,9 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#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))
|
||||
{
|
||||
@@ -1292,9 +1311,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 28;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
||||
// 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;
|
||||
@@ -1303,7 +1324,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 29;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
||||
// if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
||||
// fprintf (stderr, " %s ", synctest19);
|
||||
return (29);
|
||||
}
|
||||
|
||||
@@ -1317,7 +1339,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
if (state->lastsynctype == 28)
|
||||
{
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//if (opts->payload == 1) fprintf (stderr, "FSW ");
|
||||
// if (opts->payload == 1) fprintf (stderr, "FSW ");
|
||||
// fprintf (stderr, " %s ", synctest10);
|
||||
return (28);
|
||||
}
|
||||
state->lastsynctype = 28; //need two consecutive patterns to continue
|
||||
@@ -1334,7 +1357,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
if (state->lastsynctype == 29)
|
||||
{
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//if (opts->payload == 1) fprintf (stderr, "FSW ");
|
||||
// if (opts->payload == 1) fprintf (stderr, "FSW ");
|
||||
// fprintf (stderr, " %s ", synctest10);
|
||||
return (29);
|
||||
}
|
||||
state->lastsynctype = 29; //need two consecutive patterns to continue
|
||||
@@ -1342,6 +1366,216 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
state->lastsynctype = 28;
|
||||
}
|
||||
|
||||
else if (
|
||||
|
||||
(strcmp (synctest10, "1313113313") == 0 )
|
||||
|| (strcmp (synctest10, "1113113313") == 0 )
|
||||
|| (strcmp (synctest10, "1313113333") == 0 )
|
||||
|| (strcmp (synctest10, "1113113333") == 0 )
|
||||
|| (strcmp (synctest10, "1313133313") == 0 ) //
|
||||
|
||||
)
|
||||
{
|
||||
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
// state->last_cc_sync_time = time(NULL);
|
||||
|
||||
if (state->lastsynctype == 29)
|
||||
{
|
||||
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);
|
||||
}
|
||||
state->lastsynctype = 29;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //NXDN Sync Type Selection
|
||||
|
||||
//Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible
|
||||
#ifdef PVCONVENTIONAL
|
||||
if (opts->frame_provoice == 1)
|
||||
{
|
||||
memset (synctest32, 0, sizeof(synctest32));
|
||||
strncpy (synctest32, (synctest_p - 31), 16); //short sync grab here on 32
|
||||
char pvc_txs[9]; //string (symbol) value of TX Address
|
||||
char pvc_rxs[9]; //string (symbol) value of RX Address
|
||||
uint8_t pvc_txa = 0; //actual value of TX Address
|
||||
uint8_t pvc_rxa = 0; //actual value of RX Address
|
||||
strncpy (pvc_txs, (synctest_p - 15), 8); //copy string value of TX Address
|
||||
strncpy (pvc_rxs, (synctest_p - 7), 8); //copy string value of RX Address
|
||||
if ((strcmp (synctest32, INV_PROVOICE_CONV_SHORT) == 0))
|
||||
{
|
||||
if (state->lastsynctype == 15) //use this condition, like NXDN, to migitage false positives due to short sync pattern
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, "ProVoice ");
|
||||
// fprintf (stderr, "Sync Pattern = %s ", synctest32);
|
||||
// fprintf (stderr, "TX = %s ", pvc_txs);
|
||||
// fprintf (stderr, "RX = %s ", pvc_rxs);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
pvc_txa = pvc_txa << 1;
|
||||
pvc_rxa = pvc_rxa << 1;
|
||||
//symbol 1 is binary 1 on inverted
|
||||
//I hate working with strings, has to be a better way to evaluate this
|
||||
memset (pvc_txs, 0, sizeof (pvc_txs));
|
||||
memset (pvc_rxs, 0, sizeof (pvc_rxs));
|
||||
strncpy (pvc_txs, (synctest_p - 15+i), 1);
|
||||
strncpy (pvc_rxs, (synctest_p - 7+i), 1);
|
||||
if ((strcmp (pvc_txs, "1") == 0))
|
||||
pvc_txa = pvc_txa + 1;
|
||||
if ((strcmp (pvc_rxs, "1") == 0))
|
||||
pvc_rxa = pvc_rxa + 1;
|
||||
}
|
||||
printFrameSync (opts, state, "-PV_C ", synctest_pos + 1, modulation);
|
||||
fprintf (stderr, "TX: %d ", pvc_txa);
|
||||
fprintf (stderr, "RX: %d ", pvc_rxa);
|
||||
if (pvc_txa == 172) fprintf (stderr, "ALL CALL ");
|
||||
state->lastsynctype = 15;
|
||||
return (15);
|
||||
}
|
||||
state->lastsynctype = 15;
|
||||
}
|
||||
else if ((strcmp (synctest32, PROVOICE_CONV_SHORT) == 0))
|
||||
{
|
||||
if (state->lastsynctype == 14) //use this condition, like NXDN, to migitage false positives due to short sync pattern
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, "ProVoice ");
|
||||
// fprintf (stderr, "Sync Pattern = %s ", synctest32);
|
||||
// fprintf (stderr, "TX = %s ", pvc_txs);
|
||||
// fprintf (stderr, "RX = %s ", pvc_rxs);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
pvc_txa = pvc_txa << 1;
|
||||
pvc_rxa = pvc_rxa << 1;
|
||||
//symbol 3 is binary 1 on positive
|
||||
//I hate working with strings, has to be a better way to evaluate this
|
||||
memset (pvc_txs, 0, sizeof (pvc_txs));
|
||||
memset (pvc_rxs, 0, sizeof (pvc_rxs));
|
||||
strncpy (pvc_txs, (synctest_p - 15+i), 1);
|
||||
strncpy (pvc_rxs, (synctest_p - 7+i), 1);
|
||||
if ((strcmp (pvc_txs, "3") == 0))
|
||||
pvc_txa = pvc_txa + 1;
|
||||
if ((strcmp (pvc_rxs, "3") == 0))
|
||||
pvc_rxa = pvc_rxa + 1;
|
||||
}
|
||||
printFrameSync (opts, state, "+PV_C ", synctest_pos + 1, modulation);
|
||||
fprintf (stderr, "TX: %d ", pvc_txa);
|
||||
fprintf (stderr, "RX: %d ", pvc_rxa);
|
||||
if (pvc_txa == 172) fprintf (stderr, "ALL CALL ");
|
||||
state->lastsynctype = 14;
|
||||
return (14);
|
||||
}
|
||||
state->lastsynctype = 14;
|
||||
}
|
||||
}
|
||||
#endif //End Provoice Conventional
|
||||
|
||||
SYNC_TEST_END: ; //do nothing
|
||||
|
||||
} // t >= 10
|
||||
|
||||
if (exitflag == 1)
|
||||
|
||||
@@ -146,7 +146,8 @@ int csvChanImport(dsd_opts * opts, dsd_state * state) //channel map import
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support
|
||||
//Decimal Variant of Key Import
|
||||
int csvKeyImportDec(dsd_opts * opts, dsd_state * state) //multi-key support
|
||||
{
|
||||
char filename[1024] = "filename.csv";
|
||||
sprintf (filename, "%s", opts->key_in_file);
|
||||
@@ -210,3 +211,48 @@ int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Hex Variant of Key Import
|
||||
int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for rc4 keys
|
||||
{
|
||||
char filename[1024] = "filename.csv";
|
||||
sprintf (filename, "%s", opts->key_in_file);
|
||||
char buffer[BSIZE];
|
||||
FILE * fp;
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
printf("Unable to open file '%s'\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
int row_count = 0;
|
||||
int field_count = 0;
|
||||
unsigned long long int keynumber;
|
||||
|
||||
while (fgets(buffer, BSIZE, fp)) {
|
||||
field_count = 0;
|
||||
row_count++;
|
||||
if (row_count == 1)
|
||||
continue; //don't want labels
|
||||
char * field = strtok(buffer, ","); //seperate by comma
|
||||
while (field) {
|
||||
|
||||
if (field_count == 0)
|
||||
{
|
||||
sscanf (field, "%llX", &keynumber);
|
||||
}
|
||||
|
||||
if (field_count == 1)
|
||||
{
|
||||
sscanf (field, "%llX", &state->rkey_array[keynumber]);
|
||||
}
|
||||
|
||||
field = strtok(NULL, ",");
|
||||
field_count++;
|
||||
}
|
||||
fprintf (stderr, "Key [%04llX] [%016llX]", keynumber, state->rkey_array[keynumber]);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
476
src/dsd_main.c
476
src/dsd_main.c
@@ -44,6 +44,18 @@ int pretty_colors()
|
||||
#include "p25p1_heuristics.h"
|
||||
#include "pa_devs.h"
|
||||
|
||||
#ifdef LIMAZULUTWEAKS
|
||||
char * FM_banner[9] = {
|
||||
" ",
|
||||
" ██████╗ ██████╗██████╗ ███╗ ███████╗",
|
||||
" ██╔══██╗██╔════╝██╔══██╗ ███║ ╚════██║",
|
||||
" ██║ ██║╚█████╗ ██║ ██║ Lima ███║ ███╔═╝",
|
||||
" ██║ ██║ ╚═══██╗██║ ██║ Zulu ███║ ██╔══╝ ",
|
||||
" ██████╔╝██████╔╝██████╔╝ Edition V ████████╗███████╗",
|
||||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═══════╝╚══════╝",
|
||||
" "
|
||||
};
|
||||
#else
|
||||
char * FM_banner[9] = {
|
||||
" ",
|
||||
" ██████╗ ██████╗██████╗ ███████╗███╗ ███╗███████╗",
|
||||
@@ -52,8 +64,9 @@ char * FM_banner[9] = {
|
||||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗",
|
||||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝",
|
||||
" 'Aero' Edition v2.0.0-64-gbd94f83 Windows 32-bit RC5 "
|
||||
" "
|
||||
};
|
||||
#endif
|
||||
|
||||
int comp (const void *a, const void *b)
|
||||
{
|
||||
@@ -77,40 +90,29 @@ void
|
||||
noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
// // experimental conventional frequency scanner mode
|
||||
// if (opts->scanner_mode == 1)
|
||||
// {
|
||||
//clear heuristics from last carrier signal
|
||||
if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1)
|
||||
{
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||||
}
|
||||
|
||||
// if (state->lcn_freq_roll > state->lcn_freq_count) //with >= we were cutting one short
|
||||
// {
|
||||
// state->lcn_freq_roll = 0; //reset to zero
|
||||
// }
|
||||
// //check that we have a non zero value first, then tune next frequency
|
||||
// if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
|
||||
// {
|
||||
// //rigctl
|
||||
// if (opts->use_rigctl == 1)
|
||||
// {
|
||||
// if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
// SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
// }
|
||||
// //rtludp
|
||||
// if (opts->audio_in_type == 3)
|
||||
// {
|
||||
// rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
// }
|
||||
|
||||
// if (state->lastsynctype != -1) fprintf (stderr, "Resume Scanning Mode\n");
|
||||
|
||||
// }
|
||||
// state->lcn_freq_roll++;
|
||||
// }
|
||||
// //end experimental conventional frequency scanner mode
|
||||
//only do it here on the tweaks
|
||||
#ifdef LIMAZULUTWEAKS
|
||||
state->nxdn_last_ran = -1;
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
#endif
|
||||
|
||||
//experimental conventional frequency scanner mode
|
||||
if (opts->scanner_mode == 1 && ( (time(NULL) - state->last_cc_sync_time) > opts->trunk_hangtime))
|
||||
{
|
||||
|
||||
//always do these -- makes sense during scanning
|
||||
state->nxdn_last_ran = -1;
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
|
||||
if (state->lcn_freq_roll >= state->lcn_freq_count)
|
||||
{
|
||||
state->lcn_freq_roll = 0; //reset to zero
|
||||
@@ -124,13 +126,16 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
}
|
||||
//rtludp
|
||||
//rtl
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune(opts, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (state->lastsynctype != -1) fprintf (stderr, "Resume Scanning Mode\n");
|
||||
//print here not working as it should -- not always a -1 value on lastsynctype I presume
|
||||
// if (state->lastsynctype != -1) fprintf (stderr, "Resume Scanning Mode\n");
|
||||
|
||||
}
|
||||
state->lcn_freq_roll++;
|
||||
@@ -159,25 +164,29 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||
state->dmr_rest_channel = -1; //maybe?
|
||||
}
|
||||
|
||||
else if (opts->audio_in_type == 3) //rtl_fm tuning
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
//UDP command to tune the RTL dongle
|
||||
rtl_udp_tune(opts, state, state->p25_cc_freq);
|
||||
state->dmr_rest_channel = -1; //maybe?
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||
state->dmr_rest_channel = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
opts->p25_is_tuned = 0;
|
||||
state->edacs_tuned_lcn = -1;
|
||||
|
||||
//only for EDACS/PV
|
||||
if (opts->frame_provoice == 1 && opts->wav_out_file != NULL)
|
||||
if (opts->p25_trunk == 1 && opts->frame_provoice == 1 && opts->wav_out_file != NULL)
|
||||
{
|
||||
closeWavOutFile(opts, state);
|
||||
}
|
||||
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//test to switch back to 10/4 P1 QPSK for P25 FDMA CC
|
||||
if (opts->mod_qpsk == 1 && state->p25_cc_is_tdma == 0)
|
||||
|
||||
//reworked to always change back to 10/4 if p25_cc_is_tdma is set to 0 or 1 (inits on 2)
|
||||
if (state->p25_cc_is_tdma == 0) //is set on signal from P25 TSBK or MAC_SIGNAL
|
||||
{
|
||||
state->samplesPerSymbol = 10;
|
||||
state->symbolCenter = 4;
|
||||
@@ -187,6 +196,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->p25_vc_freq[0] = 0;
|
||||
state->p25_vc_freq[1] = 0;
|
||||
|
||||
memset(state->active_channel, 0, sizeof(state->active_channel));
|
||||
|
||||
state->is_con_plus = 0; //flag off
|
||||
}
|
||||
|
||||
@@ -234,6 +245,12 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->nxdn_location_sys_code = 0;
|
||||
sprintf (state->nxdn_location_category, "%s", " ");
|
||||
|
||||
//channel access information
|
||||
state->nxdn_rcn = 0;
|
||||
state->nxdn_base_freq = 0;
|
||||
state->nxdn_step = 0;
|
||||
state->nxdn_bw = 0;
|
||||
|
||||
//dmr mfid branding and site parms
|
||||
sprintf(state->dmr_branding_sub, "%s", "");
|
||||
sprintf(state->dmr_branding, "%s", "");
|
||||
@@ -340,8 +357,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->fourv_counter[1] = 0;
|
||||
|
||||
//values displayed in ncurses terminal
|
||||
state->p25_vc_freq[0] = 0;
|
||||
state->p25_vc_freq[1] = 0;
|
||||
// state->p25_vc_freq[0] = 0;
|
||||
// state->p25_vc_freq[1] = 0;
|
||||
|
||||
//new nxdn stuff
|
||||
state->nxdn_part_of_frame = 0;
|
||||
@@ -354,6 +371,19 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
sprintf (state->nxdn_call_type, "%s", "");
|
||||
|
||||
//unload keys when using keylaoder
|
||||
if (state->keyloader == 1)
|
||||
{
|
||||
state->R = 0; //NXDN, or RC4 (slot 1)
|
||||
state->RR = 0; //RC4 (slot 2)
|
||||
state->K = 0; //BP
|
||||
state->K1 = 0; //tera 10 char BP
|
||||
state->H = 0; //shim for above
|
||||
}
|
||||
|
||||
//forcing key application will re-enable this at the time of voice tx
|
||||
state->nxdn_cipher_type = 0;
|
||||
|
||||
//dmr overaching manufacturer in use for a particular system or radio
|
||||
// state->dmr_mfid = -1;
|
||||
|
||||
@@ -367,7 +397,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//initialize cap+ bits and block num storage
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
state->cap_plus_block_num = 0;
|
||||
memset (state->cap_plus_block_num, 0, sizeof(state->cap_plus_block_num));
|
||||
|
||||
//init confirmed data individual block crc as invalid
|
||||
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
|
||||
@@ -385,11 +415,13 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
memset(state->dmr_embedded_gps, 0, sizeof(state->dmr_embedded_gps));
|
||||
memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
||||
|
||||
// memset(state->active_channel, 0, sizeof(state->active_channel));
|
||||
|
||||
//REMUS! multi-purpose call_string
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
|
||||
if (time(NULL) - state->last_cc_sync_time > 30) //thirty seconds of no carrier
|
||||
if (time(NULL) - state->last_cc_sync_time > 10) //ten seconds of no carrier
|
||||
{
|
||||
state->dmr_rest_channel = -1;
|
||||
state->p25_vc_freq[0] = 0;
|
||||
@@ -399,6 +431,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->dmr_branding, "%s", "");
|
||||
sprintf (state->dmr_site_parms, "%s", "");
|
||||
opts->p25_is_tuned = 0;
|
||||
memset(state->active_channel, 0, sizeof(state->active_channel));
|
||||
}
|
||||
|
||||
opts->dPMR_next_part_of_superframe = 0;
|
||||
@@ -430,10 +463,14 @@ initOpts (dsd_opts * opts)
|
||||
opts->p25status = 0;
|
||||
opts->p25tg = 0;
|
||||
opts->scoperate = 15;
|
||||
#ifdef AERO_BUILD
|
||||
sprintf (opts->audio_in_dev, "/dev/dsp");
|
||||
opts->audio_in_fd = -1;
|
||||
|
||||
sprintf (opts->audio_out_dev, "/dev/dsp");
|
||||
#else
|
||||
sprintf (opts->audio_in_dev, "pulse");
|
||||
sprintf (opts->audio_out_dev, "pulse");
|
||||
#endif
|
||||
opts->audio_in_fd = -1;
|
||||
opts->audio_out_fd = -1;
|
||||
opts->audio_out_fdR = -1;
|
||||
|
||||
@@ -497,14 +534,18 @@ initOpts (dsd_opts * opts)
|
||||
opts->delay = 0;
|
||||
opts->use_cosine_filter = 1;
|
||||
opts->unmute_encrypted_p25 = 0;
|
||||
//all RTL user options -- enabled AGC by default due to weak signal related issues
|
||||
opts->rtl_dev_index = 0; //choose which device we want by index number
|
||||
opts->rtl_gain_value = 26; //mid value, 0 - AGC (not recommended) 49 highest value
|
||||
opts->rtl_squelch_level = 0; //fully open by default, want to specify level for things like NXDN with false positives
|
||||
opts->rtl_volume_multiplier = 1; //sample multiplier; 1 seems like a good value
|
||||
opts->rtl_udp_port = 6020; //set UDP port for RTL remote
|
||||
opts->rtl_bandwidth = 12; //changed recommended default to 12, 24 for ProVoice
|
||||
opts->rtlsdr_ppm_error = 0; //initialize ppm with 0 value; bug reported by N.
|
||||
opts->rtl_gain_value = 0; //mid value, 0 - AGC - 0 to 49 acceptable values
|
||||
opts->rtl_squelch_level = 100; //100 by default, but only affects NXDN and dPMR during framesync test, compared to RMS value
|
||||
opts->rtl_volume_multiplier = 1; //sample multiplier; This multiplies the sample value to produce a higher 'inlvl' (probably best left unused)
|
||||
opts->rtl_udp_port = 0; //set UDP port for RTL remote -- 0 by default, will be making this optional for some external/legacy use cases (edacs-fm, etc)
|
||||
opts->rtl_bandwidth = 12; //default is 12, reverted back to normal on this (no inherent benefit)
|
||||
opts->rtlsdr_ppm_error = 0; //initialize ppm with 0 value;
|
||||
opts->rtlsdr_center_freq = 850000000; //set to an initial value (if user is using a channel map, then they won't need to specify anything other than -i rtl if desired)
|
||||
opts->rtl_started = 0;
|
||||
opts->rtl_rms = 0; //root means square power level on rtl input signal
|
||||
//end RTL user options
|
||||
opts->pulse_raw_rate_in = 48000;
|
||||
opts->pulse_raw_rate_out = 48000; //
|
||||
opts->pulse_digi_rate_in = 48000;
|
||||
@@ -523,14 +564,24 @@ initOpts (dsd_opts * opts)
|
||||
opts->use_ncurses_terminal = 0;
|
||||
opts->ncurses_compact = 0;
|
||||
opts->ncurses_history = 1;
|
||||
#ifdef LIMAZULUTWEAKS
|
||||
opts->ncurses_compact = 1;
|
||||
#endif
|
||||
opts->payload = 0;
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->dmr_mono = 0;
|
||||
opts->dmr_stereo = 1;
|
||||
opts->aggressive_framesync = 1;
|
||||
|
||||
//this may not matter so much, since its already checked later on
|
||||
//but better safe than sorry I guess
|
||||
#ifdef AERO_BUILD
|
||||
opts->audio_in_type = 5;
|
||||
opts->audio_out_type = 5;
|
||||
#else
|
||||
opts->audio_in_type = 0;
|
||||
opts->audio_out_type = 0;
|
||||
#endif
|
||||
|
||||
opts->lrrp_file_output = 0;
|
||||
|
||||
@@ -547,7 +598,7 @@ initOpts (dsd_opts * opts)
|
||||
//rigctl options
|
||||
opts->use_rigctl = 0;
|
||||
opts->rigctl_sockfd = 0;
|
||||
opts->rigctlportno = 7356; //TCP Port Number; GQRX - 7356; SDR++ - 4532
|
||||
opts->rigctlportno = 4532; //TCP Port Number; GQRX - 7356; SDR++ - 4532
|
||||
sprintf (opts->rigctlhostname, "%s", "localhost");
|
||||
|
||||
//udp input options
|
||||
@@ -588,6 +639,9 @@ initOpts (dsd_opts * opts)
|
||||
//Trunking - Tune Data Calls
|
||||
opts->trunk_tune_data_calls = 0; //disabled by default
|
||||
|
||||
//Trunking - Tune Encrypted Calls (P25 only on applicable grants with svc opts)
|
||||
opts->trunk_tune_enc_calls = 1; //enabled by default
|
||||
|
||||
opts->dPMR_next_part_of_superframe = 0;
|
||||
|
||||
//OSS audio - Slot Preference
|
||||
@@ -600,6 +654,9 @@ initOpts (dsd_opts * opts)
|
||||
opts->dsp_out_file[0] = 0;
|
||||
opts->use_dsp_output = 0;
|
||||
|
||||
//Use P25p1 heuristics
|
||||
opts->use_heuristics = 0;
|
||||
|
||||
} //initopts
|
||||
|
||||
void
|
||||
@@ -866,6 +923,7 @@ initState (dsd_state * state)
|
||||
state->lcn_freq_roll = 0; //needs reset if sync is found?
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
state->last_active_time = time(NULL);
|
||||
state->is_con_plus = 0;
|
||||
|
||||
//dmr trunking/ncurses stuff
|
||||
@@ -881,13 +939,21 @@ initState (dsd_state * state)
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
state->nxdn_alias_block_number = 0;
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
|
||||
//site/srv/cch info
|
||||
state->nxdn_location_site_code = 0;
|
||||
state->nxdn_location_sys_code = 0;
|
||||
sprintf (state->nxdn_location_category, "%s", " ");
|
||||
|
||||
//channel access information
|
||||
state->nxdn_rcn = 0;
|
||||
state->nxdn_base_freq = 0;
|
||||
state->nxdn_step = 0;
|
||||
state->nxdn_bw = 0;
|
||||
|
||||
//multi-key array
|
||||
memset (state->rkey_array, 0, sizeof(state->rkey_array));
|
||||
memset (state->rkey_array, 0, sizeof(state->rkey_array));
|
||||
state->keyloader = 0; //keyloader off
|
||||
|
||||
//Remus DMR End Call Alert Beep
|
||||
state->dmr_end_alert[0] = 0;
|
||||
@@ -903,7 +969,7 @@ initState (dsd_state * state)
|
||||
|
||||
//initialize cap+ bits and block num storage
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
state->cap_plus_block_num = 0;
|
||||
memset (state->cap_plus_block_num, 0, sizeof(state->cap_plus_block_num));
|
||||
|
||||
//init confirmed data individual block crc as invalid
|
||||
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
|
||||
@@ -921,6 +987,7 @@ initState (dsd_state * state)
|
||||
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->active_channel, 0, sizeof(state->active_channel));
|
||||
|
||||
//REMUS! multi-purpose call_string
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
@@ -930,6 +997,7 @@ initState (dsd_state * state)
|
||||
memset (state->late_entry_mi_fragment, 0, sizeof (state->late_entry_mi_fragment));
|
||||
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||||
|
||||
state->dPMRVoiceFS2Frame.CalledIDOk = 0;
|
||||
state->dPMRVoiceFS2Frame.CallingIDOk = 0;
|
||||
@@ -947,30 +1015,45 @@ usage ()
|
||||
{
|
||||
|
||||
printf ("\n");
|
||||
printf ("Usage: dsd-fme-aero [options] Decoder/Trunking Mode\n");
|
||||
printf (" or: dsd-fme-aero [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" or: dsd-fme-aero -h Show help\n");
|
||||
printf ("Usage: dsd-fme [options] Decoder/Trunking Mode\n");
|
||||
printf (" or: dsd-fme [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" or: dsd-fme -h Show help\n");
|
||||
printf ("\n");
|
||||
printf ("Display Options:\n");
|
||||
printf (" -N Use NCurses Terminal\n");
|
||||
printf (" dsd-fme-aero -N 2> log.ans \n");
|
||||
printf (" dsd-fme -N 2> log.ans \n");
|
||||
printf (" -Z Log MBE/PDU Payloads to console\n");
|
||||
printf ("\n");
|
||||
printf ("Input/Output options:\n");
|
||||
#ifdef AERO_BUILD
|
||||
printf (" -i <device> Audio input device (default is /dev/dsp)\n");
|
||||
printf (" pulse for pulse audio \n");
|
||||
printf (" pulse for pulse audio (will require pactl running in Cygwin)\n");
|
||||
#else
|
||||
printf (" -i <device> Audio input device (default is pulse)\n");
|
||||
printf (" /dev/dsp for OSS audio (Depreciated: Will require padsp wrapper in Linux) \n");
|
||||
#endif
|
||||
printf (" rtl for rtl dongle (Default Values -- see below)\n");
|
||||
printf (" rtl:dev:freq:gain:ppm:bw:sq:udp for rtl dongle (see below)\n");
|
||||
printf (" tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)\n");
|
||||
printf (" tcp:192.168.7.5:7355 for custom address and port \n");
|
||||
printf (" filename.bin for OP25/FME capture bin files\n");
|
||||
printf (" filename.wav for 48K/1 wav files (SDR++, GQRX)\n");
|
||||
printf (" filename.wav -s 96000 for 96K/1 wav files (DSDPlus)\n");
|
||||
#ifdef AERO_BUILD
|
||||
printf (" (Use single quotes '\\directory\\audio file.wav' when directories/spaces are present)\n");
|
||||
#else
|
||||
printf (" (Use single quotes '/directory/audio file.wav' when directories/spaces are present)\n");
|
||||
#endif
|
||||
// printf (" (Windows - '\directory\audio file.wav' backslash, not forward slash)\n");
|
||||
printf (" -s <rate> Sample Rate of wav input files (48000 or 96000) Mono only!\n");
|
||||
#ifdef AERO_BUILD
|
||||
printf (" -o <device> Audio output device (default is /dev/dsp)\n");
|
||||
printf (" pulse for pulse audio (will require pactl running in Cygwin)\n");
|
||||
#else
|
||||
printf (" -o <device> Audio output device (default is pulse)\n");
|
||||
printf (" /dev/dsp for OSS audio (Depreciated: Will require padsp wrapper in Linux) \n");
|
||||
#endif
|
||||
printf (" null for no audio output\n");
|
||||
printf (" pulse for pulse audio \n");
|
||||
printf (" -d <dir> Create mbe data files, use this directory (TDMA version is experimental)\n");
|
||||
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
|
||||
@@ -981,32 +1064,33 @@ usage ()
|
||||
printf (" -a Enable Call Alert Beep (NCurses Terminal Only)\n");
|
||||
printf (" (Warning! Might be annoying.)\n");
|
||||
printf (" -L <file> Specify Filename for LRRP Data Output.\n");
|
||||
printf (" -Q <file> Specify Filename for DSP Structured File Output. (placed in DSP folder)\n");
|
||||
printf (" -Q <file> Specify Filename for OK-DMRlib Structured File Output. (placed in DSP folder)\n");
|
||||
printf (" -c <file> Output symbol capture to .bin file\n");
|
||||
printf (" -q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice\n");
|
||||
printf (" -V Enable Audio Smoothing on Upsampled 48k/1 or 24k/2 Audio (Capital V)\n");
|
||||
printf (" (Audio Smoothing is now disabled on all upsampled output by default -- fix crackle/buzz bug)\n");
|
||||
printf (" -z Set TDMA Voice Slot Preference when using OSS audio output (prevent lag and stuttering)\n");
|
||||
printf (" -z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)\n");
|
||||
printf ("\n");
|
||||
printf ("RTL-SDR options:\n");
|
||||
printf (" WARNING! Old CLI Switch Handling has been depreciated in favor of rtl:<parms>\n");
|
||||
printf (" Usage: rtl:dev:freq:gain:ppm:bw:sq:udp\n");
|
||||
printf (" NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended\n");
|
||||
printf (" dev <num> RTL-SDR Device Index Number\n");
|
||||
printf (" freq <num> RTL-SDR Frequency (851800000 or 851.8M) \n");
|
||||
printf (" gain <num> RTL-SDR Device Gain (0-49)(default = 26)(0 = Hardware AGC, not recommended)\n");
|
||||
printf (" gain <num> RTL-SDR Device Gain (0-49)(default = 0; Hardware AGC recommended)\n");
|
||||
printf (" ppm <num> RTL-SDR PPM Error (default = 0)\n");
|
||||
printf (" bw <num> RTL-SDR VFO Bandwidth kHz (default = 12)(6, 8, 12, 24) \n");
|
||||
printf (" sq <num> RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)\n");
|
||||
printf (" udp <num> RTL-SDR UDP Remote Port (default = 6020)\n");
|
||||
printf (" Example: dsd-fme-aero -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf (" bw <num> RTL-SDR Bandwidth kHz (default = 12)(4, 6, 8, 12, 16, 24) \n");
|
||||
printf (" sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)\n");
|
||||
printf (" udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)\n");
|
||||
printf (" Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T\n");
|
||||
printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:6021\n");
|
||||
printf ("\n");
|
||||
printf ("Decoder options:\n");
|
||||
printf (" -fa Legacy Auto Detection (old methods default)\n");
|
||||
printf (" -ft XDMA P25 and DMR BS/MS frame types (new default)\n");
|
||||
printf (" -fs DMR Stereo BS and MS Simplex\n");
|
||||
printf (" -f1 Decode only P25 Phase 1\n");
|
||||
printf (" -f2 Decode only P25 Phase 2 (6000 sps) **\n");
|
||||
printf (" -fd Decode only D-STAR\n");
|
||||
printf (" -fr Decode only DMR Mono - Single Slot Voice\n");
|
||||
printf (" -fx Decode only X2-TDMA\n");
|
||||
printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n");
|
||||
printf (" -fn Decode only NXDN96* (12.5 kHz)\n");
|
||||
@@ -1019,6 +1103,7 @@ usage ()
|
||||
printf (" -xd Expect inverted ICOM dPMR signal\n");
|
||||
printf ("\n");
|
||||
printf (" * denotes frame types that cannot be auto-detected.\n");
|
||||
printf (" ** Phase 2 Single Frequency may require user to manually set WACN/SYSID/CC parameters if MAC_SIGNAL not present.\n");
|
||||
printf ("\n");
|
||||
printf ("Advanced Decoder options:\n");
|
||||
printf (" -X <hex> Manually Set P2 Parameters (WACN, SYSID, CC/NAC)\n");
|
||||
@@ -1036,18 +1121,19 @@ usage ()
|
||||
printf (" -mc Use only C4FM modulation optimizations\n");
|
||||
printf (" -mg Use only GFSK modulation optimizations\n");
|
||||
printf (" -mq Use only QPSK modulation optimizations\n");
|
||||
printf (" -m2 Use P25p2 6000 sps CQPSK modulation optimizations\n");
|
||||
printf (" -m2 Use P25p2 6000 sps QPSK modulation optimizations\n");
|
||||
//printf (" (4 Level, not 8 Level LSM) (this is honestly unknown since I can't verify what local systems are using)\n");
|
||||
printf (" -F Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n");
|
||||
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
|
||||
printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
|
||||
printf (" Enabling on some systems could lead to bad voice/data decoding if bad or marginal signal\n");
|
||||
printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n");
|
||||
printf (" -F Relax NXDN SACCH/FACCH/CAC/F2U CRC Pass/Fail\n");
|
||||
printf (" Not recommended on NXDN, but can be bypassed if desired.\n");
|
||||
printf ("\n");
|
||||
printf (" -K <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
|
||||
printf (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
|
||||
printf (" (NOTE: This used to be the 'K' option! \n");
|
||||
printf ("\n");
|
||||
printf (" -H <hex> Manually Enter **tera 10/32/64 Char Privacy Hex Key (see example below)\n");
|
||||
printf (" -H <hex> Manually Enter **tera 10/32/64 Char Basic Privacy Hex Key (see example below)\n");
|
||||
printf (" Encapulate in Single Quotation Marks; Space every 16 chars.\n");
|
||||
printf (" -H 0B57935150 \n");
|
||||
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
@@ -1055,11 +1141,18 @@ usage ()
|
||||
printf ("\n");
|
||||
printf (" -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n");
|
||||
printf (" \n");
|
||||
printf (" -k <file> Import Key List from csv file.\n");
|
||||
printf (" Only supports NXDN, DMR Basic Privacy and **tera 10-Char (decimal value) only. \n");
|
||||
printf (" -1 <hex> Manually Enter RC4 Key Value (DMR, P25) (Hex Value) \n");
|
||||
printf (" \n");
|
||||
printf (" -k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.\n");
|
||||
printf (" Only supports NXDN, DMR Basic Privacy (decimal value). \n");
|
||||
printf (" (dPMR and **tera 32/64 char not supported, DMR uses TG value as key id -- EXPERIMENTAL!!). \n");
|
||||
printf (" \n");
|
||||
printf (" -4 Force Privacy Key over FID and SVC bits \n");
|
||||
printf (" -K <file> Import Key List from csv file (Hexidecimal Format) -- Capital 'K'.\n");
|
||||
printf (" Use for Hex Value **tera 10-char BP keys and RC4 10-Char Hex Keys. \n");
|
||||
printf (" \n");
|
||||
printf (" -4 Force Privacy Key over Encryption Identifiers (DMR BP and NXDN Scrambler) \n");
|
||||
printf (" \n");
|
||||
printf (" -0 Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR) \n");
|
||||
printf ("\n");
|
||||
printf (" Trunking Options:\n");
|
||||
printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n");
|
||||
@@ -1071,19 +1164,19 @@ usage ()
|
||||
printf (" Experimental -- Can only scan for sync with enabled decoders, don't mix NXDN and DMR/P25!\n");
|
||||
printf (" This is not a Trunking Feature, just scans through conventional frequencies fast!\n");
|
||||
printf (" -W Use Imported Group List as a Trunking Allow/White List -- Only Tune with Mode A\n");
|
||||
printf (" -p Disable Tune to Private Calls (DMR TIII and P25)\n");
|
||||
printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+ and P25)\n");
|
||||
printf (" (NOTE: NXDN and EDACS, simply disable trunking if desired) \n");
|
||||
printf (" -e Enable Tune to Data Calls (DMR TIII)\n");
|
||||
printf (" -p Disable Tune to Private Calls (DMR TIII, P25, NXDN Type-C and Type-D)\n");
|
||||
printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+, P25, NXDN Type-C, and Type-D)\n");
|
||||
printf (" -e Enable Tune to Data Calls (DMR TIII, Cap+, NXDN Type-C)\n");
|
||||
printf (" (NOTE: No Clear Distinction between Cap+ Private Voice Calls and Data Calls -- Both enabled with Data Calls \n");
|
||||
printf (" (NOTE: P25 Data Channels Not Enabled (no handling) \n");
|
||||
printf (" -U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)\n");
|
||||
printf (" -B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)\n");
|
||||
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 4000; DMR - 7000; EDACS/PV - 12500;\n");
|
||||
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 7000; NXDN96: 9000; DMR - 7000; EDACS/PV - 12500;\n");
|
||||
printf (" May vary based on system stregnth, etc.\n");
|
||||
printf (" -t <secs> Set Trunking or Fast Scan VC/sync loss hangtime in seconds. (default = 1 second) (decimal values permitted) \n");
|
||||
printf (" -t <secs> Set Trunking or Fast Scan VC/sync loss hangtime in seconds. (default = 1 second)\n");
|
||||
printf ("\n");
|
||||
printf (" Trunking Example TCP: dsd-fme-aero -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf (" Trunking Example RTL: dsd-fme-aero -fs -i rtl:0:450M:26:-2:8:0:6020 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf (" Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf (" Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf ("\n");
|
||||
exit (0);
|
||||
}
|
||||
@@ -1119,9 +1212,9 @@ if (opts->audio_in_type == 1)
|
||||
{
|
||||
opts->pulse_digi_rate_out = 24000; //rtl needs 24000 by 2 channel for DMR TDMA Stereo output
|
||||
opts->pulse_digi_out_channels = 2; //minimal crackling 'may' be observed, not sure, can't test to see on DMR with RTL
|
||||
fprintf (stderr, "RTL Audio Rate Out set to 24000 Khz/2 Channel \n");
|
||||
// fprintf (stderr, "RTL Audio Rate Out set to 24000 Khz/2 Channel \n");
|
||||
}
|
||||
else fprintf (stderr, "RTL Audio Rate Out set to 48000 Khz/1 Channel \n");
|
||||
// else fprintf (stderr, "RTL Audio Rate Out set to 48000 Khz/1 Channel \n");
|
||||
opts->pulse_raw_rate_out = 48000;
|
||||
opts->pulse_raw_out_channels = 1;
|
||||
|
||||
@@ -1262,16 +1355,21 @@ main (int argc, char **argv)
|
||||
char versionstr[25];
|
||||
mbe_printVersion (versionstr);
|
||||
|
||||
#ifdef LIMAZULUTWEAKS
|
||||
fprintf (stderr," Digital Speech Decoder: LimaZulu Edition IV\n");
|
||||
#else
|
||||
fprintf (stderr," Digital Speech Decoder: Florida Man Edition\n");
|
||||
for (short int i = 1; i < 8; i++) {
|
||||
//fprintf (stderr,"%s%s \n", FM_banner[i], KGRN); //cyan/blue text
|
||||
fprintf (stderr,"%s\n", FM_banner[i]); //cyan/blue tex
|
||||
#endif
|
||||
for (short int i = 1; i < 7; i++) {
|
||||
fprintf (stderr,"%s\n", FM_banner[i]);
|
||||
}
|
||||
//fprintf (stderr,"%s", KNRM); //change back to normal
|
||||
|
||||
// git_tag not working in 32-bit cygwin? or issue with copy and paste, even with the .git folder?
|
||||
// fprintf (stderr, "Github Build Version: %s \n", GIT_TAG);
|
||||
// fprintf (stderr,"MBElib version %s\n", versionstr);
|
||||
#ifdef AERO_BUILD
|
||||
fprintf (stderr, "Build Version: v2.1 Beta \n");
|
||||
#else
|
||||
fprintf (stderr, "Build Version: %s \n", GIT_TAG);
|
||||
#endif
|
||||
fprintf (stderr,"MBElib Version: %s\n", versionstr);
|
||||
|
||||
initOpts (&opts);
|
||||
initState (&state);
|
||||
@@ -1280,7 +1378,7 @@ main (int argc, char **argv)
|
||||
|
||||
exitflag = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1)
|
||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1)
|
||||
{
|
||||
opterr = 0;
|
||||
switch (c)
|
||||
@@ -1288,23 +1386,52 @@ main (int argc, char **argv)
|
||||
case 'h':
|
||||
usage ();
|
||||
exit (0);
|
||||
|
||||
case 'a':
|
||||
opts.call_alert = 1;
|
||||
break;
|
||||
|
||||
//Free'd up switches include
|
||||
//Free'd up switches include: I, J, j, n, O, v, y
|
||||
//all numerals have reclaimed, except for 4 and 0,1 (rc4 enforcement and single key)
|
||||
|
||||
//make sure to put a colon : after each if they need an argument
|
||||
//or remove colon if no argument required
|
||||
|
||||
//NOTE: The 'K' option for single BP key has been swapped to 'b'
|
||||
//'K' is now used for hexidecimal key.csv imports
|
||||
|
||||
//rc4 enforcement on DMR (due to missing the PI header)
|
||||
case '0':
|
||||
state.M = 0x21;
|
||||
fprintf (stderr,"Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR)\n");
|
||||
break;
|
||||
|
||||
//load single rc4 key
|
||||
case '1':
|
||||
sscanf (optarg, "%llX", &state.R);
|
||||
state.RR = state.R; //put key on both sides
|
||||
fprintf (stderr, "RC4 Encryption Key Value set to 0x%llX \n", state.R);
|
||||
opts.unmute_encrypted_p25 = 0;
|
||||
state.keyloader = 0; //turn off keyloader
|
||||
break;
|
||||
|
||||
case 'Y': //conventional scanner mode
|
||||
opts.scanner_mode = 1; //enable scanner
|
||||
opts.p25_trunk = 0; //turn off trunking mode if user enabled it
|
||||
break;
|
||||
|
||||
case 'k': //NXDN multi-key loader
|
||||
case 'k': //multi-key loader (dec)
|
||||
strncpy(opts.key_in_file, optarg, 1023);
|
||||
opts.key_in_file[1023] = '\0';
|
||||
csvKeyImport(&opts, &state);
|
||||
csvKeyImportDec(&opts, &state);
|
||||
state.keyloader = 1;
|
||||
break;
|
||||
|
||||
case 'K': //multi-key loader (hex)
|
||||
strncpy(opts.key_in_file, optarg, 1023);
|
||||
opts.key_in_file[1023] = '\0';
|
||||
csvKeyImportHex(&opts, &state);
|
||||
state.keyloader = 1;
|
||||
break;
|
||||
|
||||
case 'Q': //'DSP' Structured Output file for OKDMRlib
|
||||
@@ -1326,13 +1453,12 @@ main (int argc, char **argv)
|
||||
|
||||
case 'z':
|
||||
sscanf (optarg, "%d", &opts.slot_preference);
|
||||
opts.slot_preference--; //user inputs 1 or 2, internally we want 0 and 1
|
||||
if (opts.slot_preference > 0) opts.slot_preference--; //user inputs 1 or 2, internally we want 0 and 1
|
||||
if (opts.slot_preference > 1) opts.slot_preference = 1;
|
||||
fprintf (stderr, "TDMA (DMR and P2) Slot Voice Preference is Slot %d. \n", opts.slot_preference+1);
|
||||
break;
|
||||
|
||||
//Enable Audio Smoothing for Upsampled Audio
|
||||
case '0':
|
||||
case 'V':
|
||||
state.audio_smoothing = 1;
|
||||
break;
|
||||
@@ -1370,28 +1496,23 @@ main (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'C': //new letter assignment for Channel import, flow down to allow temp numbers
|
||||
case '1': //LCN to Frequency CSV Import <--> flow down to chanimport now, tell users to use a channel map for edacs
|
||||
case '7': //Channel Map Frequency CSV Import
|
||||
strncpy(opts.chan_in_file, optarg, 1023);
|
||||
opts.chan_in_file[1023] = '\0';
|
||||
csvChanImport (&opts, &state);
|
||||
break;
|
||||
|
||||
case 'G': //new letter assignment for group import, flow down to allow temp numbers
|
||||
case '2': //Group CSV Import
|
||||
strncpy(opts.group_in_file, optarg, 1023);
|
||||
opts.group_in_file[1023] = '\0';
|
||||
csvGroupImport(&opts, &state);
|
||||
break;
|
||||
|
||||
case 'T': //new letter assignment for trunking, flow down to allow temp numbers
|
||||
case '3':
|
||||
opts.p25_trunk = 1;
|
||||
opts.scanner_mode = 0; //turn off scanner mode if user enabled it
|
||||
break;
|
||||
|
||||
case 'U': //New letter assignment for RIGCTL TCP port, flow down to allow temp numbers
|
||||
case '5': //RIGCTL TCP port
|
||||
sscanf (optarg, "%d", &opts.rigctlportno);
|
||||
if (opts.rigctlportno != 0) opts.use_rigctl = 1;
|
||||
break;
|
||||
@@ -1401,19 +1522,16 @@ main (int argc, char **argv)
|
||||
//may change to a different return on sync times and this will matter!
|
||||
|
||||
case 't': //New letter assignment for Trunk Hangtime, flow down to allow temp numbers
|
||||
case '6': //hangtime in seconds, default is 1;
|
||||
sscanf (optarg, "%f", &opts.trunk_hangtime); //updated for float/decimal values
|
||||
fprintf (stderr, "Trunking or Fast Scanner Hang Time set to: %.02f sec\n", opts.trunk_hangtime);
|
||||
break;
|
||||
|
||||
case 'q': //New letter assignment for Reverse Mute, flow down to allow temp numbers
|
||||
case '8':
|
||||
opts.reverse_mute = 1;
|
||||
fprintf (stderr, "Reverse Mute\n");
|
||||
break;
|
||||
|
||||
case 'B': //New letter assignment for RIGCTL SetMod BW, flow down to allow temp numbers
|
||||
case '9': //rigctl setmod bandwidth;
|
||||
sscanf (optarg, "%d", &opts.setmod_bw);
|
||||
if (opts.setmod_bw > 25000) opts.setmod_bw = 25000; //not too high
|
||||
break;
|
||||
@@ -1425,15 +1543,15 @@ main (int argc, char **argv)
|
||||
state.symbolCenter = state.symbolCenter * opts.wav_interpolator;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
sscanf (optarg, "%d", &opts.verbose);
|
||||
break;
|
||||
// case 'v':
|
||||
// sscanf (optarg, "%d", &opts.verbose);
|
||||
// break;
|
||||
|
||||
case 'n': //disable or reclaim?
|
||||
state.use_throttle = 1;
|
||||
break;
|
||||
// case 'n': //disable or reclaim?
|
||||
// state.use_throttle = 1;
|
||||
// break;
|
||||
|
||||
case 'K':
|
||||
case 'b': //formerly Capital 'K'
|
||||
sscanf (optarg, "%lld", &state.K);
|
||||
if (state.K > 256)
|
||||
{
|
||||
@@ -1450,17 +1568,9 @@ main (int argc, char **argv)
|
||||
|
||||
case 'R':
|
||||
sscanf (optarg, "%lld", &state.R);
|
||||
if (state.R > 0x7FFF)
|
||||
{
|
||||
state.R = 0x7FFF;
|
||||
}
|
||||
// opts.dmr_mute_encL = 0;
|
||||
// opts.dmr_mute_encR = 0;
|
||||
if (state.R == 0)
|
||||
{
|
||||
// opts.dmr_mute_encL = 1;
|
||||
// opts.dmr_mute_encR = 1;
|
||||
}
|
||||
if (state.R > 0x7FFF) state.R = 0x7FFF;
|
||||
//disable keyloader in case user tries to use this and it at the same time
|
||||
state.keyloader = 0;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
@@ -1485,7 +1595,7 @@ main (int argc, char **argv)
|
||||
|
||||
case '4':
|
||||
state.M = 1;
|
||||
fprintf (stderr,"Force Privacy Key Priority over FID and SVC bits.\n");
|
||||
fprintf (stderr,"Force Privacy Key over Encryption Identifiers (DMR BP and NXDN Scrambler) \n");
|
||||
break;
|
||||
|
||||
//manually set Phase 2 TDMA WACN/SYSID/CC
|
||||
@@ -1695,6 +1805,9 @@ main (int argc, char **argv)
|
||||
sprintf (opts.output_name, "EDACS/PV");
|
||||
fprintf (stderr,"Setting symbol rate to 9600 / second\n");
|
||||
fprintf (stderr,"Decoding only ProVoice frames.\n");
|
||||
//rtl specific tweaks
|
||||
opts.rtl_bandwidth = 24;
|
||||
// opts.rtl_gain_value = 36;
|
||||
}
|
||||
else if (optarg[0] == '1')
|
||||
{
|
||||
@@ -1721,7 +1834,8 @@ main (int argc, char **argv)
|
||||
// opts.setmod_bw = 12000;
|
||||
opts.ssize = 36; //128 current default, fall back to old default on P1 only systems
|
||||
opts.msize = 15; //1024 current default, fall back to old default on P1 only systems
|
||||
sprintf (opts.output_name, "P25P1");
|
||||
opts.use_heuristics = 1; //enable for Phase 1 only
|
||||
sprintf (opts.output_name, "P25p1");
|
||||
fprintf (stderr,"Decoding only P25 Phase 1 frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'i')
|
||||
@@ -1792,8 +1906,8 @@ main (int argc, char **argv)
|
||||
opts.frame_dpmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
opts.frame_ysf = 0;
|
||||
state.samplesPerSymbol = 10;
|
||||
state.symbolCenter = 4;
|
||||
state.samplesPerSymbol = 8;
|
||||
state.symbolCenter = 3;
|
||||
opts.mod_c4fm = 1;
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 0;
|
||||
@@ -1802,8 +1916,8 @@ main (int argc, char **argv)
|
||||
state.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
// opts.setmod_bw = 12000;
|
||||
sprintf (opts.output_name, "P25P2");
|
||||
fprintf (stderr,"Decoding P25-P2 frames C4FM or OP25 Symbol Captures!\n");
|
||||
sprintf (opts.output_name, "P25p2");
|
||||
fprintf (stderr,"Decoding 6000 sps P25p2 frames only!\n");
|
||||
}
|
||||
else if (optarg[0] == 's')
|
||||
{
|
||||
@@ -1899,15 +2013,15 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 0; //
|
||||
state.rf_mod = 0; //
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_mono = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.pulse_digi_rate_out = 24000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
opts.dmr_mono = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
state.dmr_stereo = 0; //0
|
||||
// opts.setmod_bw = 7000;
|
||||
sprintf (opts.output_name, "DMR Mono");
|
||||
fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n");
|
||||
fprintf (stderr,"Decoding only DMR Mono. \nUsing DMR Stereo '-fs' or XDMA '-ft' is highly encouraged.\n");
|
||||
sprintf (opts.output_name, "DMR Stereo");
|
||||
fprintf (stderr,"-fr / DMR Mono switch has been deprecated.\n");
|
||||
fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
|
||||
|
||||
}
|
||||
else if (optarg[0] == 'm')
|
||||
@@ -1982,7 +2096,7 @@ main (int argc, char **argv)
|
||||
state.samplesPerSymbol = 8;
|
||||
state.symbolCenter = 3;
|
||||
// opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling 6000 sps P25p2 CQPSK.\n");
|
||||
fprintf (stderr,"Enabling 6000 sps P25p2 QPSK.\n");
|
||||
}
|
||||
//test
|
||||
else if (optarg[0] == '3')
|
||||
@@ -2123,16 +2237,20 @@ main (int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
opts.audio_in_type = 5;
|
||||
fprintf (stderr, "TCP Connection Failure - Using Pulse Audio Input.\n");
|
||||
#ifdef AERO_BUILD
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
opts.audio_in_type = 5;
|
||||
#else
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "TCP Connection Failure - Using %s Audio Input.\n", opts.audio_in_dev);
|
||||
opts.audio_in_type = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (opts.use_rigctl == 1)
|
||||
{
|
||||
// opts.rigctl_sockfd = Connect(opts.rigctlhostname, opts.rigctlportno);
|
||||
opts.rigctl_sockfd = Connect(opts.rigctlhostname, opts.rigctlportno);
|
||||
if (opts.rigctl_sockfd != 0) opts.use_rigctl = 1;
|
||||
else
|
||||
@@ -2175,12 +2293,12 @@ main (int argc, char **argv)
|
||||
int bw = 0;
|
||||
bw = atoi (curr);
|
||||
//check for proper values (6,8,12,24)
|
||||
if (bw == 6 || bw == 8 || bw == 12 || bw == 24)
|
||||
if (bw == 4 || bw == 6 || bw == 8 || bw == 12 || bw == 16 || bw == 24) //testing 4 and 16 as well for weak and/or nxdn48 systems
|
||||
{
|
||||
opts.rtl_bandwidth = bw;
|
||||
}
|
||||
else
|
||||
opts.rtl_bandwidth = 12; //safe default
|
||||
opts.rtl_bandwidth = 12; //safe default -- provides best performance on most systems
|
||||
}
|
||||
else goto RTLEND;
|
||||
|
||||
@@ -2205,25 +2323,35 @@ main (int argc, char **argv)
|
||||
rtl_ok = 1;
|
||||
#endif
|
||||
|
||||
#ifdef AERO_BUILD
|
||||
if (rtl_ok == 0) //not set, means rtl support isn't compiled/available
|
||||
{
|
||||
fprintf (stderr, "RTL Support not enabled/compiled, falling back to OSS /dev/dsp Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
opts.audio_in_type = 5;
|
||||
}
|
||||
#else
|
||||
if (rtl_ok == 0) //not set, means rtl support isn't compiled/available
|
||||
{
|
||||
fprintf (stderr, "RTL Support not enabled/compiled, falling back to Pulse Audio Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
opts.audio_in_type = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//doesn't work correctly, so just going to reroute to /dev/dsp instead
|
||||
if((strncmp(opts.audio_in_dev, "udp", 3) == 0)) //udp socket input from SDR++, GQRX, and others
|
||||
{
|
||||
fprintf (stderr, "UDP Input not working, falling back to OSS /dev/dsp Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
opts.audio_in_type = 5;
|
||||
}
|
||||
// if((strncmp(opts.audio_in_dev, "udp", 3) == 0)) //udp socket input from SDR++, GQRX, and others
|
||||
// {
|
||||
// fprintf (stderr, "UDP Input not working, falling back to OSS /dev/dsp Audio Input.\n");
|
||||
// sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
// opts.audio_in_type = 5;
|
||||
// }
|
||||
|
||||
int fmt;
|
||||
int speed = 48000;
|
||||
|
||||
//NOTE: Both /dev/audio AND /dev/dsp randomly open multiple input streams in Linux under padsp wrapper
|
||||
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
@@ -2362,58 +2490,60 @@ main (int argc, char **argv)
|
||||
opts.playoffset = 0;
|
||||
opts.playoffsetR = 0;
|
||||
opts.delay = 0;
|
||||
if (strlen(opts.wav_out_file) > 0 && opts.dmr_stereo_wav == 0)
|
||||
{
|
||||
openWavOutFile (&opts, &state);
|
||||
}
|
||||
|
||||
//open wav file should be handled directly by the -w switch now
|
||||
// if (strlen(opts.wav_out_file) > 0 && opts.dmr_stereo_wav == 0)
|
||||
// {
|
||||
// openWavOutFile (&opts, &state);
|
||||
// }
|
||||
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts); //need to open it up for output?
|
||||
if (opts.audio_out_type == 0) openPulseOutput(&opts);
|
||||
if (opts.audio_out_type == 5) openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
|
||||
}
|
||||
|
||||
//this particular if-elseif-else could be rewritten to be a lot neater and simpler
|
||||
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
|
||||
{
|
||||
opts.split = 1;
|
||||
opts.playoffset = 0;
|
||||
opts.playoffsetR = 0;
|
||||
opts.delay = 0;
|
||||
if (strlen(opts.wav_out_file) > 0 && opts.dmr_stereo_wav == 0)
|
||||
{
|
||||
openWavOutFile (&opts, &state);
|
||||
}
|
||||
else
|
||||
{
|
||||
openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
|
||||
}
|
||||
|
||||
//open wav file should be handled directly by the -w switch now
|
||||
// if (strlen(opts.wav_out_file) > 0 && opts.dmr_stereo_wav == 0)
|
||||
// openWavOutFile (&opts, &state);
|
||||
|
||||
// else
|
||||
|
||||
openAudioInDevice (&opts);
|
||||
|
||||
|
||||
fprintf (stderr,"Press CTRL + C to close.\n");
|
||||
// fprintf (stderr,"Press CTRL + C to close.\n");
|
||||
}
|
||||
|
||||
else
|
||||
else
|
||||
{
|
||||
opts.split = 0;
|
||||
opts.playoffset = 25;
|
||||
opts.playoffsetR = 25;
|
||||
opts.playoffset = 0; //not sure what the playoffset actually does for us
|
||||
opts.playoffsetR = 0;
|
||||
opts.delay = 0;
|
||||
openAudioInDevice (&opts);
|
||||
opts.audio_out_fd = opts.audio_in_fd;
|
||||
// opts.audio_out_fd = opts.audio_in_fd; //not sure that this really does much anymore, other than cause problems
|
||||
}
|
||||
|
||||
if (opts.playfiles == 1)
|
||||
if (opts.playfiles == 1)
|
||||
{
|
||||
state.aout_gain = 25; //BUGFIX: No audio output when playing back .amb/.imb files
|
||||
playMbeFiles (&opts, &state, argc, argv);
|
||||
}
|
||||
|
||||
else
|
||||
else
|
||||
{
|
||||
liveScanner (&opts, &state);
|
||||
}
|
||||
|
||||
cleanupAndExit (&opts, &state);
|
||||
cleanupAndExit (&opts, &state);
|
||||
|
||||
return (0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
476
src/dsd_mbe.c
476
src/dsd_mbe.c
@@ -17,6 +17,56 @@
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//test for potential clashing with other key loading mechanisms (bp key loading on tgid, nxdn key loading, etc)
|
||||
void keyring(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
//keys now loaded from csv files with the -K key.csv file (capital K)
|
||||
if (state->currentslot == 0)
|
||||
state->R = state->rkey_array[state->payload_keyid];
|
||||
|
||||
if (state->currentslot == 1)
|
||||
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[])
|
||||
{
|
||||
int i, j, count;
|
||||
uint8_t t, b;
|
||||
|
||||
//init Sbox
|
||||
uint8_t S[256];
|
||||
for(int i = 0; i < 256; i++) S[i] = i;
|
||||
|
||||
//Key Scheduling
|
||||
j = 0;
|
||||
for(i = 0; i < 256; i++)
|
||||
{
|
||||
j = (j + S[i] + key[i % keylength]) % 256;
|
||||
t = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = t;
|
||||
}
|
||||
|
||||
//Drop Bytes and Cipher Byte XOR
|
||||
i = j = 0;
|
||||
for(count = 0; count < (messagelength + drop); count++)
|
||||
{
|
||||
i = (i + 1) % 256;
|
||||
j = (j + S[i]) % 256;
|
||||
t = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = t;
|
||||
b = S[(S[i] + S[j]) % 256];
|
||||
|
||||
//return mbe payload byte here
|
||||
if (count >= drop)
|
||||
plain[count - drop] = b^cipher[count - drop];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int Pr[256] = {
|
||||
0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903,
|
||||
0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306,
|
||||
@@ -140,8 +190,15 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
unsigned long long int k;
|
||||
int x;
|
||||
|
||||
//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->payload_keyid != 0 && state->keyloader == 1)
|
||||
keyring (opts, state);
|
||||
|
||||
if (state->currentslot == 1 && state->payload_algidR != 0 && state->payload_algidR != 0x80 && state->payload_keyidR != 0 && state->keyloader == 1)
|
||||
keyring (opts, state);
|
||||
|
||||
//24-bit TG to 16-bit hash
|
||||
uint16_t hash = 0;
|
||||
uint32_t hash = 0;
|
||||
uint8_t hash_bits[24];
|
||||
memset (hash_bits, 0, sizeof(hash_bits));
|
||||
|
||||
@@ -192,7 +249,73 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
mbe_demodulateImbe7200x4400Data (imbe_fr);
|
||||
state->errs2 = mbe_eccImbe7200x4400Data (imbe_fr, imbe_d);
|
||||
|
||||
//P25p1 RC4 Handling
|
||||
if (state->payload_algid == 0xAA && state->R != 0)
|
||||
{
|
||||
uint8_t cipher[11] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t plain[11] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t rckey[13] = {0x00, 0x00, 0x00, 0x00, 0x00, // <- RC4 Key
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, // <- MI
|
||||
0x00, 0x00, 0x00}; // <- MI cont.
|
||||
|
||||
//easier to manually load up rather than make a loop
|
||||
rckey[0] = ((state->R & 0xFF00000000) >> 32);
|
||||
rckey[1] = ((state->R & 0xFF000000) >> 24);
|
||||
rckey[2] = ((state->R & 0xFF0000) >> 16);
|
||||
rckey[3] = ((state->R & 0xFF00) >> 8);
|
||||
rckey[4] = ((state->R & 0xFF) >> 0);
|
||||
|
||||
// load valid MI from state->payload_miP
|
||||
rckey[5] = ((state->payload_miP & 0xFF00000000000000) >> 56);
|
||||
rckey[6] = ((state->payload_miP & 0xFF000000000000) >> 48);
|
||||
rckey[7] = ((state->payload_miP & 0xFF0000000000) >> 40);
|
||||
rckey[8] = ((state->payload_miP & 0xFF00000000) >> 32);
|
||||
rckey[9] = ((state->payload_miP & 0xFF000000) >> 24);
|
||||
rckey[10] = ((state->payload_miP & 0xFF0000) >> 16);
|
||||
rckey[11] = ((state->payload_miP & 0xFF00) >> 8);
|
||||
rckey[12] = ((state->payload_miP & 0xFF) >> 0);
|
||||
|
||||
// if (state->p25vc == 0)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, "\n RC4K ");
|
||||
// for (short o = 0; o < 13; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// }
|
||||
|
||||
//load imbe_d into imbe_cipher octets
|
||||
int z = 0;
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
cipher[i] = 0;
|
||||
plain[i] = 0;
|
||||
for (short int j = 0; j < 8; j++)
|
||||
{
|
||||
cipher[i] = cipher[i] << 1;
|
||||
cipher[i] = cipher[i] + imbe_d[z];
|
||||
imbe_d[z] = 0;
|
||||
z++;
|
||||
}
|
||||
}
|
||||
|
||||
RC4(state->dropL, 13, 11, rckey, cipher, plain);
|
||||
state->dropL += 11;
|
||||
|
||||
z = 0;
|
||||
for (short p = 0; p < 11; p++)
|
||||
{
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
imbe_d[z] = (plain[p] & 0x80) >> 7;
|
||||
plain[p] = plain[p] << 1;
|
||||
z++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -218,17 +341,16 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
//state->errs2 = state->errs;
|
||||
mbe_demodulateImbe7100x4400Data (imbe7100_fr);
|
||||
state->errs2 = mbe_eccImbe7100x4400Data (imbe7100_fr, imbe_d);
|
||||
mbe_convertImbe7100to7200(imbe_d); //needs extra conversion step apparently
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
PrintIMBEData (opts, state, imbe_d);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//below line the old way of doing this
|
||||
// mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
PrintIMBEData (opts, state, imbe_d);
|
||||
}
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
saveImbe4400Data (opts, state, imbe_d);
|
||||
@@ -300,11 +422,12 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
|
||||
//EXPERIMENTAL!!
|
||||
//load basic privacy key number from array by the tg value (if not forced)
|
||||
//currently only Moto BP and Hytera 10 Char BP (converted to decimal)
|
||||
if (state->M == 0)
|
||||
//currently only Moto BP and Hytera 10 Char BP
|
||||
if (state->M == 0 && state->payload_algid == 0)
|
||||
{
|
||||
//see if we need to hash a value larger than 16-bits
|
||||
hash = state->lasttg & 0xFFFFFF;
|
||||
hash = state->lasttg & 0xFFFFFF;
|
||||
// fprintf (stderr, "TG: %lld Hash: %ld ", state->lasttg, hash);
|
||||
if (hash > 0xFFFF) //if greater than 16-bits
|
||||
{
|
||||
for (int i = 0; i < 24; i++)
|
||||
@@ -313,12 +436,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
hash = ComputeCrcCCITT16d (hash_bits, 24);
|
||||
hash = hash & 0xFFFF; //make sure its no larger than 16-bits
|
||||
// fprintf (stderr, "Hash: %d ", hash);
|
||||
}
|
||||
if (state->rkey_array[hash] != 0)
|
||||
{
|
||||
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
|
||||
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
||||
opts->dmr_mute_encL = 0;
|
||||
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
|
||||
}
|
||||
// else opts->dmr_mute_encL = 1; //may cause issues for manual key entry (non-csv)
|
||||
}
|
||||
@@ -398,6 +523,155 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
state->DMRvcL++;
|
||||
}
|
||||
|
||||
//DMR RC4, Slot 1
|
||||
if (state->currentslot == 0 && state->payload_algid == 0x21 && state->R != 0)
|
||||
{
|
||||
uint8_t cipher[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
|
||||
0x00, 0x00, 0x00, 0x00}; // <- MI
|
||||
|
||||
//easier to manually load up rather than make a loop
|
||||
rckey[0] = ((state->R & 0xFF00000000) >> 32);
|
||||
rckey[1] = ((state->R & 0xFF000000) >> 24);
|
||||
rckey[2] = ((state->R & 0xFF0000) >> 16);
|
||||
rckey[3] = ((state->R & 0xFF00) >> 8);
|
||||
rckey[4] = ((state->R & 0xFF) >> 0);
|
||||
rckey[5] = ((state->payload_mi & 0xFF000000) >> 24);
|
||||
rckey[6] = ((state->payload_mi & 0xFF0000) >> 16);
|
||||
rckey[7] = ((state->payload_mi & 0xFF00) >> 8);
|
||||
rckey[8] = ((state->payload_mi & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 9; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
|
||||
RC4(state->dropL, 9, 7, rckey, cipher, plain);
|
||||
state->dropL += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p < 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//P25p2 RC4 Handling, VCH 0
|
||||
if (state->currentslot == 0 && state->payload_algid == 0xAA && state->R != 0 && ((state->synctype == 35) || (state->synctype == 36)))
|
||||
{
|
||||
uint8_t cipher[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
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, // <- MI
|
||||
0x00, 0x00, 0x00}; // <- MI cont.
|
||||
|
||||
//easier to manually load up rather than make a loop
|
||||
rckey[0] = ((state->R & 0xFF00000000) >> 32);
|
||||
rckey[1] = ((state->R & 0xFF000000) >> 24);
|
||||
rckey[2] = ((state->R & 0xFF0000) >> 16);
|
||||
rckey[3] = ((state->R & 0xFF00) >> 8);
|
||||
rckey[4] = ((state->R & 0xFF) >> 0);
|
||||
|
||||
// load valid MI from state->payload_miP
|
||||
rckey[5] = ((state->payload_miP & 0xFF00000000000000) >> 56);
|
||||
rckey[6] = ((state->payload_miP & 0xFF000000000000) >> 48);
|
||||
rckey[7] = ((state->payload_miP & 0xFF0000000000) >> 40);
|
||||
rckey[8] = ((state->payload_miP & 0xFF00000000) >> 32);
|
||||
rckey[9] = ((state->payload_miP & 0xFF000000) >> 24);
|
||||
rckey[10] = ((state->payload_miP & 0xFF0000) >> 16);
|
||||
rckey[11] = ((state->payload_miP & 0xFF00) >> 8);
|
||||
rckey[12] = ((state->payload_miP & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 13; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
|
||||
RC4(state->dropL, 13, 7, rckey, cipher, plain);
|
||||
state->dropL += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p < 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -427,11 +701,12 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
|
||||
//EXPERIMENTAL!!
|
||||
//load basic privacy key number from array by the tg value (if not forced)
|
||||
//currently only Moto BP and Hytera 10 Char BP (converted to decimal)
|
||||
if (state->M == 0)
|
||||
//currently only Moto BP and Hytera 10 Char BP
|
||||
if (state->M == 0 && state->payload_algidR == 0)
|
||||
{
|
||||
//see if we need to hash a value larger than 16-bits
|
||||
hash = state->lasttgR & 0xFFFFFF;
|
||||
// fprintf (stderr, "TG: %lld Hash: %ld ", state->lasttgR, hash);
|
||||
if (hash > 0xFFFF) //if greater than 16-bits
|
||||
{
|
||||
for (int i = 0; i < 24; i++)
|
||||
@@ -440,12 +715,14 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
hash = ComputeCrcCCITT16d (hash_bits, 24);
|
||||
hash = hash & 0xFFFF; //make sure its no larger than 16-bits
|
||||
// fprintf (stderr, "Hash: %d ", hash);
|
||||
}
|
||||
if (state->rkey_array[hash] != 0)
|
||||
{
|
||||
state->K = state->rkey_array[hash] & 0xFF; //doesn't exceed 255
|
||||
state->K1 = state->H = state->rkey_array[hash] & 0xFFFFFFFFFF; //doesn't exceed 40-bit limit
|
||||
opts->dmr_mute_encR = 0;
|
||||
// fprintf (stderr, "Key: %X ", state->rkey_array[hash]);
|
||||
}
|
||||
// else opts->dmr_mute_encR = 1; //may cause issues for manual key entry (non-csv)
|
||||
}
|
||||
@@ -525,6 +802,155 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
state->DMRvcR++;
|
||||
}
|
||||
|
||||
//DMR RC4, Slot 2
|
||||
if (state->currentslot == 1 && state->payload_algidR == 0x21 && state->RR != 0)
|
||||
{
|
||||
uint8_t cipher[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
|
||||
0x00, 0x00, 0x00, 0x00}; // <- MI
|
||||
|
||||
//easier to manually load up rather than make a loop
|
||||
rckey[0] = ((state->RR & 0xFF00000000) >> 32);
|
||||
rckey[1] = ((state->RR & 0xFF000000) >> 24);
|
||||
rckey[2] = ((state->RR & 0xFF0000) >> 16);
|
||||
rckey[3] = ((state->RR & 0xFF00) >> 8);
|
||||
rckey[4] = ((state->RR & 0xFF) >> 0);
|
||||
rckey[5] = ((state->payload_miR & 0xFF000000) >> 24);
|
||||
rckey[6] = ((state->payload_miR & 0xFF0000) >> 16);
|
||||
rckey[7] = ((state->payload_miR & 0xFF00) >> 8);
|
||||
rckey[8] = ((state->payload_miR & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 9; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
|
||||
RC4(state->dropR, 9, 7, rckey, cipher, plain);
|
||||
state->dropR += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p < 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//P25p2 RC4 Handling, VCH 1
|
||||
if (state->currentslot == 1 && state->payload_algidR == 0xAA && state->RR != 0 && ((state->synctype == 35) || (state->synctype == 36)))
|
||||
{
|
||||
uint8_t cipher[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
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, // <- MI
|
||||
0x00, 0x00, 0x00}; // <- MI cont.
|
||||
|
||||
//easier to manually load up rather than make a loop
|
||||
rckey[0] = ((state->RR & 0xFF00000000) >> 32);
|
||||
rckey[1] = ((state->RR & 0xFF000000) >> 24);
|
||||
rckey[2] = ((state->RR & 0xFF0000) >> 16);
|
||||
rckey[3] = ((state->RR & 0xFF00) >> 8);
|
||||
rckey[4] = ((state->RR & 0xFF) >> 0);
|
||||
|
||||
//state->payload_miN for VCH1/slot 2
|
||||
rckey[5] = ((state->payload_miN & 0xFF00000000000000) >> 56);
|
||||
rckey[6] = ((state->payload_miN & 0xFF000000000000) >> 48);
|
||||
rckey[7] = ((state->payload_miN & 0xFF0000000000) >> 40);
|
||||
rckey[8] = ((state->payload_miN & 0xFF00000000) >> 32);
|
||||
rckey[9] = ((state->payload_miN & 0xFF000000) >> 24);
|
||||
rckey[10] = ((state->payload_miN & 0xFF0000) >> 16);
|
||||
rckey[11] = ((state->payload_miN & 0xFF00) >> 8);
|
||||
rckey[12] = ((state->payload_miN & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 13; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
|
||||
RC4(state->dropR, 13, 7, rckey, cipher, plain);
|
||||
state->dropR += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p < 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -579,7 +1005,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
else state->dmr_encL = 0;
|
||||
|
||||
//second checkdown for P25-2 WACN, SYSID, and CC set
|
||||
//check for available R key
|
||||
if (state->R != 0) state->dmr_encL = 0;
|
||||
|
||||
//second checkdown for P25p2 WACN, SYSID, and CC set
|
||||
if (state->synctype == 35 || state->synctype == 36)
|
||||
{
|
||||
if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0)
|
||||
@@ -606,13 +1035,16 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
//end reverse mute test
|
||||
|
||||
#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)
|
||||
if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstR == 16 || state->dmrburstR == 21) )
|
||||
{
|
||||
opts->audio_out = 0;
|
||||
preempt = 1;
|
||||
if (opts->payload == 0) fprintf (stderr, " *MUTED*");
|
||||
if (opts->payload == 0)
|
||||
fprintf (stderr, " *MUTED*");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
||||
{
|
||||
@@ -643,7 +1075,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
else state->dmr_encR = 0;
|
||||
|
||||
//second checkdown for P25-2 WACN, SYSID, and CC set
|
||||
//check for available RR key
|
||||
if (state->RR != 0) state->dmr_encR = 0;
|
||||
|
||||
//second checkdown for P25p2 WACN, SYSID, and CC set
|
||||
if (state->synctype == 35 || state->synctype == 36)
|
||||
{
|
||||
if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0)
|
||||
@@ -670,13 +1105,16 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
//end reverse mute test
|
||||
|
||||
#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)
|
||||
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && (state->dmrburstL == 16 || state->dmrburstL == 21) )
|
||||
{
|
||||
opts->audio_out = 0;
|
||||
preempt = 1;
|
||||
if (opts->payload == 0) fprintf (stderr, " *MUTED*");
|
||||
if (opts->payload == 0)
|
||||
fprintf (stderr, " *MUTED*");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
164
src/dsd_reset.c
164
src/dsd_reset.c
@@ -2,26 +2,59 @@
|
||||
#include "dsd.h"
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
void
|
||||
resetState (dsd_state * state)
|
||||
//fixed the memory leak, but now random segfaults occur -- double free or corruption (out) or (!prev)
|
||||
void resetState (dsd_state * state)
|
||||
{
|
||||
|
||||
int i, j;
|
||||
|
||||
//Dibit Buffer -- Free Allocated Memory
|
||||
// free (state->dibit_buf);
|
||||
|
||||
//Dibit Buffer -- Memset/Init/Allocate Memory
|
||||
// state->dibit_buf = malloc (sizeof (int) * 1000000);
|
||||
// state->dibit_buf_p = state->dibit_buf + 200;
|
||||
// memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
state->repeat = 0; //not sure yet
|
||||
//state->audio_out_buf = malloc (sizeof (short) * 1000000);
|
||||
//memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||
//state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
//state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
|
||||
//memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||
//state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
//state->audio_out_idx = 0;
|
||||
//state->audio_out_idx2 = 0;
|
||||
//state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
//state->wav_out_bytes = 0;
|
||||
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
state->repeat = 0; //repeat frame?
|
||||
|
||||
//Audio Buffer -- Free Allocated Memory
|
||||
free (state->audio_out_buf);
|
||||
free (state->audio_out_float_buf);
|
||||
free (state->audio_out_bufR);
|
||||
free (state->audio_out_float_bufR);
|
||||
|
||||
//Audio Buffer -- Memset/Init/Allocate Memory per slot
|
||||
|
||||
//slot 1
|
||||
state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
|
||||
state->audio_out_buf = malloc (sizeof (short) * 1000000);
|
||||
|
||||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
|
||||
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
|
||||
state->audio_out_idx = 0;
|
||||
state->audio_out_idx2 = 0;
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
|
||||
//slot 2
|
||||
state->audio_out_bufR = malloc (sizeof (short) * 1000000);
|
||||
state->audio_out_float_bufR = malloc (sizeof (float) * 1000000);
|
||||
|
||||
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||||
|
||||
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||
|
||||
state->audio_out_idxR = 0;
|
||||
state->audio_out_idx2R = 0;
|
||||
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
|
||||
|
||||
//Sync
|
||||
state->center = 0;
|
||||
state->jitter = -1;
|
||||
state->synctype = -1;
|
||||
@@ -31,76 +64,73 @@ resetState (dsd_state * state)
|
||||
state->umid = 0;
|
||||
state->minref = -12000;
|
||||
state->maxref = 12000;
|
||||
|
||||
state->lastsample = 0;
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
state->sbuf[i] = 0;
|
||||
}
|
||||
{
|
||||
state->sbuf[i] = 0;
|
||||
}
|
||||
state->sidx = 0;
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
state->maxbuf[i] = 15000;
|
||||
}
|
||||
{
|
||||
state->maxbuf[i] = 15000;
|
||||
}
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
state->minbuf[i] = -15000;
|
||||
}
|
||||
{
|
||||
state->minbuf[i] = -15000;
|
||||
}
|
||||
|
||||
state->midx = 0;
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
sprintf (state->ftype, " ");
|
||||
state->symbolcnt = 0;
|
||||
state->rf_mod = 0;
|
||||
|
||||
state->numflips = 0;
|
||||
state->lastsynctype = -1;
|
||||
state->lastp25type = 0;
|
||||
state->offset = 0;
|
||||
state->carrier = 0;
|
||||
for (i = 0; i < 25; i++)
|
||||
{
|
||||
for (j = 0; j < 16; j++)
|
||||
{
|
||||
state->tg[i][j] = 48;
|
||||
}
|
||||
}
|
||||
state->tgcount = 0;
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->nac = 0;
|
||||
|
||||
//Reset Voice Errors in C0 and C1 (or remaining Codewords in IMBE)
|
||||
state->errs = 0;
|
||||
state->errs2 = 0;
|
||||
state->mbe_file_type = -1;
|
||||
state->errsR = 0;
|
||||
state->errs2R = 0;
|
||||
|
||||
//Misc -- may not be needed
|
||||
state->optind = 0;
|
||||
state->numtdulc = 0;
|
||||
state->firstframe = 0;
|
||||
sprintf (state->slot0light, " slot0 ");
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
state->aout_gain = 25;
|
||||
memset (state->aout_max_buf, 0, sizeof (float) * 200);
|
||||
state->aout_max_buf_p = state->aout_max_buf;
|
||||
state->aout_max_buf_idx = 0;
|
||||
state->samplesPerSymbol = 10;
|
||||
state->symbolCenter = 4;
|
||||
sprintf (state->algid, "________");
|
||||
sprintf (state->keyid, "________________");
|
||||
state->currentslot = 0;
|
||||
state->cur_mp = malloc (sizeof (mbe_parms));
|
||||
state->prev_mp = malloc (sizeof (mbe_parms));
|
||||
state->prev_mp_enhanced = malloc (sizeof (mbe_parms));
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->p25kid = 0;
|
||||
|
||||
state->debug_audio_errors = 0;
|
||||
state->debug_header_errors = 0;
|
||||
state->debug_header_critical_errors = 0;
|
||||
//unsure if these are still used or ever were used,
|
||||
// memset (state->aout_max_buf, 0, sizeof (float) * 200);
|
||||
// state->aout_max_buf_p = state->aout_max_buf;
|
||||
// state->aout_max_buf_idx = 0;
|
||||
|
||||
state->nxdn_last_ran = 0;
|
||||
// state->payload_algid = 0;
|
||||
// state->payload_algidR = 0;
|
||||
state->dmr_encL = 0;
|
||||
state->dmr_encR = 0;
|
||||
// //MBE Specific
|
||||
// //free the memory before allocating it again -- may not use this
|
||||
// free (state->cur_mp);
|
||||
// free (state->prev_mp);
|
||||
// free (state->prev_mp_enhanced);
|
||||
|
||||
//each time you run this, it increses memory use by 4MB, massive memory leak
|
||||
//need to revisit this sometime and look into only resetting only the necesary items to let P25 switch between signals (C4FM or Wide) without needing a restart
|
||||
initialize_p25_heuristics(&state->p25_heuristics); //see if we want to re-init this or not, currently seems to cause memory leak when running over and over, mitigated with a reset flag
|
||||
// //memory allocation and init on mbe -- may not use this
|
||||
// state->cur_mp = malloc (sizeof (mbe_parms));
|
||||
// state->prev_mp = malloc (sizeof (mbe_parms));
|
||||
// state->prev_mp_enhanced = malloc (sizeof (mbe_parms));
|
||||
// mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
|
||||
//rest the heurestics, we want to do this on each tune, each RF frequency can deviate quite a bit in strength
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||||
}
|
||||
|
||||
//simple function to reset the dibit buffer
|
||||
void reset_dibit_buffer(dsd_state * state)
|
||||
{
|
||||
//Dibit Buffer -- Free Allocated Memory
|
||||
// free (state->dibit_buf);
|
||||
|
||||
//Dibit Buffer -- Memset/Init/Allocate Memory
|
||||
// state->dibit_buf = malloc (sizeof (int) * 1000000);
|
||||
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
}
|
||||
|
||||
@@ -250,6 +250,7 @@ int UDPBind (char *hostname, int portno)
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
//going to leave this function available, even if completely switched over to rtl_dev_tune now, may be useful in the future
|
||||
void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
||||
{
|
||||
int handle;
|
||||
@@ -274,8 +275,5 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
||||
address.sin_port = htons(udp_port);
|
||||
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
||||
|
||||
//BUGFIX: This was causing an indefinite number of UDP sockets to stay open on each tune request
|
||||
//we open a new socket with each request, so we need to close the socket after writing to it
|
||||
//this would cause the tuning to stop after x number of tune attempts (few hours? on a busy system)
|
||||
close (handle); //close socket after sending.
|
||||
}
|
||||
135
src/dsd_symbol.c
135
src/dsd_symbol.c
@@ -119,7 +119,11 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else cleanupAndExit(opts, state);
|
||||
else
|
||||
{
|
||||
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
|
||||
cleanupAndExit(opts, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -133,28 +137,135 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here?
|
||||
pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL);
|
||||
}
|
||||
opts->rtl_rms = rtl_return_rms();
|
||||
|
||||
#endif
|
||||
}
|
||||
//tcp socket input from SDR++
|
||||
|
||||
//tcp socket input from SDR++ -- now with 1 retry if connection is broken
|
||||
else if (opts->audio_in_type == 8)
|
||||
{
|
||||
#ifdef AERO_BUILD
|
||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
if(result == 0) {
|
||||
fprintf (stderr, "\nConnection to TCP Server Interrupted. Trying again in 3 seconds.\n");
|
||||
sample = 0;
|
||||
sf_close(opts->tcp_file_in); //close current connection on this end
|
||||
sleep (3); //halt all processing and wait 3 seconds
|
||||
|
||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
//attempt to reconnect to socket
|
||||
opts->tcp_sockfd = 0;
|
||||
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
|
||||
if (opts->tcp_sockfd != 0)
|
||||
{
|
||||
//reset audio input stream
|
||||
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->channels=1;
|
||||
opts->audio_in_file_info->seekable=0;
|
||||
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||
|
||||
if(opts->tcp_file_in == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error, couldn't Reconnect to TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||||
}
|
||||
else fprintf (stderr, "TCP Socket Reconnected Successfully.\n");
|
||||
}
|
||||
else fprintf (stderr, "TCP Socket Connection Error.\n");
|
||||
|
||||
//now retry reading sample
|
||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
if (result == 0) {
|
||||
sf_close(opts->tcp_file_in);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else cleanupAndExit(opts, state);
|
||||
opts->tcp_sockfd = 0; //added this line so we will know if it connected when using ncurses terminal keyboard shortcut
|
||||
//openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //zero sample on bad result, keep the ball rolling
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
fprintf (stderr, "Opening Pulse Audio Input.\n");
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
fprintf (stderr, "Closing DSD-FME.\n");
|
||||
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
|
||||
cleanupAndExit(opts, state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
if(result == 0) {
|
||||
fprintf (stderr, "\nConnection to TCP Server Interrupted. Trying again in 3 seconds.\n");
|
||||
sample = 0;
|
||||
sf_close(opts->tcp_file_in); //close current connection on this end
|
||||
sleep (3); //halt all processing and wait 3 seconds
|
||||
|
||||
//attempt to reconnect to socket
|
||||
opts->tcp_sockfd = 0;
|
||||
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
|
||||
if (opts->tcp_sockfd != 0)
|
||||
{
|
||||
//reset audio input stream
|
||||
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->channels=1;
|
||||
opts->audio_in_file_info->seekable=0;
|
||||
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||||
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||
|
||||
if(opts->tcp_file_in == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error, couldn't Reconnect to TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||||
}
|
||||
else fprintf (stderr, "TCP Socket Reconnected Successfully.\n");
|
||||
}
|
||||
else fprintf (stderr, "TCP Socket Connection Error.\n");
|
||||
|
||||
//now retry reading sample
|
||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
if (result == 0) {
|
||||
sf_close(opts->tcp_file_in);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
opts->tcp_sockfd = 0; //added this line so we will know if it connected when using ncurses terminal keyboard shortcut
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //zero sample on bad result, keep the ball rolling
|
||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//tcp socket input from SDR++ -- old method to open pulse or quit right away
|
||||
// else if (opts->audio_in_type == 8)
|
||||
// {
|
||||
// result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
// if(result == 0) {
|
||||
|
||||
// fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
// //open pulse input if we are pulse output AND using ncurses terminal
|
||||
// if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
// {
|
||||
// opts->audio_in_type = 0; //set input type
|
||||
// openPulseInput(opts); //open pulse input
|
||||
// }
|
||||
// //else cleanup and exit
|
||||
// else cleanupAndExit(opts, state);
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
//UDP Socket input...not working correct. Reads samples, but no sync
|
||||
// else if (opts->audio_in_type == 6)
|
||||
// {
|
||||
@@ -419,7 +530,11 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else cleanupAndExit(opts, state);
|
||||
else
|
||||
{
|
||||
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
|
||||
cleanupAndExit(opts, state);
|
||||
}
|
||||
}
|
||||
|
||||
//assign symbol/dibit values based on modulation type
|
||||
|
||||
@@ -298,9 +298,11 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->audio_in_type == 3) //rtl dongle
|
||||
{
|
||||
rtl_udp_tune(opts, state, state->trunk_lcn_freq[lcn-1]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
opts->p25_is_tuned = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -428,9 +430,11 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->audio_in_type == 3) //rtl dongle
|
||||
{
|
||||
rtl_udp_tune(opts, state, state->trunk_lcn_freq[lcn-1]);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||
state->edacs_tuned_lcn = lcn;
|
||||
opts->p25_is_tuned = 1;
|
||||
opts->p25_is_tuned = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ static const unsigned int CNXDNConvolution_NUM_OF_STATES = 16U;
|
||||
static const uint32_t CNXDNConvolution_M = 4U;
|
||||
static const unsigned int CNXDNConvolution_K = 5U;
|
||||
|
||||
static uint16_t m_metrics1[16U] = {0};
|
||||
static uint16_t m_metrics2[16U] = {0};
|
||||
static uint64_t m_decisions[300U] = {0};
|
||||
//NOTE:
|
||||
static uint16_t m_metrics1[16U];
|
||||
static uint16_t m_metrics2[16U];
|
||||
static uint64_t m_decisions[300U]; //300
|
||||
static uint16_t * m_oldMetrics = NULL;
|
||||
static uint16_t * m_newMetrics = NULL;
|
||||
static uint64_t * m_dp = NULL;
|
||||
|
||||
|
||||
/* Functions ----------------------------------------------------------------*/
|
||||
|
||||
void CNXDNConvolution_decode(uint8_t s0, uint8_t s1)
|
||||
@@ -158,13 +158,15 @@ void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsign
|
||||
|
||||
void CNXDNConvolution_start(void)
|
||||
{
|
||||
memset(m_metrics1, 0x00U, CNXDNConvolution_NUM_OF_STATES * sizeof(uint16_t));
|
||||
memset(m_metrics2, 0x00U, CNXDNConvolution_NUM_OF_STATES * sizeof(uint16_t));
|
||||
|
||||
m_oldMetrics = m_metrics1;
|
||||
m_newMetrics = m_metrics2;
|
||||
m_dp = m_decisions;
|
||||
|
||||
memset(m_metrics1, 0x00U, sizeof(m_metrics1));
|
||||
memset(m_metrics2, 0x00U, sizeof(m_metrics2));
|
||||
memset(m_decisions, 0x00U, sizeof(m_decisions));
|
||||
|
||||
for (int x = 0; x < 4; x++) CNXDNConvolution_decode(0U, 0U);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,13 +52,15 @@ void nxdn_descramble(uint8_t dibits[], int len)
|
||||
|
||||
void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
{
|
||||
uint8_t deperm[144];
|
||||
uint8_t depunc[192];
|
||||
uint8_t trellis_buf[96];
|
||||
uint8_t deperm[200]; //144
|
||||
uint8_t depunc[200]; //192
|
||||
uint8_t trellis_buf[400]; //96
|
||||
uint16_t crc = 0; //crc calculated by function
|
||||
uint16_t check = 0; //crc from payload for comparison
|
||||
int out;
|
||||
char buf[128];
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
|
||||
for (int i=0; i<144; i++)
|
||||
deperm[PERM_16_9[i]] = bits[i];
|
||||
@@ -74,7 +76,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
uint8_t temp[210];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[13];
|
||||
uint8_t m_data[20]; //13
|
||||
memset (temp, 0, sizeof(temp));
|
||||
memset (m_data, 0, sizeof(m_data));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
@@ -125,29 +127,33 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " FACCH Payload ");
|
||||
fprintf (stderr, " FACCH1 Payload ");
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
fprintf (stderr, " - %03X %03X", check, crc);
|
||||
if (crc != check && opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//new sacch
|
||||
//sacch
|
||||
void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
{
|
||||
//see about initializing these variables
|
||||
uint8_t deperm[60];
|
||||
uint8_t depunc[72];
|
||||
uint8_t trellis_buf[32];
|
||||
uint8_t answer[26];
|
||||
uint8_t deperm[200]; //60
|
||||
uint8_t depunc[200]; //72
|
||||
uint8_t trellis_buf[400]; //32
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (answer, 0, sizeof(answer));
|
||||
|
||||
int o = 0;
|
||||
uint8_t crc = 0; //value computed by crc6 on payload
|
||||
uint8_t check = 0; //value pulled from last 6 bits
|
||||
@@ -176,7 +182,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
uint8_t temp[90];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[5];
|
||||
uint8_t m_data[10]; //5
|
||||
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
@@ -229,15 +235,27 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
uint8_t nsf_sacch[26];
|
||||
uint8_t nsf_sacch[400];
|
||||
memset (nsf_sacch, 0, sizeof(nsf_sacch));
|
||||
for (int i = 0; i < 26; i++)
|
||||
{
|
||||
nsf_sacch[i] = trellis_buf[i+8];
|
||||
}
|
||||
|
||||
if (crc == check)
|
||||
{
|
||||
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
|
||||
state->nxdn_last_ran = ran;
|
||||
}
|
||||
|
||||
fprintf (stderr, "PF 1/1");
|
||||
|
||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
|
||||
|
||||
//I'm placing this here, my observation is that SACCH NSF
|
||||
//is almost always, if not always, just IDLE
|
||||
else fprintf (stderr, " IDLE");
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -246,8 +264,20 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", check, crc);
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//reset the sacch field -- Github Issue #118
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
|
||||
}
|
||||
|
||||
@@ -257,7 +287,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
//sf and ran together are denoted as SR in the manual (more confusing acronyms)
|
||||
//sf (structure field) and RAN will always exist in first 8 bits of each SACCH, then the next 18 bits are the fragment of the superframe
|
||||
sf = (trellis_buf[0] << 1) | trellis_buf[1];
|
||||
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
|
||||
|
||||
if (sf == 3) part_of_frame = 0;
|
||||
else if (sf == 2) part_of_frame = 1;
|
||||
else if (sf == 1) part_of_frame = 2;
|
||||
@@ -268,12 +298,22 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
|
||||
else fprintf (stderr, " ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
fprintf (stderr, "PF %d/4", part_of_frame+1);
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//reset scrambler seed to key value on new superframe
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
||||
|
||||
if (crc == check)
|
||||
{
|
||||
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
|
||||
state->nxdn_ran = state->nxdn_last_ran = ran;
|
||||
state->nxdn_sf = sf;
|
||||
state->nxdn_part_of_frame = part_of_frame;
|
||||
@@ -296,30 +336,33 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
NXDN_SACCH_Full_decode (opts, state);
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
|
||||
}
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
|
||||
// for (int i = 0; i < 4; i++)
|
||||
// {
|
||||
// fprintf (stderr, "[%02X]", m_data[i]);
|
||||
// }
|
||||
// // if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348])
|
||||
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type)
|
||||
{
|
||||
|
||||
uint8_t deperm[348];
|
||||
uint8_t depunc[406];
|
||||
uint8_t trellis_buf[199];
|
||||
uint8_t deperm[500]; //348
|
||||
uint8_t depunc[500]; //406
|
||||
uint8_t trellis_buf[400]; //199
|
||||
int id = 0;
|
||||
uint16_t crc = 0;
|
||||
uint16_t check = 0;
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
|
||||
for (int i=0; i<348; i++) {
|
||||
deperm[PERM_12_29[i]] = bits[i];
|
||||
}
|
||||
@@ -341,10 +384,10 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[220];
|
||||
uint8_t temp[500]; //220, this one was way too small
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[26];
|
||||
uint8_t m_data[52]; //26
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
@@ -390,7 +433,12 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
check = check | trellis_buf[i+184];
|
||||
}
|
||||
|
||||
uint8_t f2u_message_buffer[199];
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (type == 0) fprintf (stderr, " UDCH");
|
||||
if (type == 1) fprintf (stderr, " FACCH2");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
uint8_t f2u_message_buffer[400]; //199
|
||||
memset (f2u_message_buffer, 0, sizeof(f2u_message_buffer));
|
||||
|
||||
//just going to leave this all here in case its needed, like in cac,
|
||||
@@ -401,36 +449,65 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
}
|
||||
|
||||
if (crc == check)
|
||||
{
|
||||
fprintf (stderr, " F2/U ");
|
||||
//NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
||||
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)
|
||||
}
|
||||
else if (opts->aggressive_framesync == 0)
|
||||
{
|
||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " F2/U Payload\n ");
|
||||
if (type == 0) fprintf (stderr, " UDCH");
|
||||
if (type == 1) fprintf (stderr, " FACCH2");
|
||||
fprintf (stderr, " Payload\n ");
|
||||
for (int i = 0; i < 26; i++)
|
||||
{
|
||||
if (i == 13) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
if (i == 12) fprintf (stderr, "\n ");
|
||||
}
|
||||
if (crc != check) fprintf (stderr, " CRC ERR ");
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
// if (crc != check) fprintf (stderr, " CRC ERR ");
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
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, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
{
|
||||
|
||||
uint8_t deperm[300];
|
||||
uint8_t depunc[350];
|
||||
uint8_t trellis_buf[171];
|
||||
uint8_t deperm[500]; //300
|
||||
uint8_t depunc[500]; //350
|
||||
uint8_t trellis_buf[400]; //171
|
||||
int id = 0;
|
||||
int ran = 0;
|
||||
uint16_t crc = 0;
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
|
||||
for (int i=0; i<300; i++) {
|
||||
deperm[PERM_12_25[i]] = bits[i];
|
||||
}
|
||||
@@ -455,7 +532,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
uint8_t temp[360];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[26];
|
||||
uint8_t m_data[52]; //26
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
@@ -490,7 +567,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
|
||||
crc = crc16cac(trellis_buf, 171);
|
||||
|
||||
uint8_t cac_message_buffer[171];
|
||||
uint8_t cac_message_buffer[400]; //171
|
||||
memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
|
||||
|
||||
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field
|
||||
@@ -499,11 +576,27 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
cac_message_buffer[i] = trellis_buf[i+8];
|
||||
}
|
||||
|
||||
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
if (crc == 0)
|
||||
{
|
||||
fprintf (stderr, " CAC ");
|
||||
NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
|
||||
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
|
||||
state->nxdn_last_ran = ran;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " CAC");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
if (crc != 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (opts->payload == 1)
|
||||
@@ -515,32 +608,326 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
if (i == 10) fprintf (stderr, "\n ");
|
||||
}
|
||||
if (crc != 0) fprintf (stderr, " CRC ERR ");
|
||||
// if (crc != 0) fprintf (stderr, " CRC ERR ");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Type-D "IDAS"
|
||||
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " SCCH");
|
||||
|
||||
//see about initializing these variables
|
||||
uint8_t deperm[200]; //60
|
||||
uint8_t depunc[200]; //72
|
||||
uint8_t trellis_buf[400]; //32
|
||||
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
|
||||
int o = 0;
|
||||
uint8_t crc = 0; //value computed by crc7 on payload
|
||||
uint8_t check = 0; //value pulled from last 7 bits
|
||||
int sf = 0;
|
||||
int part_of_frame = 0;
|
||||
|
||||
for (int i=0; i<60; i++)
|
||||
deperm[PERM_12_5[i]] = bits[i];
|
||||
for (int p=0; p<60; p+= 10) {
|
||||
depunc[o++] = deperm[p+0];
|
||||
depunc[o++] = deperm[p+1];
|
||||
depunc[o++] = deperm[p+2];
|
||||
depunc[o++] = deperm[p+3];
|
||||
depunc[o++] = deperm[p+4];
|
||||
depunc[o++] = 0;
|
||||
depunc[o++] = deperm[p+5];
|
||||
depunc[o++] = deperm[p+6];
|
||||
depunc[o++] = deperm[p+7];
|
||||
depunc[o++] = deperm[p+8];
|
||||
depunc[o++] = deperm[p+9];
|
||||
depunc[o++] = 0;
|
||||
}
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[90];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[10]; //5
|
||||
|
||||
memset (temp, 0, sizeof (temp));
|
||||
memset (m_data, 0, sizeof (m_data));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
|
||||
for (int i = 0; i < 72; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
temp[i+72] = 0;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 36U; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 32U);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
|
||||
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
|
||||
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
|
||||
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
|
||||
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
|
||||
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
|
||||
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
|
||||
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
crc = crc7_scch(trellis_buf, 25);
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
check = check << 1;
|
||||
check = check | trellis_buf[i+25];
|
||||
}
|
||||
|
||||
//check the sf early for scrambler reset, if required
|
||||
sf = (trellis_buf[0] << 1) | trellis_buf[1];
|
||||
if (sf == 3) part_of_frame = 0;
|
||||
else if (sf == 2) part_of_frame = 1;
|
||||
else if (sf == 1) part_of_frame = 2;
|
||||
else if (sf == 0) part_of_frame = 3;
|
||||
else part_of_frame = 0;
|
||||
|
||||
//reset scrambler seed to key value on new superframe
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
||||
|
||||
/*
|
||||
4.3.2. Mapping to Functional Channel
|
||||
When Subscriber Unit performs voice communication in RTCH2, SCCH is allocated as
|
||||
described below.
|
||||
|
||||
SCCH has super Frame Structure with 4 frame unit during communication, and has non
|
||||
super Frame Structure with single frame unit at the start time and end time of sending.
|
||||
Allocation of the other channel is not specified particularly.
|
||||
*/
|
||||
|
||||
//English Translation: Superframe when voice, Non Superframe when not voice
|
||||
|
||||
//What I've found is that by not using the superframe structure, and decoding each 'unit'
|
||||
//individually instead, we can get more expedient decoding on elements without having to
|
||||
//sacrifice an entire superframe for one bad CRC, also each element cleanly divides into a
|
||||
//single 'unit' except for enc parms IV, which can be stored seperately if needed
|
||||
|
||||
//NOTE: scch has its own message format, and thus, doesn't go to content element decoding
|
||||
//like everything else does
|
||||
|
||||
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);
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n SCCH Payload ");
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
|
||||
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type)
|
||||
{
|
||||
uint8_t deperm[300]; //144
|
||||
uint8_t depunc[300]; //192
|
||||
uint8_t trellis_buf[600]; //96
|
||||
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached
|
||||
uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
|
||||
uint16_t crc[2]; //crc calculated by function
|
||||
uint16_t check[2]; //crc from payload for comparison
|
||||
int out;
|
||||
|
||||
//switch to the convolutional decoder
|
||||
uint8_t temp[500];
|
||||
uint8_t s0;
|
||||
uint8_t s1;
|
||||
uint8_t m_data[40]; //13
|
||||
memset (temp, 0, sizeof(temp));
|
||||
memset (m_data, 0, sizeof(m_data));
|
||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||
memset (deperm, 0, sizeof(deperm));
|
||||
memset (depunc, 0, sizeof(depunc));
|
||||
memset (crc, 0, sizeof(crc));
|
||||
memset (check, 0, sizeof(check));
|
||||
memset (f3_udch2, 0, sizeof(f3_udch2));
|
||||
memset (f3_udch2_bytes, 0, sizeof(f3_udch2_bytes));
|
||||
|
||||
for (int j=0; j<2; j++)
|
||||
{
|
||||
for (int i=0; i<144; i++)
|
||||
deperm[PERM_16_9[i]] = bits[i+(j*144)];
|
||||
out = 0;
|
||||
for (int i=0; i<144; i+=3) {
|
||||
depunc[out++] = deperm[i+0];
|
||||
depunc[out++] = 0;
|
||||
depunc[out++] = deperm[i+1];
|
||||
depunc[out++] = deperm[i+2];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 192; i++)
|
||||
{
|
||||
temp[i] = depunc[i] << 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
temp[i+192] = 0;
|
||||
}
|
||||
|
||||
CNXDNConvolution_start();
|
||||
for (int i = 0U; i < 100U; i++)
|
||||
{
|
||||
s0 = temp[(2*i)];
|
||||
s1 = temp[(2*i)+1];
|
||||
|
||||
CNXDNConvolution_decode(s0, s1);
|
||||
}
|
||||
|
||||
CNXDNConvolution_chainback(m_data, 96U);
|
||||
|
||||
for(int i = 0; i < 12; i++)
|
||||
{
|
||||
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
|
||||
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
|
||||
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
|
||||
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
|
||||
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
|
||||
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
|
||||
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
|
||||
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
|
||||
}
|
||||
|
||||
crc[j] = crc12f (trellis_buf, 84); //84
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
check[j] = check[j] << 1;
|
||||
check[j] = check[j] | trellis_buf[84+i]; //84
|
||||
|
||||
}
|
||||
//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 < 12; i++) f3_udch2_bytes[i+(j*12)] = m_data[i];
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (type == 0) fprintf (stderr, " UDCH2");
|
||||
if (type == 1) fprintf (stderr, " FACCH3");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
|
||||
if (crc[0] == check[0] && crc[1] == check[1])
|
||||
{
|
||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
else if (opts->aggressive_framesync == 0)
|
||||
{
|
||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
if (type == 0) fprintf (stderr, " UDCH2");
|
||||
if (type == 1) fprintf (stderr, " FACCH3");
|
||||
fprintf (stderr, " Payload \n ");
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
if (i == 12) fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", f3_udch2_bytes[i]);
|
||||
}
|
||||
|
||||
if ( (crc[0] != check[0] || crc[1] != check[1]) && opts->payload == 1)
|
||||
{
|
||||
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// fprintf (stderr, " - %03X %03X", check[0], crc[0]);
|
||||
// fprintf (stderr, " - %03X %03X", check[1], crc[1]);
|
||||
}
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
fprintf (stderr, "\n UDCH2 Data: ASCII - " );
|
||||
for (int i = 0; i < 22; i++) //all but last crc portion
|
||||
{
|
||||
if (i == 12) i = 14; //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, " ");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
|
||||
{
|
||||
|
||||
//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)
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (MessageType == 0x10) fprintf(stderr, " IDLE");
|
||||
else if (MessageType == 0x11) fprintf(stderr, " DISC"); //disconnect
|
||||
else if (MessageType == 0x00) fprintf(stderr, " CALL_RESP");
|
||||
else if (MessageType == 0x01) fprintf(stderr, " VCALL");
|
||||
else if (MessageType == 0x02) fprintf(stderr, " VCALL_REC_REQ");
|
||||
else if (MessageType == 0x03) fprintf(stderr, " VCALL_IV");
|
||||
|
||||
else if (MessageType == 0x07) fprintf(stderr, " TX_REL_EX");
|
||||
else if (MessageType == 0x08) fprintf(stderr, " TX_REL");
|
||||
|
||||
else if (MessageType == 0x04) fprintf(stderr, " VCALL_ASSGN");
|
||||
else if (MessageType == 0x05) fprintf(stderr, " VCALL_ASSGN_DUP");
|
||||
else if (MessageType == 0x06) fprintf(stderr, " CALL_CONN_RESP");
|
||||
else if (MessageType == 0x07) fprintf(stderr, " TX_REL_EX");
|
||||
else if (MessageType == 0x08) fprintf(stderr, " TX_REL");
|
||||
else if (MessageType == 0x09) fprintf(stderr, " DCALL_HEADER");
|
||||
else if (MessageType == 0x0A) fprintf(stderr, " DCALL_REC_REQ");
|
||||
else if (MessageType == 0x0B) fprintf(stderr, " DCALL_UDATA");
|
||||
else if (MessageType == 0x0C) fprintf(stderr, " DCALL_ACK");
|
||||
else if (MessageType == 0x0D) fprintf(stderr, " DCALL_ASSGN_DUP");
|
||||
else if (MessageType == 0x0E) fprintf(stderr, " DCALL_ASSGN");
|
||||
else if (MessageType == 0x11) fprintf(stderr, " DISC");
|
||||
else if (MessageType == 0x17) fprintf(stderr, " DST_ID_INFO");
|
||||
else if (MessageType == 0x18) fprintf(stderr, " SITE_INFO");
|
||||
else if (MessageType == 0x19) fprintf(stderr, " SRV_INFO");
|
||||
else if (MessageType == 0x1C) fprintf(stderr, " FAIL_STAT_INFO");
|
||||
else if (MessageType == 0x19) fprintf(stderr, " SRV_INFO");
|
||||
else if (MessageType == 0x1A) fprintf(stderr, " CCH_INFO");
|
||||
else if (MessageType == 0x1B) fprintf(stderr, " ADJ_SITE_INFO");
|
||||
else if (MessageType == 0x1C) fprintf(stderr, " FAIL_STAT_INFO");
|
||||
else if (MessageType == 0x20) fprintf(stderr, " REG_RESP");
|
||||
else if (MessageType == 0x22) fprintf(stderr, " REG_C_RESP");
|
||||
else if (MessageType == 0x24) fprintf(stderr, " GRP_REG_RESP");
|
||||
@@ -549,23 +936,23 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
|
||||
else if (MessageType == 0x38) fprintf(stderr, " SDCALL_REQ_HEADER");
|
||||
else if (MessageType == 0x39) fprintf(stderr, " SDCALL_REQ_USERDATA");
|
||||
else if (MessageType == 0x3B) fprintf(stderr, " SDCALL_RESP");
|
||||
|
||||
else if (MessageType == 0x3F) fprintf(stderr, " ALIAS");
|
||||
else if (MessageType == 0x0C) fprintf(stderr, " DCALL_ACK");
|
||||
else fprintf(stderr, " Unknown M-%02X", MessageType);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//zero out stale values so they won't persist after a transmit release, idle, or disconnect
|
||||
if (MessageType == 0x08 || MessageType == 0x10 || MessageType == 0x11) //tx_rel, idle, or disc
|
||||
//Zero out stale values on DISC or TX_REL only (IDLE messaages occur often on NXDN96 VCH, and randomly on Type-C FACCH1 steals for some reason)
|
||||
if (MessageType == 0x08 || MessageType == 0x11)
|
||||
{
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
state->nxdn_cipher_type = 0;
|
||||
state->nxdn_cipher_type = 0; //force will reactivate it if needed during voice tx
|
||||
if (state->keyloader == 1) state->R = 0;
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||
sprintf (state->nxdn_call_type, "%s", "");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//voice descrambler
|
||||
@@ -677,4 +1064,23 @@ static uint16_t crc16cac(const uint8_t buf[], int len)
|
||||
}
|
||||
crc = crc ^ 0xffff;
|
||||
return crc & 0xffff;
|
||||
}
|
||||
|
||||
static uint8_t crc7_scch(uint8_t bits[], int len)
|
||||
{
|
||||
uint8_t s[7];
|
||||
uint8_t a;
|
||||
for (int i=0;i<7;i++)
|
||||
s[i] = 1;
|
||||
for (int i=0;i<len;i++) {
|
||||
a = bits[i] ^ s[0];
|
||||
s[0] = s[1];
|
||||
s[1] = s[2];
|
||||
s[2] = s[3];
|
||||
s[3] = a ^ s[4];
|
||||
s[4] = s[5];
|
||||
s[5] = s[6];
|
||||
s[6] = a;
|
||||
}
|
||||
return load_i(s, 7);
|
||||
}
|
||||
1737
src/nxdn_element.c
1737
src/nxdn_element.c
File diff suppressed because it is too large
Load Diff
274
src/nxdn_frame.c
274
src/nxdn_frame.c
@@ -32,28 +32,42 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
// length is implicitly 192, with frame sync in first 10 dibits
|
||||
uint8_t dbuf[182];
|
||||
uint8_t lich;
|
||||
int answer_len=0;
|
||||
int answer_len = 0;
|
||||
uint8_t answer[32];
|
||||
uint8_t sacch_answer[32];
|
||||
int lich_parity_received;
|
||||
int lich_parity_computed;
|
||||
int voice=0;
|
||||
int facch=0;
|
||||
int facch2=0;
|
||||
int sacch=0;
|
||||
int cac=0;
|
||||
int voice = 0;
|
||||
int facch = 0;
|
||||
int facch2 = 0;
|
||||
int udch = 0;
|
||||
int sacch = 0;
|
||||
int cac = 0;
|
||||
int sr_structure;
|
||||
int sr_ran;
|
||||
|
||||
//new, and even more confusing NXDN Type-D / "IDAS" acronyms
|
||||
int idas = 0;
|
||||
int scch = 0;
|
||||
int facch3 = 0;
|
||||
int udch2 = 0;
|
||||
|
||||
//new breakdown of lich codes
|
||||
uint8_t lich_rf = 0; //RF Channel Type
|
||||
uint8_t lich_fc = 0; //Functional Channel Type
|
||||
uint8_t lich_op = 0; //Options
|
||||
uint8_t direction; //inbound or outbound direction
|
||||
|
||||
uint8_t lich_dibits[8];
|
||||
uint8_t sacch_bits[60];
|
||||
uint8_t facch_bits_a[144];
|
||||
uint8_t facch_bits_b[144];
|
||||
uint8_t cac_bits[300];
|
||||
uint8_t facch2_bits[348]; //facch2 or udch, same amount of bits
|
||||
uint8_t facch3_bits[288]; //facch3 or udch2, same amount of bits
|
||||
|
||||
//nxdn bit buffer, for easy assignment handling
|
||||
int nxdn_bit_buffer[364];
|
||||
//nxdn bit buffer, for easy assignment handling
|
||||
int nxdn_bit_buffer[364];
|
||||
int nxdn_dibit_buffer[182];
|
||||
|
||||
//init all arrays
|
||||
@@ -71,7 +85,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
memset (nxdn_dibit_buffer, 0, sizeof(nxdn_dibit_buffer));
|
||||
|
||||
//collect lich bits first, if they are good, then we can collect the rest of them
|
||||
for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state);
|
||||
for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state);
|
||||
|
||||
nxdn_descramble (lich_dibits, 8);
|
||||
|
||||
@@ -82,11 +96,10 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
lich_parity_computed = ((lich >> 7) + (lich >> 6) + (lich >> 5) + (lich >> 4)) & 1;
|
||||
lich = lich >> 1;
|
||||
if (lich_parity_received != lich_parity_computed)
|
||||
{
|
||||
// fprintf(stderr, "NXDN lich parity error, ignoring frame \n"); //debug
|
||||
// state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
|
||||
{
|
||||
if (opts->payload == 1) fprintf(stderr, " Lich Parity Error %02X\n", lich);
|
||||
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
|
||||
goto END;
|
||||
// return;
|
||||
}
|
||||
|
||||
voice = 0;
|
||||
@@ -100,7 +113,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (lich % 2 == 0 && opts->p25_trunk == 1)
|
||||
{
|
||||
if (opts->payload == 1) fprintf(stderr, " Simplex/Inbound NXDN lich on trunking system - type 0x%02X\n", lich);
|
||||
// state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
|
||||
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
|
||||
goto END;
|
||||
}
|
||||
|
||||
@@ -111,21 +124,20 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
break;
|
||||
case 0x28: //facch2 types
|
||||
case 0x29:
|
||||
case 0x2e:
|
||||
case 0x2f:
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
facch2 = 1;
|
||||
break;
|
||||
case 0x2e: //udch types
|
||||
case 0x2f:
|
||||
case 0x4e:
|
||||
case 0x4f:
|
||||
case 0x69:
|
||||
case 0x6f:
|
||||
facch2 = 1;
|
||||
udch = 1;
|
||||
break;
|
||||
case 0x32: //facch in 1, vch in 2
|
||||
case 0x33:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x73:
|
||||
voice = 2;
|
||||
facch = 1;
|
||||
sacch = 1;
|
||||
@@ -133,8 +145,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
case 0x34: //vch in 1, facch in 2
|
||||
case 0x35:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x75:
|
||||
case 0x55: //disabled for testing, IDAS system randomly triggers this one, probably due to poor signal
|
||||
voice = 1;
|
||||
facch = 2;
|
||||
sacch = 1;
|
||||
@@ -143,7 +154,6 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
case 0x37:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x77:
|
||||
voice = 3;
|
||||
facch = 0;
|
||||
sacch = 1;
|
||||
@@ -156,8 +166,6 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
case 0x41:
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x61:
|
||||
case 0x71:
|
||||
voice = 0;
|
||||
facch = 3;
|
||||
sacch = 1;
|
||||
@@ -166,6 +174,59 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
case 0x39:
|
||||
sacch = 1;
|
||||
break;
|
||||
|
||||
//NXDN "Type-D" or "IDAS" Specific Lich Codes
|
||||
case 0x76: //normal vch voice (in one and two)
|
||||
case 0x77:
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
voice = 3;
|
||||
break;
|
||||
case 0x74: //vch in 1, facch1 in 2 (facch 2 steal)
|
||||
case 0x75:
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
voice = 1;
|
||||
facch = 2;
|
||||
break;
|
||||
case 0x72: //facch in 1, vch in 2 (facch 1 steal)
|
||||
case 0x73:
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
voice = 2;
|
||||
facch = 1;
|
||||
break;
|
||||
case 0x70: //facch steal in vch 1 and vch 2 (during voice only)
|
||||
case 0x71:
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
facch = 3;
|
||||
break;
|
||||
case 0x6E: //udch2
|
||||
case 0x6F:
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
udch2 = 1;
|
||||
break;
|
||||
case 0x68:
|
||||
case 0x69: //facch3
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
facch3 = 1;
|
||||
break;
|
||||
case 0x62:
|
||||
case 0x63: //facch1 in 1, null data and post field in 2
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
facch = 1;
|
||||
break;
|
||||
case 0x60:
|
||||
case 0x61: //facch1 in both (non vch)
|
||||
idas = 1;
|
||||
scch = 1;
|
||||
facch = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (opts->payload == 1) fprintf(stderr, " false sync or unsupported NXDN lich type 0x%02X\n", lich);
|
||||
//reset the sacch field, we probably got a false sync and need to wipe or give a bad crc
|
||||
@@ -177,17 +238,29 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
break;
|
||||
} // end of switch(lich)
|
||||
|
||||
//enable these after good lich parity and known lich value
|
||||
state->carrier = 1;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
|
||||
//printframesync after determining we have a good lich and it has something in it
|
||||
if (voice || facch || sacch || facch2 || cac)
|
||||
if (idas)
|
||||
{
|
||||
if (opts->frame_nxdn48 == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "IDAS D ", 0, "-");
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "L%02X - ", lich);
|
||||
}
|
||||
else if (voice || facch || sacch || facch2 || udch || cac)
|
||||
{
|
||||
// if (state->synctype == 28) fprintf (stderr, " +");
|
||||
// else fprintf (stderr, " -");
|
||||
if (opts->frame_nxdn48 == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "NXDN48 ", 0, "-");
|
||||
}
|
||||
else printFrameSync (opts, state, "NXDN96 ", 0, "-");
|
||||
if (opts->payload == 1) fprintf (stderr, "L%02X -", lich);
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "L%02X - ", lich);
|
||||
}
|
||||
|
||||
//now that we have a good LICH, we can collect all of our dibits
|
||||
@@ -206,7 +279,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
nxdn_bit_buffer[i*2+1] = dbuf[i] & 1;
|
||||
}
|
||||
|
||||
//sacch
|
||||
//sacch or scch bits
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
sacch_bits[i] = nxdn_bit_buffer[i+16];
|
||||
@@ -231,22 +304,115 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
facch2_bits[i] = nxdn_bit_buffer[i+16];
|
||||
}
|
||||
|
||||
//udch2 or facch3
|
||||
for (int i = 0; i < 288; i++)
|
||||
{
|
||||
facch3_bits[i] = nxdn_bit_buffer[i+16+60];
|
||||
}
|
||||
|
||||
//vch frames stay inside dbuf, easier to assign that to ambe_fr frames
|
||||
//sacch needs extra handling depending on superframe or non-superframe variety
|
||||
|
||||
//Add advanced decoding of LICH (RF, FC, OPT, and Direction
|
||||
lich_rf = (lich >> 5) & 0x3;
|
||||
lich_fc = (lich >> 3) & 0x3;
|
||||
lich_op = (lich >> 1) & 0x3;
|
||||
if (lich % 2 == 0) direction = 0;
|
||||
else direction = 1;
|
||||
|
||||
// RF Channel Type
|
||||
if (lich_rf == 0) fprintf (stderr, "RCCH ");
|
||||
else if (lich_rf == 1) fprintf (stderr, "RTCH ");
|
||||
else if (lich_rf == 2) fprintf (stderr, "RDCH ");
|
||||
else
|
||||
{
|
||||
if (lich < 0x60) fprintf (stderr, "RTCH_C ");
|
||||
else fprintf (stderr, "RTCH2 ");
|
||||
}
|
||||
|
||||
// Functional Channel Type -- things start to get really convoluted here
|
||||
// These will echo when handled, either with the decoded message type, or relevant crc err
|
||||
// if (lich_rf == 0) //CAC Type
|
||||
// {
|
||||
// //Technically, we should be checking direction as well, but the fc never has split meaning on CAC
|
||||
// if (lich_fc == 0) fprintf (stderr, "CAC ");
|
||||
// else if (lich_fc == 1) fprintf (stderr, "Long CAC ");
|
||||
// else if (lich_fc == 3) fprintf (stderr, "Short CAC ");
|
||||
// else fprintf (stderr, "Reserved ");
|
||||
// }
|
||||
// else //USC Type
|
||||
// {
|
||||
// if (lich_fc == 0) fprintf (stderr, "NSF SACCH ");
|
||||
// else if (lich_fc == 1) fprintf (stderr, "UDCH ");
|
||||
// else if (lich_fc == 2) fprintf (stderr, "SF SACCH ");
|
||||
// else if (lich_fc == 3) fprintf (stderr, "SF SACCH/IDLE ");
|
||||
// }
|
||||
|
||||
#ifdef LIMAZULUTWEAKS
|
||||
|
||||
//LimaZulu specific tweak, load keys from frequency value, if avalable -- test before VCALL
|
||||
//needs to be loaded here, if superframe data pair, then we need to run the LFSR on it as well
|
||||
|
||||
if (voice) //can this run TOO frequently?
|
||||
{
|
||||
long int freq = 0;
|
||||
uint8_t hash_bits[24];
|
||||
memset (hash_bits, 0, sizeof(hash_bits));
|
||||
uint16_t limazulu = 0;
|
||||
|
||||
//if not available, then poll rigctl if its available
|
||||
if (opts->use_rigctl == 1)
|
||||
freq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
|
||||
//if using rtl input, we can ask for the current frequency tuned
|
||||
else if (opts->audio_in_type == 3)
|
||||
freq = (long int)opts->rtlsdr_center_freq;
|
||||
|
||||
// freq = 167831250; //hardset for testing
|
||||
|
||||
//since a frequency value will be larger than the 16-bit max, we need to hash it first
|
||||
//the hash has to be run the same way as the import, so at a 24-bit depth, which hopefully
|
||||
//will not lead to any duplicate key loads due to multiple CRC16 collisions on a larger value?
|
||||
for (int i = 0; i < 24; i++)
|
||||
hash_bits[i] = ((freq << i) & 0x800000) >> 23; //load into array for CRC16
|
||||
|
||||
if (freq) limazulu = ComputeCrcCCITT16d (hash_bits, 24);
|
||||
limazulu = limazulu & 0xFFFF; //make sure no larger than 16-bits
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (freq) fprintf (stderr, "\n Freq: %ld - Freq Hash: %d", freq, limazulu);
|
||||
if (state->rkey_array[limazulu] != 0) fprintf (stderr, " - Key Loaded: %lld", state->rkey_array[limazulu]);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
if (state->rkey_array[limazulu] != 0)
|
||||
state->R = state->rkey_array[limazulu];
|
||||
|
||||
if (state->R != 0 && state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
|
||||
//add additional time to last_sync_time for LimaZulu to hold on current frequency
|
||||
//a little longer without affecting normal scan time on trunk_hangtime variable
|
||||
state->last_cc_sync_time = time(NULL) + 2; //ask him for an ideal wait timer
|
||||
}
|
||||
|
||||
#endif //end LIMAZULUTWEAKS
|
||||
|
||||
if (opts->scanner_mode == 1)
|
||||
state->last_cc_sync_time = time(NULL) + 2; //add a little extra hangtime between resuming scan
|
||||
|
||||
//Option/Steal Flags echoed in Voice, V+F, or Data
|
||||
if (voice && !facch) //voice only, no facch steal
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " Voice ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
else if (voice && facch) //voice with facch steal
|
||||
else if (voice && facch) //voice with facch1 steal
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " V%d+F%d ", 3 - facch, facch); //print which position on each
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
else
|
||||
else //Covers FACCH1 in both, FACCH2, UDCH, UDCH2, CAC
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Data ");
|
||||
@@ -284,43 +450,62 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (lich == 0x20 || lich == 0x21 || lich == 0x61 || lich == 0x40 || lich == 0x41) state->nxdn_sacch_non_superframe = TRUE;
|
||||
else state->nxdn_sacch_non_superframe = FALSE;
|
||||
|
||||
if (sacch) nxdn_deperm_sacch(opts, state, sacch_bits);
|
||||
if (cac) nxdn_deperm_cac(opts, state, cac_bits);
|
||||
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits);
|
||||
//TODO Later: Add Direction and/or LICH to all decoding functions
|
||||
if (scch) nxdn_deperm_scch (opts, state, sacch_bits, direction);
|
||||
|
||||
//testing purposes -- don't run facch steals on enc -- causing issues with key loader (VCALL_ASSGN_DUP)
|
||||
if (state->nxdn_cipher_type == 0 || state->R == 0) //!voice
|
||||
if (udch2) nxdn_deperm_facch3_udch2(opts, state, facch3_bits, 0);
|
||||
if (facch3) nxdn_deperm_facch3_udch2(opts, state, facch3_bits, 1);
|
||||
|
||||
if (sacch) nxdn_deperm_sacch(opts, state, sacch_bits);
|
||||
if (cac) nxdn_deperm_cac(opts, state, cac_bits);
|
||||
|
||||
//Seperated UDCH user data from facch2 data
|
||||
if (udch) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 0);
|
||||
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 1);
|
||||
|
||||
//SHOULD be okay to run facch1's again on steal frames, will need testing
|
||||
// if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
// if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
|
||||
//only run facch in second slot if its not equal to the first one
|
||||
//ideally, this would work better AFTER decoding/FEC
|
||||
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
if (facch & 2)
|
||||
{
|
||||
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
if (memcmp (facch_bits_a, facch_bits_b, 144) != 0)
|
||||
nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
}
|
||||
|
||||
|
||||
if (voice)
|
||||
{
|
||||
//restore MBE file open here
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
//update last voice sync time
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
//turn on scrambler if forced by user option
|
||||
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
|
||||
//process voice frame
|
||||
nxdn_voice (opts, state, voice, dbuf);
|
||||
}
|
||||
|
||||
//close MBE file if no voice and its open
|
||||
if (!voice)
|
||||
{
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
if (opts->frame_nxdn96 == 1) //nxdn96 has voice and data mixed together, so we will need to do a time check first
|
||||
if (opts->frame_nxdn96 == 1) //nxdn96 has pure voice and data frames mixed together, so we will need to do a time check first
|
||||
{
|
||||
if ( (time(NULL) - state->last_vc_sync_time) > 1) //test for optimal time, 1 sec should be okay
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice mixing
|
||||
//may need to reconsider this, due to double FACCH1 steals on some Type-C (ASSGN_DUP, etc) and Conventional Systems (random IDLE FACCH1 steal for no reason)
|
||||
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice frames mixing
|
||||
}
|
||||
}
|
||||
|
||||
if (voice && facch == 2) //facch steal 2 -- after voice
|
||||
if (voice && facch == 2) //facch steal 2 -- after voice 1
|
||||
{
|
||||
//roll the voice scrambler LFSR here if key available to advance seed -- half rotation on a facch steal
|
||||
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
|
||||
@@ -334,7 +519,8 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->payload == 1 && !voice) fprintf (stderr, "\n");
|
||||
else if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
END: ; //do nothing
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* p25_frequency.c
|
||||
* P25 Channel to Frequency Calculator
|
||||
*
|
||||
* NXDN Channel to Frequency, Courtesy of IcomIcR20 and EricCottrell (base values)
|
||||
* NXDN Channel to Frequency Calculator
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-11 DSD-FME Florida Man Edition
|
||||
@@ -59,16 +59,16 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
|
||||
|
||||
}
|
||||
|
||||
//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 freq;
|
||||
long int base = 0;
|
||||
long int step = 0;
|
||||
|
||||
//the base freq value is per EricCottrell in the Understanding NXDN Trunking Forum Thread
|
||||
//will need to do some research or tests to confirm these values are accurate
|
||||
//reworked to include Direct Frequency Assignment if available
|
||||
|
||||
//first, check channel map
|
||||
//first, check channel map for imported value, DFA systems most likely won't need an import,
|
||||
//unless it has 'system definable' attributes
|
||||
if (state->trunk_chan_map[channel] != 0)
|
||||
{
|
||||
freq = state->trunk_chan_map[channel];
|
||||
@@ -76,42 +76,41 @@ long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t
|
||||
return (freq);
|
||||
}
|
||||
|
||||
//then, let's see if its DFA instead -- 6.5.36
|
||||
else if (state->nxdn_rcn == 1)
|
||||
{
|
||||
//determine the base frequency in Hz
|
||||
if (state->nxdn_base_freq == 1) base = 100000000; //100 MHz
|
||||
else if (state->nxdn_base_freq == 2) base = 330000000; //330 Mhz
|
||||
else if (state->nxdn_base_freq == 3) base = 400000000; //400 Mhz
|
||||
else if (state->nxdn_base_freq == 4) base = 750000000; //750 Mhz
|
||||
else base = 0; //just set to zero, will be system definable most likely and won't be able to calc
|
||||
|
||||
//determine the step value in Hz
|
||||
if (state->nxdn_step = 2) step = 1250; //1.25 kHz
|
||||
else if (state->nxdn_step = 3) step = 3125; //3.125 kHz
|
||||
else step = 0; //just set to zero, will be system definable most likely and won't be able to calc
|
||||
|
||||
//if we have a valid base and step, then calc frequency
|
||||
//6.5.45. Outbound/Inbound Frequency Number (OFN/IFN)
|
||||
if (base && step)
|
||||
{
|
||||
freq = base + (channel * step);
|
||||
fprintf (stderr, "\n DFA Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
return (freq);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\n Custom DFA Settings -- Unknown Freq;");
|
||||
return (0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\n Channel not found in import file");
|
||||
return (0);
|
||||
}
|
||||
|
||||
//if not found, attempt to find it via calculation
|
||||
//disabled, frequency 'band plan' isn't standard
|
||||
//like originally believed
|
||||
|
||||
// else
|
||||
// {
|
||||
// if ((channel > 0) && (channel <= 400))
|
||||
// {
|
||||
// if (opts->frame_nxdn48 == 1) base = 450000000;
|
||||
// else base = 451000000;
|
||||
|
||||
// freq = base + (channel - 1) * 12500;
|
||||
// fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
// return (freq);
|
||||
// }
|
||||
// else if ((channel >= 401) && (channel <= 800))
|
||||
// {
|
||||
// if (opts->frame_nxdn48 == 1) base = 460000000;
|
||||
// else base = 461000000;
|
||||
|
||||
// freq = base + (channel - 401) * 12500;
|
||||
// fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
// return (freq);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// fprintf(stderr, "\n Non-standard frequency or channel not found in import file");
|
||||
// return (0);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* p25_lcw.c
|
||||
* P25p1 Link Control Word Decoding
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2023-05 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//new p25_lcw function here -- TIA-102.AABF-D LCW Format Messages (if anybody wants to fill the rest out)
|
||||
@@ -93,13 +101,15 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
if (channel1 && group1)
|
||||
{
|
||||
fprintf (stderr, "Ch: %04X TG: %d; ", channel1, group1);
|
||||
sprintf (state->dmr_lrrp_gps[0], "Active Ch: %04X TG: %d;", channel1, group1);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; ", channel1, group1);
|
||||
state->last_active_time = time(NULL);
|
||||
}
|
||||
|
||||
if (channel2 && group2 && group1 != group2)
|
||||
{
|
||||
fprintf (stderr, "Ch: %04X TG: %d; ", channel2, group2);
|
||||
sprintf (state->dmr_lrrp_gps[1], "Active Ch: %04X TG: %d;", channel2, group2);
|
||||
sprintf (state->active_channel[1], "Active Ch: %04X TG: %d; ", channel2, group2);
|
||||
state->last_active_time = time(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -285,9 +295,20 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
//tune back to CC here - save about 1-2 seconds
|
||||
else if (lc_format == 0x4F) //# Call Termination/Cancellation
|
||||
{
|
||||
fprintf (stderr, " Call Termination/Cancellation");
|
||||
fprintf (stderr, " Call Termination");
|
||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
||||
{
|
||||
|
||||
//Will we need to check for a symbolrate change here, can a P25p2 TDMA-CC system
|
||||
//revert back to a phase 1 traffic channel or carry a phase 1 traffic channel?
|
||||
|
||||
//clear heuristics from current traffic channel
|
||||
if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1)
|
||||
{
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
initialize_p25_heuristics(&state->inv_p25_heuristics);
|
||||
}
|
||||
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
@@ -299,16 +320,17 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
//reset some strings
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
sprintf (state->dmr_lrrp_gps[0], "%s", ""); //this is used for active ch in p25 trunking
|
||||
sprintf (state->dmr_lrrp_gps[1], "%s", ""); //this is used for active ch in p25 trunking
|
||||
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_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->payload_algid = 0;
|
||||
@@ -317,11 +339,12 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
//reset some strings
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
sprintf (state->dmr_lrrp_gps[0], "%s", ""); //this is used for active ch in p25 trunking
|
||||
sprintf (state->dmr_lrrp_gps[1], "%s", ""); //this is used for active ch in p25 trunking
|
||||
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_udp_tune (opts, state, state->p25_cc_freq);
|
||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,6 +459,9 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
|
||||
//reset dropbytes - skip first 11 for LCW
|
||||
state->dropL = 267;
|
||||
|
||||
//set vc counter to 0
|
||||
state->p25vc = 0;
|
||||
|
||||
@@ -466,14 +469,19 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
||||
{
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
if (state->R != 0 && state->payload_algid == 0xAA)
|
||||
{
|
||||
fprintf (stderr, " Key: %010llX", state->R);
|
||||
opts->unmute_encrypted_p25 = 1;
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC");
|
||||
|
||||
@@ -171,6 +171,8 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
|
||||
// TODO: error correction of the LSD bytes...
|
||||
// TODO: do something useful with the LSD bytes...
|
||||
|
||||
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
||||
}
|
||||
|
||||
// IMBE 9
|
||||
|
||||
@@ -172,6 +172,8 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
// TODO: error correction of the LSD bytes...
|
||||
// TODO: do something useful with the LSD bytes...
|
||||
|
||||
state->dropL += 2; //need to skip 2 here for the LSD bytes
|
||||
}
|
||||
|
||||
// IMBE 9
|
||||
@@ -183,6 +185,9 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
//set vc counter to 0
|
||||
state->p25vc = 0;
|
||||
|
||||
//reset dropbytes -- skip first 11 for next LCW
|
||||
state->dropL = 267;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
@@ -366,15 +371,19 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
if (irrecoverable_errors == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
if (state->R != 0 && state->payload_algid == 0xAA)
|
||||
{
|
||||
fprintf (stderr, " Key: %010llX", state->R);
|
||||
opts->unmute_encrypted_p25 = 1;
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
|
||||
state->payload_miP = (mihex1 << 32) | (mihex2);
|
||||
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
|
||||
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " ENC");
|
||||
@@ -390,4 +399,45 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//run LFSR on the MI if we have irrecoverable errors here
|
||||
if (irrecoverable_errors && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
|
||||
{
|
||||
LFSRP(state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
void LFSRP(dsd_state * state)
|
||||
{
|
||||
//rework for P2 TDMA support
|
||||
unsigned long long int lfsr = 0;
|
||||
if (state->currentslot == 0)
|
||||
lfsr = state->payload_miP;
|
||||
|
||||
if (state->currentslot == 1)
|
||||
lfsr = state->payload_miN;
|
||||
|
||||
int cnt = 0;
|
||||
for(cnt=0;cnt<64;cnt++)
|
||||
{
|
||||
// Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
|
||||
unsigned long long int bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1;
|
||||
lfsr = (lfsr << 1) | (bit);
|
||||
}
|
||||
|
||||
if (state->currentslot == 0)
|
||||
state->payload_miP = lfsr;
|
||||
|
||||
if (state->currentslot == 1)
|
||||
state->payload_miN = lfsr;
|
||||
|
||||
//print current ENC identifiers already known and new calculated MI
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (state->currentslot == 0)
|
||||
fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algid, state->payload_keyid, state->payload_miP);
|
||||
if (state->currentslot == 1)
|
||||
fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algidR, state->payload_keyidR, state->payload_miN);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
110
src/p25p1_mdpu.c
110
src/p25p1_mdpu.c
@@ -24,6 +24,16 @@ static uint32_t crc32mbf(uint8_t buf[], int len)
|
||||
|
||||
void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
//reset some strings when returning from a call in case they didn't get zipped already
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
|
||||
//clear stale Active Channel messages here
|
||||
if ( (time(NULL) - state->last_active_time) > 3 )
|
||||
{
|
||||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||
}
|
||||
|
||||
int tsbkbit[196]; //tsbk bit array, 196 trellis encoded bits
|
||||
int tsbk_dibit[98];
|
||||
@@ -276,21 +286,33 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//Group Voice Channel Grant - Extended
|
||||
else if (opcode == 0x0)
|
||||
{
|
||||
int svc = mpdu_byte[8]; //look up what these do!
|
||||
int svc = mpdu_byte[8];
|
||||
int channelt = (mpdu_byte[14] << 8) | mpdu_byte[15];
|
||||
int channelr = (mpdu_byte[16] << 8) | mpdu_byte[17];
|
||||
long int source = (mpdu_byte[3] << 16) |(mpdu_byte[4] << 8) | mpdu_byte[5];
|
||||
int group = (mpdu_byte[18] << 8) | mpdu_byte[19];
|
||||
long int freq1 = 0;
|
||||
long int freq2 = 0;
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
fprintf (stderr, "\n Group Voice Channel Grant Update - Extended");
|
||||
fprintf (stderr, "%s\n ",KYEL);
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
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, " Group Voice Channel Grant Update - Extended");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc, channelt, channelr, group, group);
|
||||
freq1 = process_channel_to_freq (opts, state, channelt);
|
||||
freq2 = process_channel_to_freq (opts, state, channelr);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[0], "Active Ch: %04X TG: %d", channelt, group);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d ", channelt, group);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
@@ -305,6 +327,9 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//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))
|
||||
{
|
||||
@@ -312,14 +337,24 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channelt >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
@@ -328,13 +363,17 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
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_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +383,7 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
else if (opcode == 0x6)
|
||||
{
|
||||
//I'm not doing EVERY element of this, just enough for tuning!
|
||||
int svc = mpdu_byte[8]; //look up what these do!
|
||||
int svc = mpdu_byte[8];
|
||||
int channelt = (mpdu_byte[22] << 8) | mpdu_byte[23];
|
||||
int channelr = (mpdu_byte[24] << 8) | mpdu_byte[25]; //optional!
|
||||
//using source and target address, not source and target id (is this correct?)
|
||||
@@ -352,14 +391,25 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
long int target = (mpdu_byte[19] << 16) |(mpdu_byte[20] << 8) | mpdu_byte[21];
|
||||
long int freq1 = 0;
|
||||
long int freq2 = 0;
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
fprintf (stderr, "\n Unit to Unit Voice Channel Grant Update - Extended");
|
||||
fprintf (stderr, "%s\n ",KYEL);
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
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, " Unit to Unit Voice Channel Grant Update - Extended");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Source [%ld][%04lX] Target [%ld][%04lX]", svc, channelt, channelr, source, source, target, target);
|
||||
freq1 = process_channel_to_freq (opts, state, channelt);
|
||||
freq2 = process_channel_to_freq (opts, state, channelr); //optional!
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[0], "Active Ch: %04X TGT: %ld;", channelt, target);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TGT: %ld; ", channelt, target);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
@@ -374,21 +424,35 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//Skip tuning private calls if group calls are disabled
|
||||
if (opts->trunk_tune_private_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
|
||||
{
|
||||
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
if (opts->mod_qpsk == 1)
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
if (state->p25_chan_tdma[channelt >> 12] == 1)
|
||||
{
|
||||
state->samplesPerSymbol = 8;
|
||||
state->symbolCenter = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
@@ -396,14 +460,18 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
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
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
|
||||
void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
//reset some strings when returning from a call in case they didn't get zipped already
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
|
||||
//clear stale Active Channel messages here
|
||||
if ( (time(NULL) - state->last_active_time) > 3 )
|
||||
{
|
||||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||
}
|
||||
|
||||
int tsbkbit[196]; //tsbk bit array, 196 trellis encoded bits
|
||||
int tsbk_dibit[98];
|
||||
@@ -38,11 +48,7 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
int protectbit = 0;
|
||||
int MFID = 0xFF; //Manufacturer ID - Might be beneficial to NOT send anything but standard 0x00 or 0x01 messages
|
||||
|
||||
//Update: Identified Bug in skipdibit incrememnt causing many block deinterleave/crc failures
|
||||
//with correct values set, now we are decoding many more TSBKs
|
||||
//TODO: Don't Print TSBKs/vPDUs unless verbosity levels set higher
|
||||
//TSBKs are always single block, but up to three can be transmitted in a row,
|
||||
//Multi-Block PDUs are sent on a different DUID - 0xC (not handled currently)
|
||||
|
||||
//collect three reps of 101 dibits (98 valid dibits with status dibits interlaced)
|
||||
for (j = 0; j < 3; j++)
|
||||
@@ -63,7 +69,7 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (i+(j*101) == skipdibit)
|
||||
{
|
||||
skipdibit += 36; //was set to 35, this was the bug
|
||||
skipdibit += 36;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -475,10 +475,16 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
//set to 16 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 16;
|
||||
else state->dmrburstR = 16;
|
||||
|
||||
#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
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
//set to 21 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
}
|
||||
#endif
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
@@ -546,6 +552,7 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, " ALG ID 0x%02X", state->payload_algid);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
|
||||
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
|
||||
fprintf (stderr, " ESSB");
|
||||
}
|
||||
|
||||
@@ -561,6 +568,7 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, " ALG ID 0x%02X", state->payload_algidR);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
|
||||
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
|
||||
fprintf (stderr, " ESSB");
|
||||
}
|
||||
|
||||
@@ -568,7 +576,11 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (ec == -1 || ec >= 15)
|
||||
{
|
||||
//ESS R-S Failure
|
||||
//ESS R-S Failure -- run LFSR on current MI if applicable
|
||||
if (state->currentslot == 0 && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
|
||||
LFSRP(state);
|
||||
if (state->currentslot == 1 && state->payload_algidR != 0x80 && state->payload_keyidR != 0 && state->payload_miN != 0)
|
||||
LFSRP(state);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
@@ -630,15 +642,28 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
//set to 16 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 16;
|
||||
else state->dmrburstR = 16;
|
||||
#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
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
//set to 21 for MBE OSS shim to preempt audio
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
}
|
||||
#endif
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
|
||||
process_ESS(opts, state);
|
||||
|
||||
//reset drop bytes after a 2V
|
||||
if (state->currentslot == 0 && state->payload_algid == 0xAA)
|
||||
state->dropL = 256;
|
||||
|
||||
if (state->currentslot == 1 && state->payload_algidR == 0xAA)
|
||||
state->dropR = 256;
|
||||
|
||||
}
|
||||
|
||||
//P2 Data Unit ID
|
||||
@@ -711,12 +736,24 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else fprintf (stderr, "VCH S ");
|
||||
|
||||
//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
|
||||
//this is primarily a fix for TDMA control channels that carry voice (Duke P25)
|
||||
//but may also allow for chain tuning without returning to the control channel <--may be problematic since we can assign a p25_cc_freq from the pdu
|
||||
if (duid_decoded == 13 && opts->p25_is_tuned == 1 && ((time(NULL) - state->last_vc_sync_time) > opts->trunk_hangtime) ) //version for MAC_SIGNAL only, no idle
|
||||
{
|
||||
opts->p25_is_tuned = 0;
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||
memset (state->active_channel, 0, sizeof (state->active_channel)); //zero out here? I think this will be fine
|
||||
}
|
||||
|
||||
if (duid_decoded == 0)
|
||||
{
|
||||
fprintf (stderr, " 4V %d", state->fourv_counter[state->currentslot]+1);
|
||||
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->last_vc_sync_time = time(NULL);
|
||||
process_4V (opts, state);
|
||||
}
|
||||
}
|
||||
@@ -726,6 +763,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
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->last_vc_sync_time = time(NULL);
|
||||
process_2V (opts, state);
|
||||
}
|
||||
}
|
||||
@@ -823,22 +861,21 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
void processP2 (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
state->dmr_stereo = 1;
|
||||
//state->currentslot = 1;
|
||||
|
||||
p2_dibit_buffer (opts, state);
|
||||
|
||||
//look at our ISCH values and determine location in superframe before running frame scramble
|
||||
for (framing_counter = 0; framing_counter < 4; framing_counter++) //12
|
||||
for (framing_counter = 0; framing_counter < 4; framing_counter++)
|
||||
{
|
||||
process_ISCH (opts, state); //run ISCH in here so we know when to start descramble offset
|
||||
//run ISCH in here so we know when to start descramble offset
|
||||
process_ISCH (opts, state);
|
||||
}
|
||||
|
||||
//set initial current slot depending on offset value
|
||||
if (state->p2_scramble_offset % 2)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
state->currentslot = 1;
|
||||
}
|
||||
else state->currentslot = 1;
|
||||
else state->currentslot = 0;
|
||||
|
||||
//frame_scramble runs lfsr and creates an array of unscrambled bits to pull from
|
||||
process_Frame_Scramble (opts, state);
|
||||
@@ -848,14 +885,5 @@ void processP2 (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_stereo = 0;
|
||||
state->p2_is_lcch = 0;
|
||||
|
||||
//bugfix for OSS dmrbust 16 shim, reset both to 0 upon exit
|
||||
//in case or marginal signal and both get stuck on 16, indefinitely muting the non-preferred slot
|
||||
//but...this can also cause at least one 4v/2v to get through on the other slot if the sync lines up that way
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
//set both to blank value
|
||||
state->dmrburstL = 17;
|
||||
state->dmrburstR = 17;
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
380
src/p25p2_vpdu.c
380
src/p25p2_vpdu.c
@@ -97,7 +97,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X SG: %d;", channel, sgroup);
|
||||
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d; ", channel, sgroup);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
@@ -117,19 +118,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
// //testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -144,14 +134,18 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
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
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,7 +173,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X SG: %d", channel, sgroup);
|
||||
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d ", channel, sgroup);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
@@ -199,19 +194,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -225,14 +209,18 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
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
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,7 +255,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X SG: %d; Ch: %04X SG: %d;", channel1, group1, channel2, group2);
|
||||
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d; Ch: %04X SG: %d; ", channel1, group1, channel2, group2);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
@@ -313,19 +302,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -341,17 +319,21 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
SetFreq(opts->rigctl_sockfd, tunable_freq);
|
||||
//probably best to only set these when really tuning
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1; //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
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,12 +362,26 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
int source = (MAC[7+len_a] << 16) | (MAC[8+len_a] << 8) | MAC[9+len_a];
|
||||
long int freq = 0;
|
||||
|
||||
fprintf (stderr, "\n Group Voice Channel Grant Update");
|
||||
fprintf (stderr, "\n");
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
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, " Group Voice Channel Grant Update");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN [%04X] Group [%d] Source [%d]", svc, channel, group, source);
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d;", channel, group);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; ", channel, group);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
@@ -399,25 +395,17 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//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 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -433,13 +421,17 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
SetFreq(opts->rigctl_sockfd, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,11 +463,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TGT: %d;", channel, target);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TGT: %d; ", channel, target);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Skip tuning private calls if private calls is disabled
|
||||
if (opts->trunk_tune_private_calls == 0) goto SKIPCALL;
|
||||
|
||||
//Skip tuning encrypted calls if enc calls are disabled -- abb formats do not carry svc bits :(
|
||||
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
|
||||
|
||||
//unit to unit needs work, may fail under certain conditions (first blocked, second allowed, etc) (labels should still work though)
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
@@ -492,19 +488,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channel >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channel >> 12] == 1)
|
||||
{
|
||||
@@ -519,14 +504,18 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, freq);
|
||||
if (state->synctype == 0 || state->synctype == 1) state->p25_vc_freq[0] = freq;
|
||||
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
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq);
|
||||
if (state->synctype == 0 || state->synctype == 1) state->p25_vc_freq[0] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -558,20 +547,46 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
long int freq1r = 0;
|
||||
long int freq2t = 0;
|
||||
long int freq2r = 0;
|
||||
|
||||
fprintf (stderr, "\n Group Voice Channel Grant Update Multiple - Explicit");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc1, channelt1, channelr1, group1, group1);
|
||||
if (svc1 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc1 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (svc1 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (svc1 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (svc1 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", svc1 & 0x7); //call priority
|
||||
}
|
||||
freq1t = process_channel_to_freq (opts, state, channelt1);
|
||||
freq1r = process_channel_to_freq (opts, state, channelr1);
|
||||
if (channelr1 != 0 && channelr1 != 0xFFFF) freq1r = process_channel_to_freq (opts, state, channelr1);
|
||||
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc2, channelt2, channelr2, group2, group2);
|
||||
if (svc2 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc2 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (svc2 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (svc2 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (svc2 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", svc2 & 0x7); //call priority
|
||||
}
|
||||
freq1t = process_channel_to_freq (opts, state, channelt2);
|
||||
freq1r = process_channel_to_freq (opts, state, channelr2);
|
||||
if (channelr2 != 0 && channelr2 != 0xFFFF) freq1r = process_channel_to_freq (opts, state, channelr2);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d; Ch: %04X TG: %d;", channelt1, group1, channelt2, group2);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; ", channelt1, group1, channelt2, group2);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//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 ( (svc1 & 0x40) && (svc2 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 1;
|
||||
if (channelt2 == channelt2) loop = 1;
|
||||
else loop = 2;
|
||||
@@ -582,6 +597,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
for (int j = 0; j < loop; j++)
|
||||
{
|
||||
//test svc opts for enc to tune or skip
|
||||
if (j == 0)
|
||||
{
|
||||
if ( (svc1 & 0x40) && opts->trunk_tune_enc_calls == 0) j++; //skip to next
|
||||
}
|
||||
if (j == 1)
|
||||
{
|
||||
if (( svc2 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //skip to end
|
||||
}
|
||||
|
||||
//assign our internal variables for check down on if to tune one freq/group or not
|
||||
if (j == 0)
|
||||
{
|
||||
@@ -610,19 +635,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -636,16 +650,20 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, tunable_freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
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
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -680,18 +698,54 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
fprintf (stderr, "\n Group Voice Channel Grant Update Multiple - Implicit");
|
||||
fprintf (stderr, "\n Channel 1 [%04X] Group 1 [%d][%04X]", channel1, group1, group1);
|
||||
if (so1 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (so1 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (so1 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (so1 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (so1 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", so1 & 0x7); //call priority
|
||||
}
|
||||
freq1 = process_channel_to_freq (opts, state, channel1);
|
||||
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
if (so2 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (so2 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (so2 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (so2 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (so2 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", so2 & 0x7); //call priority
|
||||
}
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
fprintf (stderr, "\n Channel 3 [%04X] Group 3 [%d][%04X]", channel3, group3, group3);
|
||||
if (so3 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (so3 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (so3 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (so3 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (so3 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", so3 & 0x7); //call priority
|
||||
}
|
||||
freq3 = process_channel_to_freq (opts, state, channel3);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; Ch: %04X TG: %d;", channel1, group1, channel2, group2, channel3, group3);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2, channel3, group3);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//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 ( (so1 & 0x40) && (so2 & 0x40) && (so3 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 3;
|
||||
|
||||
long int tunable_freq = 0;
|
||||
@@ -700,6 +754,20 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
for (int j = 0; j < loop; j++)
|
||||
{
|
||||
//test svc opts for enc to tune or skip
|
||||
if (j == 0)
|
||||
{
|
||||
if ( (so1 & 0x40) && opts->trunk_tune_enc_calls == 0) j++; //skip to next
|
||||
}
|
||||
if (j == 1)
|
||||
{
|
||||
if ( (so2 & 0x40) && opts->trunk_tune_enc_calls == 0) j++; //skip to next
|
||||
}
|
||||
if (j == 2)
|
||||
{
|
||||
if ( (so3 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //skip to end
|
||||
}
|
||||
|
||||
//assign our internal variables for check down on if to tune one freq/group or not
|
||||
if (j == 0)
|
||||
{
|
||||
@@ -735,19 +803,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -763,17 +820,21 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
SetFreq(opts->rigctl_sockfd, tunable_freq);
|
||||
//probably best to only set these when really tuning
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1; //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
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
//probably best to only set these when really tuning
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -807,11 +868,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->dmr_lrrp_gps[slot], "Active Ch: %04X TG: %d; Ch: %04X TG: %d;", channel1, group1, channel2, group2);
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//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 -- abb formats do not carry svc bits :(
|
||||
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
|
||||
|
||||
int loop = 1;
|
||||
if (channel1 == channel2) loop = 1;
|
||||
else loop = 2;
|
||||
@@ -851,19 +916,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[tunable_chan >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
|
||||
{
|
||||
@@ -880,16 +934,20 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//probably best to only set these when really tuning
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, tunable_freq);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, tunable_freq);
|
||||
//probably best to only set these when really tuning
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -916,10 +974,23 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
long int freq1 = 0;
|
||||
long int freq2 = 0;
|
||||
|
||||
fprintf (stderr, "\n Group Voice Channel Grant Update - Explicit");
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
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, " Group Voice Channel Grant Update - Explicit");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc, channelt, channelr, group, group);
|
||||
freq1 = process_channel_to_freq (opts, state, channelt);
|
||||
freq2 = process_channel_to_freq (opts, state, channelr);
|
||||
if (channelr != 0 && channelr != 0xFFFF) freq2 = process_channel_to_freq (opts, state, channelr); //one system had this as channel 0xFFFF -- look up any particular meaning for that
|
||||
|
||||
//don't set the tg here, one multiple grant updates, will mess up the TG value on current call
|
||||
// if (slot == 0)
|
||||
@@ -940,25 +1011,18 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//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
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//may be this way independent of whether or not this is QPSK (does C4FM run at 6000 sps?)
|
||||
if (opts->mod_qpsk == 1)
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
if (state->p25_chan_tdma[channelt >> 12] == 1)
|
||||
{
|
||||
@@ -973,14 +1037,18 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
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
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
//rtl_udp
|
||||
//rtl
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
#ifdef USE_RTLSDR
|
||||
rtl_dev_tune (opts, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1218,7 +1286,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
{
|
||||
|
||||
fprintf (stderr, "\n Secondary Control Channel Broadcast - Explicit\n");
|
||||
fprintf (stderr, " RFSS[%03d] SITE ID [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]", rfssid, siteid, channelt, channelr, sysclass);
|
||||
fprintf (stderr, " RFSS [%03d] SITE ID [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]", rfssid, siteid, channelt, channelr, sysclass);
|
||||
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
@@ -1475,7 +1543,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
int lcolorcode = ((MAC[12+len_a] & 0xF) << 8) | MAC[13+len_a];
|
||||
fprintf (stderr, "\n Network Status Broadcast - Extended \n");
|
||||
fprintf (stderr, " LRA [%02X] WACN [%05X] SYSID [%03X] NAC [%03X] CHAN-T [%04X] CHAN-R [%04X]", lra, lwacn, lsysid, lcolorcode, channelt, channelr);
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
state->p25_cc_freq = process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
state->p25_cc_is_tdma = 1; //flag on for CC tuning purposes when system is qpsk
|
||||
if (state->p2_hardset == 0 ) //state->p2_is_lcch == 1 shim until CRC is working, prevent bogus data
|
||||
|
||||
@@ -13,6 +13,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
//Figure out which PDU we are looking at, see above info on 8.4.1
|
||||
//reorganize bits into bytes and process accordingly
|
||||
|
||||
//new slot variable with flipped assignment for SACCH
|
||||
uint8_t slot = (state->currentslot ^ 1) & 1;
|
||||
|
||||
unsigned long long int SMAC[24] = {0}; //22.5 bytes for SACCH MAC PDUs
|
||||
int byte = 0;
|
||||
int k = 0;
|
||||
@@ -117,6 +120,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
|
||||
state->dmrburstL = 20;
|
||||
fprintf (stderr, "\n VCH 0 - ");
|
||||
@@ -139,6 +143,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
|
||||
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -150,6 +155,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->payload_algidR = 0; //zero this out as well
|
||||
|
||||
state->dmrburstR = 20;
|
||||
@@ -173,6 +179,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
|
||||
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -191,6 +198,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
state->dmrburstL = 23;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
@@ -206,11 +214,15 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
|
||||
//blank the call string here -- slot variable is already flipped accordingly for sacch
|
||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
}
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->dmrburstR = 23;
|
||||
state->payload_algidR = 0;
|
||||
state->payload_keyidR = 0;
|
||||
@@ -236,12 +248,25 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
process_MAC_VPDU(opts, state, 1, SMAC);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//blank the call string here -- slot variable is already flipped accordingly for sacch
|
||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
}
|
||||
if (opcode == 0x4 && err == 0)
|
||||
{
|
||||
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
|
||||
//if (state->currentslot == 1) state->dmrburstL = 21;
|
||||
//else state->dmrburstR = 21;
|
||||
#ifdef AERO_BUILD
|
||||
if (opts->audio_out_type != 5)
|
||||
{
|
||||
if (state->currentslot == 1) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
}
|
||||
#else
|
||||
if (state->currentslot == 1) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
#endif
|
||||
|
||||
fprintf (stderr, " MAC_ACTIVE ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
process_MAC_VPDU(opts, state, 1, SMAC);
|
||||
@@ -251,13 +276,13 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
state->dmrburstL = 21;
|
||||
state->dmrburstL = 22;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmrburstR = 21;
|
||||
state->dmrburstR = 22;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
@@ -280,6 +305,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
//Figure out which PDU we are looking at, see above info on 8.4.1
|
||||
//reorganize bits into bytes and process accordingly
|
||||
|
||||
//new slot variable
|
||||
uint8_t slot = state->currentslot;
|
||||
|
||||
unsigned long long int FMAC[24] = {0}; //19.5 bytes for FACCH MAC PDUs, add padding to end
|
||||
int byte = 0;
|
||||
int k = 0;
|
||||
@@ -347,6 +375,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
|
||||
state->dmrburstL = 20;
|
||||
fprintf (stderr, "\n VCH 0 - ");
|
||||
@@ -369,6 +398,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
|
||||
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -380,6 +410,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
|
||||
state->dmrburstR = 20;
|
||||
fprintf (stderr, "\n VCH 1 - ");
|
||||
@@ -402,6 +433,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
|
||||
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
|
||||
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
|
||||
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
|
||||
fprintf(stderr, " MPTT");
|
||||
// fprintf (stderr, " %s", KRED);
|
||||
// fprintf (stderr, "ENC");
|
||||
@@ -419,6 +451,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
|
||||
state->fourv_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
state->dmrburstL = 23;
|
||||
state->payload_algid = 0; //zero this out as well
|
||||
state->payload_keyid = 0;
|
||||
@@ -433,12 +466,16 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
|
||||
//blank the call string here
|
||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
|
||||
state->fourv_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->dmrburstR = 23;
|
||||
state->payload_algidR = 0; //zero this out as well
|
||||
state->payload_keyidR = 0;
|
||||
@@ -484,12 +521,25 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
process_MAC_VPDU(opts, state, 0, FMAC);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//blank the call string here
|
||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
}
|
||||
if (opcode == 0x4 && err == 0)
|
||||
{
|
||||
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
|
||||
//if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
//else state->dmrburstR = 21;
|
||||
#ifdef AERO_BUILD
|
||||
if (opts->audio_out_type != 5)
|
||||
{
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
}
|
||||
#else
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
#endif
|
||||
|
||||
fprintf (stderr, " MAC_ACTIVE ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
process_MAC_VPDU(opts, state, 0, FMAC);
|
||||
|
||||
750
src/provoice.c
750
src/provoice.c
@@ -1,584 +1,432 @@
|
||||
#include "dsd.h"
|
||||
#include "provoice_const.h"
|
||||
|
||||
void
|
||||
processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
// #define PVDEBUG
|
||||
|
||||
void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, dibit, k;
|
||||
uint8_t lid[80];
|
||||
uint8_t lidbyte[10];
|
||||
uint8_t init[64];
|
||||
uint8_t initbyte[8];
|
||||
int i, j, dibit;
|
||||
char imbe7100_fr1[7][24];
|
||||
char imbe7100_fr2[7][24];
|
||||
const int *w, *x;
|
||||
|
||||
//raw bits storage for analysis
|
||||
uint8_t raw_bits[800];
|
||||
memset (raw_bits, 0, sizeof(raw_bits));
|
||||
//raw bytes storage for analysis
|
||||
uint8_t raw_bytes[100];
|
||||
memset (raw_bytes, 0, sizeof(raw_bytes));
|
||||
|
||||
unsigned long long int initial = 0; //initial 64-bits before the lid
|
||||
uint16_t lid = 0; //lid value 16-bit
|
||||
unsigned long long int secondary = 0; //secondary 64-bits after lid, before voice
|
||||
|
||||
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));
|
||||
uint8_t spacer = 0;
|
||||
uint16_t bf = 0; //the 16-bit value in-between imbe 2 and imbe 3 that is usually 2175
|
||||
|
||||
fprintf (stderr," VOICE");
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1)
|
||||
|
||||
//print group and source values if EA trunked
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->ea_mode == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " Site [%02llX][%03lld] Group [%05d] Source [%08d] LCN[%02d] ",
|
||||
state->edacs_site_id, state->edacs_site_id, state->lasttg, state->lastsrc, state->edacs_tuned_lcn);
|
||||
fprintf (stderr, " Site: %lld Group: %d Source: %d LCN: %d ",
|
||||
state->edacs_site_id, state->lasttg, state->lastsrc, state->edacs_tuned_lcn);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//print afs value if standard/networked trunked
|
||||
else if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->ea_mode == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " Site: %lld AFS: %d-%d LCN: %d ",
|
||||
state->edacs_site_id, (state->lasttg >> 7) & 0xF, state->lasttg & 0x7F, state->edacs_tuned_lcn);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
init[i] = dibit;
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
//iNitial 64 bits
|
||||
//load all initial bits before voice into raw_bits array for analysis/handling
|
||||
for (i = 0; i < 64+16+64; i++)
|
||||
raw_bits[i] = getDibit (opts, state);
|
||||
|
||||
//Note: the initial 144-bits seem to be provisioned differently depending on system type
|
||||
initial = (unsigned long long int)ConvertBitIntoBytes(&raw_bits[0], 64);
|
||||
lid = (uint16_t)ConvertBitIntoBytes(&raw_bits[64], 16);
|
||||
secondary = (unsigned long long int)ConvertBitIntoBytes(&raw_bits[80], 64);
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
k = 0;
|
||||
fprintf (stderr, "\n N64: ");
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
initbyte[i] = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
initbyte[i] = initbyte[i] << 1;
|
||||
initbyte[i] = initbyte[i] | init[k];
|
||||
k++;
|
||||
}
|
||||
fprintf (stderr, "%02X", initbyte[i]);
|
||||
if (i == 3) fprintf (stderr, "-");
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "\n N64: %016llX", initial);
|
||||
fprintf (stderr, "\n LID: %04X", lid);
|
||||
fprintf (stderr, " %016llX", secondary);
|
||||
}
|
||||
// lid
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
lid[i] = dibit;
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
lid[i+16] = dibit;
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
//load lid (bits) into lidbyte
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
k = 0;
|
||||
fprintf (stderr, " LID: ");
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
lidbyte[i] = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
lidbyte[i] = lidbyte[i] << 1;
|
||||
lidbyte[i] = lidbyte[i] | lid[k];
|
||||
k++;
|
||||
}
|
||||
fprintf (stderr, "%02X", lidbyte[i]);
|
||||
if (i == 3 || i == 7) fprintf (stderr, "-");
|
||||
}
|
||||
// fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
// imbe frames 1,2 first half
|
||||
w = pW;
|
||||
x = pX;
|
||||
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[144+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[150+j+(i*12)] = dibit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+282] = dibit;
|
||||
}
|
||||
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+288] = dibit;
|
||||
}
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
spacer_bit[0] = dibit;
|
||||
raw_bits[292] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
spacer_bit[1] = dibit;
|
||||
raw_bits[293] = dibit;
|
||||
|
||||
// imbe frames 1,2 second half
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+294] = dibit;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[296+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[302+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+338] = dibit;
|
||||
}
|
||||
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+343] = dibit;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[348+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[354+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+438] = dibit;
|
||||
}
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+443] = dibit;
|
||||
}
|
||||
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
spacer_bit[2] = dibit;
|
||||
raw_bits[448] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
spacer_bit[3] = dibit;
|
||||
raw_bits[449] = dibit;
|
||||
|
||||
//resume raw_bits at +6 current value to round out payload bytes
|
||||
//easier to visualize patterns
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state); //HERE
|
||||
init[i] = dibit; //recycle
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
k = 0;
|
||||
fprintf (stderr, "\n 16B: ");
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
initbyte[i] = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
initbyte[i] = initbyte[i] << 1;
|
||||
initbyte[i] = initbyte[i] | init[k];
|
||||
k++;
|
||||
}
|
||||
fprintf (stderr, "%02X", initbyte[i]);
|
||||
}
|
||||
// fprintf (stderr, "\n");
|
||||
}
|
||||
raw_bits[i+450+6] = getDibit (opts, state);
|
||||
|
||||
bf = (uint16_t)ConvertBitIntoBytes(&raw_bits[456], 16);
|
||||
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\n BF: %04X ", bf);
|
||||
|
||||
// imbe frames 3,4 first half
|
||||
w = pW;
|
||||
x = pX;
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
}
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+466+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"_");
|
||||
#endif
|
||||
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+472+j+(i*12)] = dibit;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+604+6] = dibit;
|
||||
}
|
||||
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[i+610+6] = dibit;
|
||||
}
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
spacer_bit[4];
|
||||
raw_bits[614+2] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
spacer_bit[5];
|
||||
raw_bits[615+2] = dibit;
|
||||
|
||||
// imbe frames 3,4 second half
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+616+6] = dibit;
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+618+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+624+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr," ");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+660+6] = dibit;
|
||||
}
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+665+6] = dibit;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+670+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+676+j+(i*12)] = dibit;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr," ");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+760+6] = dibit;
|
||||
}
|
||||
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+765+6] = dibit;
|
||||
}
|
||||
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
#endif
|
||||
spacer_bit[6] = dibit;
|
||||
raw_bits[782] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
//fprintf (stderr,"%i", dibit);
|
||||
//fprintf (stderr," ");
|
||||
spacer_bit[7] = dibit;
|
||||
raw_bits[783] = dibit;
|
||||
|
||||
#ifdef PVDEBUG
|
||||
|
||||
spacer = (uint8_t)ConvertBitIntoBytes(&spacer_bit[0], 8);
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\n SP: %X", spacer);
|
||||
|
||||
//convert raw bits into raw bytes for payload analysis
|
||||
for (j = 0; j < 98; j++)
|
||||
{
|
||||
raw_bytes[j] = (uint8_t)ConvertBitIntoBytes(&raw_bits[(j*8)], 8);
|
||||
}
|
||||
|
||||
//payload on all raw bytes for analysis...its a lot of 'em
|
||||
if (opts->payload == 1) //find better thingy later or change this
|
||||
// if (opcode != 0x3333)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n pV Payload Dump: \n ");
|
||||
for (j = 0; j < 98; j++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", raw_bytes[j]);
|
||||
if (j == 17 || j == 35 || j == 53 || j == 71 || j == 89)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
fprintf (stderr,"\n");
|
||||
}
|
||||
//line break at end of frame
|
||||
fprintf (stderr,"\n");
|
||||
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
#include <rtl-sdr.h>
|
||||
#include "dsd.h"
|
||||
|
||||
//#define DEFAULT_SAMPLE_RATE 48000 //moved to opts->rtl_bandwidth
|
||||
#define DEFAULT_SAMPLE_RATE 48000
|
||||
#define DEFAULT_BUF_LENGTH (1 * 16384)
|
||||
#define MAXIMUM_OVERSAMPLE 16 //16
|
||||
#define MAXIMUM_OVERSAMPLE 16
|
||||
#define MAXIMUM_BUF_LENGTH (MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH)
|
||||
#define AUTO_GAIN -100
|
||||
#define BUFFER_DUMP 4096
|
||||
#define BUFFER_DUMP 4096
|
||||
|
||||
#define FREQUENCIES_LIMIT 1000
|
||||
|
||||
@@ -46,7 +46,8 @@ static int ACTUAL_BUF_LENGTH;
|
||||
static int *atan_lut = NULL;
|
||||
static int atan_lut_size = 131072; /* 512 KB */
|
||||
static int atan_lut_coef = 8;
|
||||
//new for UDP
|
||||
|
||||
//UDP -- keep for compatibility reasons
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
static pthread_t socket_freq;
|
||||
@@ -57,7 +58,7 @@ int bandwidth_divisor = 48000; //divide bandwidth by this to get multiplier for
|
||||
|
||||
short int volume_multiplier;
|
||||
short int port;
|
||||
//
|
||||
|
||||
struct dongle_state
|
||||
{
|
||||
int exit_flag;
|
||||
@@ -597,7 +598,6 @@ static void *demod_thread_fn(void *arg)
|
||||
|
||||
int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
|
||||
{
|
||||
//target_gain = 36;
|
||||
int i, r, err1, err2, count, nearest;
|
||||
int* gains;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
@@ -628,10 +628,9 @@ int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
|
||||
int r;
|
||||
r = rtlsdr_set_center_freq(dev, frequency);
|
||||
if (r < 0) {
|
||||
fprintf (stderr, "WARNING: Failed to set center freq.\n");
|
||||
fprintf (stderr, " (WARNING: Failed to set Center Frequency). \n");
|
||||
} else {
|
||||
//fprintf (stderr, "Tuned to %u Hz.\n", frequency);
|
||||
fprintf (stderr, "Tuned to center frequency %u Hz.\n", frequency);
|
||||
fprintf (stderr, " (Center Frequency: %u Hz.) \n", frequency);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -679,7 +678,6 @@ int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
||||
|
||||
int verbose_auto_gain(rtlsdr_dev_t *dev)
|
||||
{
|
||||
|
||||
int r;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
if (r != 0) {
|
||||
@@ -692,7 +690,6 @@ int verbose_auto_gain(rtlsdr_dev_t *dev)
|
||||
|
||||
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
||||
{
|
||||
//gain = 36;
|
||||
int r;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
if (r < 0) {
|
||||
@@ -710,7 +707,6 @@ int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
||||
|
||||
int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
|
||||
{
|
||||
//ppm_error = -2; //fix this opt arg to accept negative float values, i.e. float or double??
|
||||
int r;
|
||||
if (ppm_error == 0) {
|
||||
return 0;}
|
||||
@@ -732,25 +728,23 @@ int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
||||
return r;
|
||||
}
|
||||
|
||||
//static void optimal_settings(struct fm_state *fm, int freq, int hopping)
|
||||
static void optimal_settings(int freq, int rate) //
|
||||
static void optimal_settings(int freq, int rate)
|
||||
{
|
||||
// giant ball of hacks
|
||||
// seems unable to do a single pass, 2:1
|
||||
//int r, capture_freq, capture_rate;
|
||||
int capture_freq, capture_rate;
|
||||
struct dongle_state *d = &dongle;
|
||||
struct demod_state *dm = &demod;
|
||||
struct controller_state *cs = &controller;
|
||||
dm->downsample = (1000000 / dm->rate_in) + 1;
|
||||
dm->downsample = (1000000 / dm->rate_in) + 1; //dm->rate_in is the rtl_bandwidth value
|
||||
if (dm->downsample_passes) {
|
||||
dm->downsample_passes = (int)log2(dm->downsample) + 1;
|
||||
dm->downsample = 1 << dm->downsample_passes;
|
||||
}
|
||||
capture_freq = freq;
|
||||
capture_rate = dm->downsample * dm->rate_in;
|
||||
capture_rate = dm->downsample * dm->rate_in; //
|
||||
if (!d->offset_tuning) {
|
||||
capture_freq = freq + capture_rate/4;}
|
||||
capture_freq = freq + capture_rate/4;} //
|
||||
capture_freq += cs->edge * dm->rate_in / 2;
|
||||
dm->output_scale = (1<<15) / (128 * dm->downsample);
|
||||
if (dm->output_scale < 1) {
|
||||
@@ -759,6 +753,7 @@ static void optimal_settings(int freq, int rate) //
|
||||
dm->output_scale = 1;}
|
||||
d->freq = (uint32_t)capture_freq;
|
||||
d->rate = (uint32_t)capture_rate;
|
||||
// fprintf (stderr, "Capture Frequency: %i Rate: %i \n", capture_freq, capture_rate);
|
||||
}
|
||||
|
||||
static void *controller_thread_fn(void *arg)
|
||||
@@ -790,7 +785,6 @@ static void *controller_thread_fn(void *arg)
|
||||
/* Set the sample rate */
|
||||
verbose_set_sample_rate(dongle.dev, dongle.rate);
|
||||
fprintf (stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample);
|
||||
fprintf (stderr, "Press CTRL + C to close.\n");
|
||||
|
||||
while (!exitflag) {
|
||||
safe_cond_wait(&s->hop, &s->hop_m);
|
||||
@@ -807,20 +801,16 @@ static void *controller_thread_fn(void *arg)
|
||||
|
||||
void dongle_init(struct dongle_state *s)
|
||||
{
|
||||
//s->rate = DEFAULT_SAMPLE_RATE;
|
||||
s->rate = rtl_bandwidth;
|
||||
s->gain = AUTO_GAIN; // tenths of a dB
|
||||
s->mute = 0;
|
||||
s->direct_sampling = 0;
|
||||
s->offset_tuning = 0; //
|
||||
s->offset_tuning = 0; //E4000 tuners only
|
||||
s->demod_target = &demod;
|
||||
|
||||
}
|
||||
|
||||
void demod_init(struct demod_state *s)
|
||||
{
|
||||
//s->rate_in = DEFAULT_SAMPLE_RATE;
|
||||
//s->rate_out = DEFAULT_SAMPLE_RATE;
|
||||
s->rate_in = rtl_bandwidth;
|
||||
s->rate_out = rtl_bandwidth;
|
||||
s->squelch_level = 0;
|
||||
@@ -830,16 +820,16 @@ void demod_init(struct demod_state *s)
|
||||
s->downsample_passes = 0;
|
||||
s->comp_fir_size = 0;
|
||||
s->prev_index = 0;
|
||||
s->post_downsample = 1; // once this works, default = 4
|
||||
s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either
|
||||
s->custom_atan = 0;
|
||||
s->deemph = 0;
|
||||
s->rate_out2 = -1; // flag for disabled
|
||||
s->rate_out2 = rtl_bandwidth; // -1 flag for disabled -- this enables low_pass_real, seems to work okay
|
||||
s->mode_demod = &fm_demod;
|
||||
s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
|
||||
s->prev_lpr_index = 0;
|
||||
s->deemph_a = 0;
|
||||
s->now_lpr = 0;
|
||||
s->dc_block = 0;
|
||||
s->dc_block = 1; //enabling by default, but offset tuning is also enabled, so center spike shouldn't be an issue
|
||||
s->dc_avg = 0;
|
||||
pthread_rwlock_init(&s->rw, NULL);
|
||||
pthread_cond_init(&s->ready, NULL);
|
||||
@@ -856,7 +846,6 @@ void demod_cleanup(struct demod_state *s)
|
||||
|
||||
void output_init(struct output_state *s)
|
||||
{
|
||||
//s->rate = DEFAULT_SAMPLE_RATE;
|
||||
s->rate = rtl_bandwidth;
|
||||
pthread_rwlock_init(&s->rw, NULL);
|
||||
pthread_cond_init(&s->ready, NULL);
|
||||
@@ -904,7 +893,8 @@ void sanity_checks(void)
|
||||
}
|
||||
|
||||
}
|
||||
//UDP remote all below HERE
|
||||
|
||||
//UDP remote stuff
|
||||
static unsigned int chars_to_int(unsigned char* buf) {
|
||||
|
||||
int i;
|
||||
@@ -918,9 +908,7 @@ static unsigned int chars_to_int(unsigned char* buf) {
|
||||
}
|
||||
|
||||
static void *socket_thread_fn(void *arg) {
|
||||
//struct fm_state *fm = arg;
|
||||
struct demod_state *d = static_cast<demod_state*>(arg);
|
||||
//int port = 6020;
|
||||
int r, n;
|
||||
int sockfd, newsockfd, portno;
|
||||
socklen_t clilen;
|
||||
@@ -952,114 +940,34 @@ static void *socket_thread_fn(void *arg) {
|
||||
while((n = read(sockfd,buffer,5)) != 0) {
|
||||
if(buffer[0] == 0) {
|
||||
new_freq = chars_to_int(buffer);
|
||||
dongle.freq = new_freq; //
|
||||
//opts->rtlsdr_center_freq = new_freq; //or dongle.freq, this should update the freq displayed in ncurses terminal hopefully and not do anything naughty
|
||||
|
||||
dongle.freq = new_freq;
|
||||
optimal_settings(new_freq, demod.rate_in);
|
||||
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
||||
//verbose_set_frequency (dongle.dev, new_freq);
|
||||
//fprintf (stderr, "Tuning to: %d [Hz] (central freq: %d [Hz])\n", new_freq, new_freq + freq_offset);
|
||||
fprintf (stderr, "\nTuning to: %d [Hz] \n", new_freq);
|
||||
}
|
||||
/*
|
||||
if(buffer[0] == 1) {
|
||||
// change demod type
|
||||
int type = chars_to_int(buffer);
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
fprintf (stderr, "Changing demod type to FM\n");
|
||||
fm->mode_demod = &fm_demod;
|
||||
break;
|
||||
case 1:
|
||||
fprintf (stderr, "Changing demod type to AM\n");
|
||||
fm->mode_demod = &am_demod;
|
||||
break;
|
||||
case 2:
|
||||
fprintf (stderr, "Changing demod type to USB\n");
|
||||
fm->mode_demod = &usb_demod;
|
||||
fm->custom_atan = 1;
|
||||
break;
|
||||
case 3:
|
||||
fprintf (stderr, "Changing demod type to LSB\n");
|
||||
fm->mode_demod = &lsb_demod;
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "Unknown demod type %d\n", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//SQUELCH HERE
|
||||
|
||||
if (buffer[0] == 2) {
|
||||
new_squelch = chars_to_int(buffer);
|
||||
demod.squelch_level = new_squelch; //demod, or d*? or d->
|
||||
//full_demod(d);
|
||||
//new_freq = 850000000;
|
||||
//dongle.freq = new_freq;
|
||||
//optimal_settings(new_freq, demod.rate_in); //hacky way to 'squelch', just setting it to a dead freq instead
|
||||
//rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
||||
fprintf (stderr, "Changing squelch to %d \n", new_squelch);
|
||||
}
|
||||
|
||||
/*
|
||||
if (buffer[0] == 3) {
|
||||
new_gain = chars_to_int(buffer);
|
||||
if (new_gain == AUTO_GAIN) {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
} else {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
new_gain = nearest_gain(new_gain);
|
||||
r = rtlsdr_set_tuner_gain(dev, new_gain);
|
||||
}
|
||||
|
||||
if (r != 0) {
|
||||
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
|
||||
} else if (new_gain == AUTO_GAIN) {
|
||||
fprintf (stderr, "Tuner gain set to automatic.\n");
|
||||
} else {
|
||||
fprintf (stderr, "Tuner gain set to %0.2f dB.\n", new_gain/10.0);
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (buffer[0] == 8) {
|
||||
agc_mode = chars_to_int(buffer);
|
||||
if (agc_mode == 0 || agc_mode == 1) {
|
||||
fprintf (stderr, "Setting AGC to %d\n", agc_mode);
|
||||
rtlsdr_set_agc_mode(dev, agc_mode);
|
||||
} else {
|
||||
fprintf (stderr, "Failed to set AGC to %d\n", agc_mode);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
//UDP Control all above HERE
|
||||
//UDP stuff end
|
||||
|
||||
void rtlsdr_sighandler()
|
||||
{
|
||||
//fprintf (stderr, "Signal caught, exiting!\n");
|
||||
//fprintf (stderr, "Press CTRL + C again to close. Thanks. \n"); //Kindly remind user to double tap CTRL + C
|
||||
|
||||
fprintf (stderr, "Signal caught, exiting!\n");
|
||||
rtlsdr_cancel_async(dongle.dev);
|
||||
//cleanup_rtlsdr_stream(); //thank the wraith for this one...if it works...didn't work
|
||||
//_Exit(1);
|
||||
}
|
||||
|
||||
void open_rtlsdr_stream(dsd_opts *opts)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
int r;
|
||||
rtl_bandwidth = opts->rtl_bandwidth * 1000; //multiple by 1000 to get rate
|
||||
//rtl_bandwidth = 48000;
|
||||
rtl_bandwidth = opts->rtl_bandwidth * 1000; //reverted back to straight value
|
||||
bandwidth_multiplier = (bandwidth_divisor / rtl_bandwidth);
|
||||
//bandwidth_multiplier = 1;
|
||||
|
||||
//this needs to be initted first, then we set the parameters
|
||||
dongle_init(&dongle);
|
||||
demod_init(&demod);
|
||||
output_init(&output);
|
||||
@@ -1070,29 +978,23 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
controller.freq_len++;
|
||||
}
|
||||
|
||||
if (opts->rtlsdr_ppm_error > 0 || opts->rtlsdr_ppm_error < 0) { //this way will adjust PPM based on negative values as well
|
||||
if (opts->rtlsdr_ppm_error != 0) {
|
||||
dongle.ppm_error = opts->rtlsdr_ppm_error;
|
||||
fprintf (stderr, "Setting RTL PPM Error Set to %d\n", opts->rtlsdr_ppm_error);
|
||||
}
|
||||
|
||||
if (opts->audio_in_type == 3) {
|
||||
dongle.dev_index = opts->rtl_dev_index;
|
||||
//rtl_bandwidth = opts->rtl_bandwidth * 1000; //multiple by 1000 to get rate
|
||||
//rtl_bandwidth = 48000;
|
||||
//bandwidth_multiplier = rtl_bandwidth / bandwidth_divisor; //find multiple with no remainder if oddball number entered
|
||||
//bandwidth_multiplier = 1;
|
||||
demod.squelch_level = opts->rtl_squelch_level; //adding user definable squelch level to prevent false positives on account of noise in NXDN etc
|
||||
fprintf (stderr, "Setting RTL VFO Bandwidth to %d Hz\n", rtl_bandwidth);
|
||||
fprintf (stderr, "Setting RTL Sample Multiplier to %d\n", bandwidth_multiplier);
|
||||
fprintf (stderr, "Setting RTL Squelch Level to %d\n", demod.squelch_level);
|
||||
port = opts->rtl_udp_port;
|
||||
}
|
||||
|
||||
dongle.dev_index = opts->rtl_dev_index;
|
||||
// demod.squelch_level = opts->rtl_squelch_level; //no longer used here, used in framesync vc rms value under select conditions
|
||||
fprintf (stderr, "Setting RTL Bandwidth to %d Hz\n", rtl_bandwidth);
|
||||
// fprintf (stderr, "Setting RTL Sample Multiplier to %d\n", bandwidth_multiplier);
|
||||
fprintf (stderr, "Setting RTL RMS Squelch Level to %d\n", opts->rtl_squelch_level);
|
||||
if (opts->rtl_udp_port != 0) port = opts->rtl_udp_port; //set this here, only open socket thread if set
|
||||
if (opts->rtl_gain_value > 0) {
|
||||
dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm really works
|
||||
dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm works
|
||||
}
|
||||
volume_multiplier = opts->rtl_volume_multiplier;
|
||||
fprintf (stderr, "Setting RTL Volume Multiplier to %d\n", volume_multiplier);
|
||||
// fprintf (stderr, "Setting RTL Volume Multiplier to %d\n", volume_multiplier);
|
||||
|
||||
/* quadruple sample_rate to limit to Δθ to ±π/2 */
|
||||
demod.rate_in *= demod.post_downsample;
|
||||
|
||||
@@ -1103,24 +1005,16 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
if (controller.freq_len > 1) demod.terminate_on_squelch = 0;
|
||||
|
||||
ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
|
||||
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
||||
|
||||
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf (stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index);
|
||||
exit(1);
|
||||
} else {
|
||||
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index); //Kindly tell us which device we are using
|
||||
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index);
|
||||
}
|
||||
|
||||
// sigact.sa_handler = sighandler;
|
||||
// sigemptyset(&sigact.sa_mask);
|
||||
// sigact.sa_flags = 0;
|
||||
// sigaction(SIGINT, &sigact, NULL);
|
||||
// sigaction(SIGTERM, &sigact, NULL);
|
||||
// sigaction(SIGQUIT, &sigact, NULL);
|
||||
// sigaction(SIGPIPE, &sigact, NULL);
|
||||
|
||||
if (demod.deemph) {
|
||||
demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
|
||||
}
|
||||
@@ -1128,9 +1022,11 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
/* Set the tuner gain */
|
||||
if (dongle.gain == AUTO_GAIN) {
|
||||
verbose_auto_gain(dongle.dev);
|
||||
fprintf (stderr, "Setting RTL Autogain. \n");
|
||||
} else {
|
||||
dongle.gain = nearest_gain(dongle.dev, dongle.gain);
|
||||
verbose_gain_set(dongle.dev, dongle.gain);
|
||||
// fprintf (stderr, "Setting RTL Nearest Gain to %d. \n", dongle.gain); //seems to be working now
|
||||
}
|
||||
|
||||
verbose_ppm_set(dongle.dev, dongle.ppm_error);
|
||||
@@ -1142,7 +1038,8 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
usleep(100000);
|
||||
pthread_create(&demod.thread, NULL, demod_thread_fn, (void*)(&demod));
|
||||
pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void*)(&dongle));
|
||||
pthread_create(&socket_freq, NULL, socket_thread_fn, (void *)(&controller));
|
||||
//only create socket thread IF user specified (for legacy uses), else don't use it
|
||||
if (port != 0) pthread_create(&socket_freq, NULL, socket_thread_fn, (void *)(&controller));
|
||||
}
|
||||
|
||||
void cleanup_rtlsdr_stream()
|
||||
@@ -1155,8 +1052,6 @@ void cleanup_rtlsdr_stream()
|
||||
safe_cond_signal(&output.ready, &output.ready_m);
|
||||
safe_cond_signal(&controller.hop, &controller.hop_m);
|
||||
pthread_join(controller.thread, NULL);
|
||||
//add socket thread
|
||||
//pthread_join(socket_freq, NULL);
|
||||
|
||||
//dongle_cleanup(&dongle);
|
||||
demod_cleanup(&demod);
|
||||
@@ -1164,32 +1059,69 @@ void cleanup_rtlsdr_stream()
|
||||
controller_cleanup(&controller);
|
||||
|
||||
rtlsdr_close(dongle.dev);
|
||||
|
||||
}
|
||||
|
||||
//void get_rtlsdr_sample(int16_t *sample)
|
||||
//original for safe keeping
|
||||
// void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
||||
// {
|
||||
// if (output.queue.empty())
|
||||
// {
|
||||
// safe_cond_wait(&output.ready, &output.ready_m);
|
||||
// }
|
||||
// pthread_rwlock_wrlock(&output.rw);
|
||||
// *sample = output.queue.front() * volume_multiplier;
|
||||
// output.queue.pop();
|
||||
// pthread_rwlock_unlock(&output.rw);
|
||||
// }
|
||||
|
||||
//find way to modify this function to allow hopping (tuning) while squelched and send 0 sample?
|
||||
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if (output.queue.empty())
|
||||
{
|
||||
if (opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
//ncursesPrinter(opts, state);
|
||||
//printw ("\n\n\n HELP I'M LOCKED!\n");
|
||||
}
|
||||
safe_cond_wait(&output.ready, &output.ready_m);
|
||||
//goto END;
|
||||
}
|
||||
|
||||
pthread_rwlock_wrlock(&output.rw);
|
||||
//*sample = output.queue.front();
|
||||
|
||||
*sample = output.queue.front() * volume_multiplier; //try multiplying by numbers here for 'gain'
|
||||
*sample = output.queue.front() * volume_multiplier;
|
||||
output.queue.pop();
|
||||
pthread_rwlock_unlock(&output.rw);
|
||||
// END:
|
||||
// if (1 == 2)
|
||||
// {
|
||||
// fprintf (stderr, "This is a dumb thing to fix");
|
||||
// }
|
||||
}
|
||||
|
||||
//function may lag since it isn't running as its own thread
|
||||
void rtl_dev_tune(dsd_opts * opts, long int frequency)
|
||||
{
|
||||
int r;
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\nTuning to %lu Hz.", frequency);
|
||||
dongle.freq = opts->rtlsdr_center_freq = frequency;
|
||||
optimal_settings(dongle.freq, demod.rate_in);
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, " (Center Frequency: %u Hz.) \n", dongle.freq);
|
||||
r = rtlsdr_set_center_freq(dongle.dev, dongle.freq);
|
||||
if (r < 0)
|
||||
fprintf (stderr, " (WARNING: Failed to set Center Frequency %u). \n", dongle.freq);
|
||||
|
||||
pthread_rwlock_wrlock(&output.rw); //prevent possible segfault when cleaning the queue
|
||||
rtl_clean_queue();
|
||||
pthread_rwlock_unlock(&output.rw); //resume
|
||||
|
||||
}
|
||||
|
||||
//return RMS value (root means square) power level -- used as soft squelch inside of framesync
|
||||
int rtl_return_rms()
|
||||
{
|
||||
int sr = 0;
|
||||
sr = rms(demod.lowpassed, demod.lp_len, 1);
|
||||
// 'Fix' potential negative value overflow from the rms function -- Observed in Windows builds
|
||||
sr = abs(sr);
|
||||
if (sr > 9999) sr = 9999;
|
||||
return (sr);
|
||||
}
|
||||
|
||||
//simple function to clear the rtl sample queue when tuning and during other events (ncurses menu open/close)
|
||||
void rtl_clean_queue()
|
||||
{
|
||||
//insert method to clear the entire queue to prevent sample 'lag'
|
||||
std::queue<int16_t> empty; //create an empty queue
|
||||
std::swap( output.queue, empty ); //swap in empty queue to effectively zero out current queue
|
||||
}
|
||||
BIN
tone24.wav
Normal file
BIN
tone24.wav
Normal file
Binary file not shown.
BIN
tone48.wav
Normal file
BIN
tone48.wav
Normal file
Binary file not shown.
4
virtualsink.sh
Normal file
4
virtualsink.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||
pactl load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user