mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Compare commits
95 Commits
win32-rc5
...
v.2.0_fina
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae58fabb72 | ||
|
|
e390251b9d | ||
|
|
f7ad3e638f | ||
|
|
a16c99994c | ||
|
|
7f187ff6d8 | ||
|
|
8485be965b | ||
|
|
d1e1572139 | ||
|
|
95e74c8e28 | ||
|
|
815fbb026f | ||
|
|
d1ce0121be | ||
|
|
a55db055d4 | ||
|
|
443b7c3031 | ||
|
|
4bebb361ec | ||
|
|
6f538fd166 | ||
|
|
fef36e3761 | ||
|
|
19df3dd7f1 | ||
|
|
acd2b0b134 | ||
|
|
0908baa47c | ||
|
|
c507ed229c | ||
|
|
3101bbde28 | ||
|
|
5e24ff505d | ||
|
|
4a8bf144dd | ||
|
|
d872818e03 | ||
|
|
f967b80217 | ||
|
|
f3d94ddc2a | ||
|
|
18bec720ae | ||
|
|
456687ba86 | ||
|
|
ba0e422f23 | ||
|
|
ce75acb41a | ||
|
|
68862296bf | ||
|
|
f3c0199b32 | ||
|
|
c8e8e041b7 | ||
|
|
85eea59598 | ||
|
|
304b5545ba | ||
|
|
313759333e | ||
|
|
1737c1f7e9 | ||
|
|
bd94f83318 | ||
|
|
5d7988ea0f | ||
|
|
432495c1ad | ||
|
|
9c75583323 | ||
|
|
b9389742f6 | ||
|
|
fb59406a28 | ||
|
|
339323695f | ||
|
|
d8e7c4c3aa | ||
|
|
1dc6737cc2 | ||
|
|
c1ed3fe038 | ||
|
|
d86b370a22 | ||
|
|
b7bfa98a50 | ||
|
|
da41dcd5c9 | ||
|
|
0c27de102d | ||
|
|
54c75e20c9 | ||
|
|
3102770353 | ||
|
|
477ca97830 | ||
|
|
5b51adfc95 | ||
|
|
4ab16b5935 | ||
|
|
fe5ec8b0b4 | ||
|
|
58d8ad8a8c | ||
|
|
df5d755345 | ||
|
|
9a7a836eca | ||
|
|
4243fc9692 | ||
|
|
c999c97445 | ||
|
|
569f72508a | ||
|
|
d78f516afe | ||
|
|
6e4a373d26 | ||
|
|
2f644f5ba6 | ||
|
|
37c24d0ca7 | ||
|
|
9cdbd35e51 | ||
|
|
67e28c4655 | ||
|
|
591df8657a | ||
|
|
c708ea5911 | ||
|
|
a4ecfdca30 | ||
|
|
ac1fd7897c | ||
|
|
a02f992a25 | ||
|
|
630d3f362c | ||
|
|
6666424ff8 | ||
|
|
b0fc20cea6 | ||
|
|
f61dbd4fe7 | ||
|
|
f369d645b1 | ||
|
|
7148e653e5 | ||
|
|
bb5da93fcd | ||
|
|
d2d750e920 | ||
|
|
485161f42d | ||
|
|
67661c2fb0 | ||
|
|
dcb21f2cd0 | ||
|
|
9f03bbc8a1 | ||
|
|
b4ecdf7820 | ||
|
|
35cc358101 | ||
|
|
db23968a6f | ||
|
|
9efd950b9f | ||
|
|
08461492ee | ||
|
|
b2ccd3a878 | ||
|
|
9b8a382ea5 | ||
|
|
235eeedcda | ||
|
|
0cff92101c | ||
|
|
c44e039772 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ build
|
||||
examples
|
||||
*.bin
|
||||
*.ans
|
||||
|
||||
|
||||
@@ -1,11 +1,43 @@
|
||||
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 -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 new NXDN Sync Pattern Testing
|
||||
option(NXDN
|
||||
"Build with new NXDN Sync Pattern Testing Enabled" OFF)
|
||||
if (NXDN)
|
||||
add_definitions(-DNXDNTESTSYNC)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
|
||||
option(LZ
|
||||
"Build with new LimaZulu Requested NXDN Tweaks Enabled" OFF)
|
||||
if (LZ)
|
||||
add_definitions(-DLIMAZULUTWEAKS)
|
||||
endif ()
|
||||
|
||||
include(git_revision)
|
||||
git_describe(GIT_TAG)
|
||||
|
||||
@@ -14,7 +46,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 +70,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 |
181
examples/Example_Usage.md
Normal file
181
examples/Example_Usage.md
Normal file
@@ -0,0 +1,181 @@
|
||||
### 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 (1 and 2) . 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 (will need to specify wacn/sys/nac manually)
|
||||
-fx X2-TDMA
|
||||
```
|
||||
|
||||
## New -- Experimental 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 NXDN98 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 is purely set by your CPU/GPU, and also by other factors like using SDR++ server to connect to a SDR++ client, or RTL_TCP server to client, etc, so faster computers scan faster, and slower will scan slower, slower scans may require multiple duplicate entries into your scanner csv file if you make a really large one.
|
||||
|
||||
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
|
||||
`dsd-fme -ft -i rtl:0:154.9875M:26:-2:8:0:6020 `
|
||||
|
||||
```
|
||||
RTL-SDR options:
|
||||
WARNING! Old CLI Switch Handling has been depreciated in favor of rtl:<parms>
|
||||
Usage: rtl:dev:freq:gain:ppm:bw:sq:udp
|
||||
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 = 26)(0 = Hardware AGC, not recommended)
|
||||
ppm <num> RTL-SDR PPM Error (default = 0)
|
||||
bw <num> RTL-SDR VFO Bandwidth kHz (default = 12)(6, 8, 12, 24)
|
||||
sq <num> RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)
|
||||
udp <num> RTL-SDR UDP Remote Port (default = 6020)
|
||||
Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:12: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 (CQPSK) 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 CQPSK (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: CQPSK Phase 1 and Phase 2 Systems are 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, Rest Channels 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 will 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 will not work properly with RTL input method due to the internal handling of the RTL dongle, when using squelch, it will effectively stop all processing (including trunking/tuning) until signal is regained, but squelch is required on NXDN to prevent false sync patterns.
|
||||
|
||||
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: Experimental 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 dmr privacy key assertion over fid and svc bits
|
||||
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
|
||||
p - stop per call decoded wav files
|
||||
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)
|
||||
2 - Lockout Tuning/Playback of TG in Slot 2 (Current Session Only)
|
||||
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)
|
||||
u - Toggle Trunking Tuning to Private Calls (DMR T3, P25)
|
||||
d - Toggle Trunking Tuning to Data Calls (DMR T3)
|
||||
|
||||
```
|
||||
127
examples/Install_Notes.md
Normal file
127
examples/Install_Notes.md
Normal file
@@ -0,0 +1,127 @@
|
||||
## 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 22.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
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### Ubuntu 18.04/LM19/Buster Note:
|
||||
The above install.sh should now function on older system types. You can elect to manually follow the steps down below. Do NOT Manually build and install ITPP 4.3.1 on older systems, it is currently not wanting to build on Ubuntu 18.04 and Linux Mint 19. Install it from the repository instead.
|
||||
|
||||
## 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.
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
## Headless
|
||||
|
||||
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
|
||||
|
||||
```
|
||||
Optional 'Virtual Sinks' for routing audio from SDR++ or GQRX, Media Players, etc. into DSD-FME
|
||||
|
||||
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.
|
||||
|
||||
```
|
||||
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 @@
|
||||
ChannelNumber(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 @@
|
||||
ChannelNumber(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 Number(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, BP, 10-char Hytera BP only
|
||||
2,70
|
||||
1,123
|
||||
100,70
|
||||
12,48713912656
|
||||
672560,254
|
||||
|
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
|
||||
|
40
examples/trunking.sh
Normal file
40
examples/trunking.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#example trunking sh scripts (SDR++ and RTL Input) -T = trunking
|
||||
#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:26:-2:8:0:6020 -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:26:-2:12:0:6020 -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:26:-2:12:0:6020 -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:26:-2:8:0:6020 -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:26:-2:24:0:6020 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#NXDN48 Trunking with Channel Map (Custom Channels > 800)
|
||||
#dsd-fme -fi -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans
|
||||
#NOTE! NXDN Trunking will not work correctly with the RTL input method
|
||||
|
||||
#NXDN96 Trunking with Channel Map (Custom Channels > 800)
|
||||
#dsd-fme -fn -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans
|
||||
#NOTE! NXDN Trunking will not work correctly with the RTL input method
|
||||
|
||||
#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
|
||||
|
||||
#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>
|
||||
@@ -47,14 +58,11 @@
|
||||
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
//OSS support
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
#include <pulse/simple.h> //PULSE AUDIO
|
||||
#include <pulse/error.h> //PULSE AUDIO
|
||||
|
||||
#define SAMPLE_RATE_IN 48000 //48000
|
||||
#define SAMPLE_RATE_OUT 48000 //8000,
|
||||
#define SAMPLE_RATE_OUT 8000 //8000,
|
||||
|
||||
#ifdef USE_RTLSDR
|
||||
#include <rtl-sdr.h>
|
||||
@@ -193,7 +201,6 @@ typedef struct
|
||||
int audio_in_type;
|
||||
char audio_out_dev[1024];
|
||||
int audio_out_fd;
|
||||
int audio_out_fdR; //right channel audio for OSS hack
|
||||
SNDFILE *audio_out_file;
|
||||
SF_INFO *audio_out_file_info;
|
||||
|
||||
@@ -328,12 +335,12 @@ typedef struct
|
||||
float trunk_hangtime; //hangtime in seconds before tuning back to CC
|
||||
|
||||
int scanner_mode; //experimental -- use the channel map as a conventional scanner, quicker tuning, but no CC
|
||||
|
||||
|
||||
//csv import filenames
|
||||
char group_in_file[1024];
|
||||
char lcn_in_file[1024];
|
||||
char chan_in_file[1024];
|
||||
char key_in_file[1024];
|
||||
char key_in_file[1024];
|
||||
//end import filenames
|
||||
|
||||
//reverse mute
|
||||
@@ -358,8 +365,8 @@ typedef struct
|
||||
//Trunking - Tune Data Calls
|
||||
uint8_t trunk_tune_data_calls;
|
||||
|
||||
//OSS audio - slot preference
|
||||
uint8_t slot_preference;
|
||||
//Trunking - Tune Enc Calls (P25 only on applicable grants with svc opts)
|
||||
uint8_t trunk_tune_enc_calls;
|
||||
|
||||
//'DSP' Format Output
|
||||
uint8_t use_dsp_output;
|
||||
@@ -540,8 +547,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 time slot
|
||||
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 +563,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 +651,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,20 +663,28 @@ 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];
|
||||
|
||||
//dmr manufacturer branding and sub_branding (i.e., Motorola and Con+)
|
||||
char dmr_branding[20];
|
||||
char dmr_branding_sub[80];
|
||||
char dmr_branding[99];
|
||||
char dmr_branding_sub[99];
|
||||
|
||||
//Remus DMR End Call Alert Beep
|
||||
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
||||
@@ -733,6 +750,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"
|
||||
|
||||
@@ -783,7 +820,7 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void openMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
|
||||
void openWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void openWavOutFileL (dsd_opts * opts, dsd_state * state);
|
||||
void openWavOutFileR (dsd_opts * opts, dsd_state * state);
|
||||
void openWavOutFileR (dsd_opts * opts, dsd_state * state);
|
||||
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state);
|
||||
void openSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
||||
@@ -836,8 +873,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 +882,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 +900,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 +923,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);
|
||||
|
||||
@@ -913,6 +957,7 @@ uint8_t ComputeCrc5Bit(uint8_t * DMRData);
|
||||
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData);
|
||||
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData);
|
||||
|
||||
|
||||
//new simplified dmr functions
|
||||
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
|
||||
void dmr_data_sync (dsd_opts * opts, dsd_state * state);
|
||||
|
||||
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,6 +773,7 @@ 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
|
||||
|
||||
50
src/dmr_bs.c
50
src/dmr_bs.c
@@ -114,7 +114,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//disabled for dmr_cach testing
|
||||
tact_okay = 0;
|
||||
if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1;
|
||||
if (tact_okay != 1) goto END;
|
||||
if (tact_okay != 1) goto END; //when going to end for bad tact or emb, consider using getdibit or skipdibit to 'stash' dibits and get better return on next sync pattern? in data particularly
|
||||
|
||||
|
||||
internalslot = state->currentslot = tact_bits[1];
|
||||
@@ -189,13 +189,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
|
||||
//embedded link control
|
||||
if(internalslot == 0 && vc1 > 1 && vc1 < 7) //grab on vc1 values 2-5 B C D and E
|
||||
if(internalslot == 0 && vc1 > 1 && vc1 < 7) //grab on vc1 values 2-5 B C D and E (F for Single/RC)
|
||||
{
|
||||
state->dmr_embedded_signalling[internalslot][vc1-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->dmr_embedded_signalling[internalslot][vc1-1][i*2+1] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
if(internalslot == 1 && vc2 > 1 && vc2 < 7) //grab on vc2 values 2-5 B C D and E
|
||||
if(internalslot == 1 && vc2 > 1 && vc2 < 7) //grab on vc2 values 2-5 B C D and E (F for Single/RC)
|
||||
{
|
||||
state->dmr_embedded_signalling[internalslot][vc2-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->dmr_embedded_signalling[internalslot][vc2-1][i*2+1] = (1 & dibit); // bit 0
|
||||
@@ -263,7 +263,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR ");
|
||||
|
||||
|
||||
vc1 = 1;
|
||||
|
||||
//close MBEout file - slot 1
|
||||
@@ -333,7 +333,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
else sprintf (polarity, "%s", "-");
|
||||
|
||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC%d ", polarity, light, state->dmr_color_code, vc);
|
||||
|
||||
|
||||
if (internalslot == 0 && vc1 == 6)
|
||||
{
|
||||
//process embedded link control
|
||||
@@ -361,25 +361,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
// if ( opts->audio_in_type == 5 && internalslot == 0 && state->dmrburstR != 16 ) //(OSS shim)
|
||||
// {
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
// }
|
||||
// if ( opts->audio_in_type == 5 && internalslot == 1 && state->dmrburstL != 16 ) //(OSS shim)
|
||||
// {
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
// }
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
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 alg refresh after vc6 ambe processing
|
||||
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
|
||||
@@ -396,7 +383,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
//'DSP' output to file
|
||||
if (opts->use_dsp_output == 1)
|
||||
@@ -416,13 +403,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
}
|
||||
|
||||
//reset err checks
|
||||
cach_err = 1;
|
||||
tact_okay = 0;
|
||||
emb_ok = 0;
|
||||
|
||||
|
||||
//reset emb components
|
||||
cc = 25;
|
||||
power = 9;
|
||||
@@ -474,12 +461,12 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
//run refresh if either slot had an active MI in it.
|
||||
if (state->payload_algid >= 0x21)
|
||||
if (state->payload_algid != 0)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
if (state->payload_algidR >= 0x21)
|
||||
if (state->payload_algidR != 0)
|
||||
{
|
||||
state->currentslot = 1;
|
||||
dmr_alg_refresh (opts, state);
|
||||
@@ -520,7 +507,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
};
|
||||
//add time to mirror printFrameSync
|
||||
time_t now;
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
@@ -565,7 +552,8 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//decode and correct tact and compare
|
||||
if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1;
|
||||
if (tact_okay != 1) goto END;
|
||||
if (tact_okay != 1) goto END;
|
||||
|
||||
|
||||
internalslot = state->currentslot = tact_bits[1];
|
||||
|
||||
@@ -624,7 +612,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
if ( strcmp (sync, DMR_BS_VOICE_SYNC) != 0)
|
||||
{
|
||||
sync_okay = 0;
|
||||
goto END;
|
||||
goto END;
|
||||
}
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
@@ -724,7 +712,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);
|
||||
@@ -741,12 +729,12 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
//run refresh if either slot had an active MI in it.
|
||||
if (state->payload_algid >= 0x21)
|
||||
if (state->payload_algid != 0)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
if (state->payload_algidR >= 0x21)
|
||||
if (state->payload_algidR != 0)
|
||||
{
|
||||
state->currentslot = 1;
|
||||
dmr_alg_refresh (opts, state);
|
||||
|
||||
574
src/dmr_csbk.c
574
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)
|
||||
@@ -615,13 +650,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 +722,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 +730,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 +741,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 +756,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 +822,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)
|
||||
{
|
||||
k = 0; //= 0
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " F%X Private or Data Call", pdflag);
|
||||
fprintf (stderr, " F%X Private or Data Call - ", 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][48+(group_tally*8)+(pd_b2*16)], 8);
|
||||
|
||||
//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) //now looking to see if any appended data was added
|
||||
{
|
||||
k = 0;
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " F%X Private or Data Call - ", pdflag2);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
pch[i+8] = state->cap_plus_csbk_bits[ts][i+56+(group_tally*8)+(pd_b2*16)]; //48
|
||||
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); //64
|
||||
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);
|
||||
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 +1039,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
|
||||
@@ -892,20 +1077,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 +1133,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;
|
||||
@@ -1031,60 +1221,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 +1349,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 +1364,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,16 +1372,22 @@ 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
|
||||
@@ -1157,8 +1396,11 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//rtl_udp
|
||||
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];
|
||||
//debug
|
||||
fprintf (stderr, " - Freq: %ld", state->trunk_chan_map[j+xpt_bank+1]);
|
||||
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+xpt_bank+1]);
|
||||
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
|
||||
@@ -1174,20 +1416,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 +1434,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
|
||||
|
||||
@@ -75,9 +75,10 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
if ( Hamming_7_4_decode (tact_bits) ) cach_okay = 1;
|
||||
else
|
||||
{
|
||||
|
||||
cach_okay = -1;
|
||||
SlotTypeOk = 0;
|
||||
goto END;
|
||||
goto END;
|
||||
}
|
||||
|
||||
state->currentslot = tact_bits[1];
|
||||
@@ -179,6 +180,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
dibit = (int)state->dmr_stereo_payload[65];
|
||||
}
|
||||
else state->dmr_stereo_payload[65] = dibit;
|
||||
|
||||
SlotType[8] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[9] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -253,14 +255,14 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
/* Check and correct the SlotType (apply Golay(20,8) FEC check) */
|
||||
|
||||
|
||||
// golay (20,8) hamming-weight of 6 reliably corrects at most 2 bit-errors
|
||||
if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1;
|
||||
else
|
||||
{
|
||||
SlotTypeOk = -1;
|
||||
|
||||
SlotTypeOk = 0;
|
||||
goto END;
|
||||
goto END;
|
||||
}
|
||||
|
||||
state->color_code = (SlotType[0] << 3) + (SlotType[1] << 2) +(SlotType[2] << 1) + (SlotType[3] << 0);
|
||||
@@ -343,6 +345,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
//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
|
||||
}
|
||||
|
||||
131
src/dmr_flco.c
131
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);
|
||||
@@ -377,7 +361,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 +387,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 ");
|
||||
@@ -549,7 +533,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
END_FLCO:
|
||||
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 +889,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 +907,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);
|
||||
|
||||
@@ -239,9 +239,9 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
// if (irr_err == 0)
|
||||
// {
|
||||
// if (sbrc_hex == 0) ; //NULL
|
||||
// else if (sbrc_hex == 0x313) //sbrc_hex == 0x313 and 0x643 (cap+ things)
|
||||
// else if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0)
|
||||
// {
|
||||
// //Cap+ Site ID seems to fit here on samples I've seen with the alternate SB signalling
|
||||
// //Cap+ Site ID seems to fit here on samples I've seen with the alternate SB signalling, but no idea what signals that info and not the emb alg/key info
|
||||
// fprintf (stderr, "%s ", KYEL);
|
||||
// fprintf (stderr, "\n ");
|
||||
// fprintf (stderr, " Capacity Plus Site %d", cap_site);
|
||||
|
||||
@@ -166,7 +166,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||
|
||||
state->dmr_stereo_payload[i+66] = dibit;
|
||||
|
||||
@@ -176,7 +176,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
|
||||
// load the superframe to do embedded signal processing
|
||||
if(vc > 1) //grab on vc1 values 2-5 B C D and E
|
||||
if(vc > 1) //grab on vc1 values 2-5 B C D and E (F for Single/RC)
|
||||
{
|
||||
state->dmr_embedded_signalling[internalslot][vc-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->dmr_embedded_signalling[internalslot][vc-1][i*2+1] = (1 & dibit); // bit 0
|
||||
@@ -212,7 +212,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
power = EmbeddedSignalling[4];
|
||||
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
|
||||
}
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
@@ -296,7 +295,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (vc == 6)
|
||||
{
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
|
||||
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;
|
||||
|
||||
@@ -444,18 +444,17 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (state->audio_out_idx > opts->delay)
|
||||
{
|
||||
if (opts->audio_out_type == 5) //OSS
|
||||
// output synthesized speech to sound card
|
||||
if(opts->audio_out_type == 2)
|
||||
{
|
||||
//go F yourself PA
|
||||
}
|
||||
else
|
||||
{
|
||||
//OSS
|
||||
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
||||
//Test just sending it straight on since I think I've figured out the STDIN and RTL for Stereo
|
||||
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works.
|
||||
state->audio_out_idx = 0;
|
||||
}
|
||||
else if (opts->audio_out_type == 0)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL);
|
||||
state->audio_out_idx = 0;
|
||||
}
|
||||
else state->audio_out_idx = 0; //failsafe for audio_out == 0
|
||||
|
||||
|
||||
}
|
||||
@@ -479,18 +478,15 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
||||
if (state->audio_out_idxR > opts->delay)
|
||||
{
|
||||
// output synthesized speech to sound card
|
||||
if (opts->audio_out_type == 5) //OSS
|
||||
if(opts->audio_out_type == 2)
|
||||
{
|
||||
//go F yourself PA
|
||||
}
|
||||
else
|
||||
{
|
||||
//OSS
|
||||
result = write (opts->audio_out_fdR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2));
|
||||
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works.
|
||||
state->audio_out_idxR = 0;
|
||||
}
|
||||
else if (opts->audio_out_type == 0)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL);
|
||||
state->audio_out_idxR = 0;
|
||||
}
|
||||
else state->audio_out_idxR = 0; //failsafe for audio_out == 0
|
||||
|
||||
}
|
||||
|
||||
@@ -545,6 +541,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)
|
||||
{
|
||||
@@ -562,7 +561,6 @@ openAudioInDevice (dsd_opts * opts)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strncmp(opts->audio_in_dev, "tcp", 3) == 0)
|
||||
{
|
||||
opts->audio_in_type = 8;
|
||||
@@ -572,13 +570,13 @@ openAudioInDevice (dsd_opts * opts)
|
||||
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 open TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strncmp(opts->audio_in_dev, "udp", 3) == 0)
|
||||
{
|
||||
opts->audio_in_type = 6;
|
||||
@@ -603,10 +601,25 @@ openAudioInDevice (dsd_opts * opts)
|
||||
{
|
||||
opts->audio_in_type = 0;
|
||||
}
|
||||
else if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
|
||||
//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 = 5;
|
||||
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;
|
||||
@@ -654,11 +667,9 @@ openAudioInDevice (dsd_opts * opts)
|
||||
|
||||
}
|
||||
//open pulse audio if no bin or wav
|
||||
else //seems this condition is never met
|
||||
else
|
||||
{
|
||||
//opts->audio_in_type = 5; //not sure if this works or needs to openPulse here
|
||||
fprintf(stderr, "Error, couldn't open input file.\n");
|
||||
exit(1);
|
||||
opts->audio_in_type = 0; //not sure if this works or needs to openPulse here
|
||||
}
|
||||
}
|
||||
if (opts->split == 1)
|
||||
|
||||
@@ -283,8 +283,8 @@ 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)
|
||||
//disabling again, causing issues with trunking
|
||||
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);
|
||||
@@ -347,7 +347,7 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||
|
||||
valid = 0;
|
||||
|
||||
//disabling again, causing issues with trunking P25
|
||||
//disabling again, causing issues with trunking
|
||||
if (state->synctype == 0 && opts->p25_trunk == 1)
|
||||
{
|
||||
// Use the P25 heuristics if available
|
||||
|
||||
@@ -34,7 +34,7 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
|
||||
}
|
||||
|
||||
char * getDateF(void) {
|
||||
char datename[80]; //32-bit needs this to be 80
|
||||
char datename[120]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
|
||||
@@ -231,10 +231,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
|
||||
|
||||
@@ -1276,7 +1276,122 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef NXDNTESTSYNC //use experimental sync detection based on multiple factors
|
||||
|
||||
//NXDN FSW sync and handling - testing with more exact syncs patterns
|
||||
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
||||
{
|
||||
strncpy (synctest10, (synctest_p - 9), 10); //FSW only
|
||||
strncpy (synctest19, (synctest_p - 18), 19); //Preamble + FSW
|
||||
|
||||
//Using Hard Coded Sync Strings with variations for the areas where the symbol
|
||||
//error will occur due to the demodulation issues internally
|
||||
|
||||
//Preamble plus FSW, proceed right away
|
||||
if (
|
||||
|
||||
(strcmp (synctest19, "3131133313131331131") == 0 )
|
||||
|| (strcmp (synctest19, "3131133313331331131") == 0 )
|
||||
|| (strcmp (synctest19, "3131133313131331111") == 0 )
|
||||
|| (strcmp (synctest19, "3131133313331331111") == 0 )
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->lastsynctype = 28;
|
||||
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n +PANDF ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest19);
|
||||
return (28);
|
||||
}
|
||||
else if (
|
||||
|
||||
(strcmp (synctest19, "1313311133131331131") == 0 )
|
||||
|| (strcmp (synctest19, "1313311133331331131") == 0 )
|
||||
|| (strcmp (synctest19, "1313311133131331111") == 0 )
|
||||
|| (strcmp (synctest19, "1313311133331331111") == 0 )
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->lastsynctype = 29;
|
||||
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n -PANDF ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest19);
|
||||
return (29);
|
||||
}
|
||||
|
||||
else if (
|
||||
(strcmp (synctest10, "3131331131") == 0 )
|
||||
|| (strcmp (synctest10, "3331331131") == 0 )
|
||||
|| (strcmp (synctest10, "3131331111") == 0 )
|
||||
|| (strcmp (synctest10, "3331331111") == 0 )
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
if (state->lastsynctype == 28)
|
||||
{
|
||||
state->lastsynctype = 28;
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n +FSW ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest10);
|
||||
return (28);
|
||||
}
|
||||
|
||||
state->lastsynctype = 28;
|
||||
|
||||
|
||||
}
|
||||
|
||||
else if (
|
||||
|
||||
(strcmp (synctest10, "1313113313") == 0 )
|
||||
|| (strcmp (synctest10, "1113113313") == 0 )
|
||||
|| (strcmp (synctest10, "1313113333") == 0 )
|
||||
|| (strcmp (synctest10, "1113113333") == 0 )
|
||||
|
||||
)
|
||||
{
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
|
||||
if (state->lastsynctype == 29)
|
||||
{
|
||||
state->lastsynctype = 29;
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, "\n -FSW ");
|
||||
// if (opts->payload == 1)
|
||||
// fprintf (stderr, " %s \n", synctest10);
|
||||
return (29);
|
||||
}
|
||||
state->lastsynctype = 29;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else //use current 'more stable' NXDN Sync pattern detection
|
||||
|
||||
//NXDN FSW sync and handling - moved to very bottom of sync stack for falsing sanity
|
||||
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
||||
{
|
||||
@@ -1286,30 +1401,33 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
//Preamble plus FSW, proceed right away
|
||||
if ( (strncmperr (synctest19, NXDN_PANDFSW, 19, 1) == 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 = 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;
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->lastsynctype = 29;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
||||
// if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
||||
// fprintf (stderr, " %s ", synctest19);
|
||||
return (29);
|
||||
}
|
||||
|
||||
else if ( (strncmperr (synctest10, NXDN_FSW, 10, 1) == 0) )
|
||||
{
|
||||
state->carrier = 1;
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
@@ -1317,7 +1435,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
|
||||
@@ -1326,7 +1445,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
else if ( (strncmperr (synctest10, INV_NXDN_FSW, 10, 1) == 0) )
|
||||
{
|
||||
state->carrier = 1;
|
||||
// state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
@@ -1334,7 +1453,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 +1462,95 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
} // t >= 10
|
||||
|
||||
if (exitflag == 1)
|
||||
|
||||
368
src/dsd_main.c
368
src/dsd_main.c
@@ -52,7 +52,7 @@ char * FM_banner[9] = {
|
||||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗",
|
||||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝",
|
||||
" 'Aero' Edition v2.0.0-64-gbd94f83 Windows 32-bit RC5 "
|
||||
" "
|
||||
};
|
||||
|
||||
int comp (const void *a, const void *b)
|
||||
@@ -77,36 +77,6 @@ void
|
||||
noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
// // experimental conventional frequency scanner mode
|
||||
// if (opts->scanner_mode == 1)
|
||||
// {
|
||||
|
||||
// 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
|
||||
|
||||
//experimental conventional frequency scanner mode
|
||||
if (opts->scanner_mode == 1 && ( (time(NULL) - state->last_cc_sync_time) > opts->trunk_hangtime))
|
||||
{
|
||||
@@ -187,6 +157,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
|
||||
}
|
||||
|
||||
@@ -196,7 +168,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_payload_p = state->dibit_buf + 200;
|
||||
memset (state->dmr_payload_buf, 0, sizeof (int) * 200);
|
||||
//dmr buffer end
|
||||
|
||||
|
||||
//close MBE out files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
@@ -234,6 +206,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 +318,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 +332,18 @@ 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
|
||||
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 +357,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 +375,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 +391,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,12 +423,11 @@ initOpts (dsd_opts * opts)
|
||||
opts->p25status = 0;
|
||||
opts->p25tg = 0;
|
||||
opts->scoperate = 15;
|
||||
sprintf (opts->audio_in_dev, "/dev/dsp");
|
||||
sprintf (opts->audio_in_dev, "pulse");
|
||||
opts->audio_in_fd = -1;
|
||||
|
||||
sprintf (opts->audio_out_dev, "/dev/dsp");
|
||||
sprintf (opts->audio_out_dev, "pulse");
|
||||
opts->audio_out_fd = -1;
|
||||
opts->audio_out_fdR = -1;
|
||||
|
||||
opts->split = 0;
|
||||
opts->playoffset = 0;
|
||||
@@ -527,10 +519,10 @@ initOpts (dsd_opts * opts)
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->dmr_mono = 0;
|
||||
opts->dmr_stereo = 1;
|
||||
opts->aggressive_framesync = 1;
|
||||
|
||||
opts->audio_in_type = 5;
|
||||
opts->audio_out_type = 5;
|
||||
opts->aggressive_framesync = 1; //more aggressive to combat wonk wonk voice decoding
|
||||
//see if initializing these values causes issues elsewhere, if so, then disable.
|
||||
opts->audio_in_type = 0; //this was never initialized, causes issues on rPI 64 (bullseye) if not initialized
|
||||
opts->audio_out_type = 0; //this was never initialized, causes issues on rPI 64 (bullseye) if not initialized
|
||||
|
||||
opts->lrrp_file_output = 0;
|
||||
|
||||
@@ -547,7 +539,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,13 +580,10 @@ initOpts (dsd_opts * opts)
|
||||
//Trunking - Tune Data Calls
|
||||
opts->trunk_tune_data_calls = 0; //disabled by default
|
||||
|
||||
opts->dPMR_next_part_of_superframe = 0;
|
||||
//Trunking - Tune Encrypted Calls (P25 only on applicable grants with svc opts)
|
||||
opts->trunk_tune_enc_calls = 1; //enabled by default
|
||||
|
||||
//OSS audio - Slot Preference
|
||||
//slot preference is used during OSS audio playback to
|
||||
//prefer one tdma voice slot over another when both are playing back
|
||||
//this is a fix to cygwin stuttering when both slots have voice
|
||||
opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
||||
opts->dPMR_next_part_of_superframe = 0;
|
||||
|
||||
//dsp structured file
|
||||
opts->dsp_out_file[0] = 0;
|
||||
@@ -827,7 +816,7 @@ initState (dsd_state * state)
|
||||
state->p25_cc_is_tdma = 2; //init on 2, TSBK NET_STS will set 0, TDMA NET_STS will set 1. //used to determine if we need to change symbol rate when cc hunting
|
||||
|
||||
//experimental symbol file capture read throttle
|
||||
state->symbol_throttle = 100; //throttle speed
|
||||
state->symbol_throttle = 0; //throttle speed
|
||||
state->use_throttle = 0; //only use throttle if set to 1
|
||||
|
||||
state->p2_scramble_offset = 0;
|
||||
@@ -837,6 +826,7 @@ initState (dsd_state * state)
|
||||
state->p25_chan_iden = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
state->p25_chan_tdma[i] = -1; //0, or -1
|
||||
state->p25_chan_type[i] = 0;
|
||||
state->p25_trans_off[i] = 0;
|
||||
state->p25_chan_spac[i] = 0;
|
||||
@@ -866,6 +856,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 +872,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;
|
||||
@@ -900,10 +899,10 @@ initState (dsd_state * state)
|
||||
//initialize unified dmr pdu 'superframe'
|
||||
memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf));
|
||||
memset (state->data_header_valid, 0, sizeof(state->data_header_valid));
|
||||
|
||||
|
||||
//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_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
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 +920,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
|
||||
@@ -947,18 +947,18 @@ 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");
|
||||
printf (" -i <device> Audio input device (default is /dev/dsp)\n");
|
||||
printf (" pulse for pulse audio \n");
|
||||
printf (" -i <device> Audio input device (default is pulse audio)\n");
|
||||
printf (" - for piped stdin\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");
|
||||
@@ -966,11 +966,8 @@ usage ()
|
||||
printf (" filename.wav for 48K/1 wav files (SDR++, GQRX)\n");
|
||||
printf (" filename.wav -s 96000 for 96K/1 wav files (DSDPlus)\n");
|
||||
printf (" (Use single quotes '/directory/audio file.wav' when directories/spaces are present)\n");
|
||||
// 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");
|
||||
printf (" -o <device> Audio output device (default is /dev/dsp)\n");
|
||||
printf (" null for no audio output\n");
|
||||
printf (" pulse for pulse audio \n");
|
||||
printf (" -o <device> Audio output device (default is pulse audio)(null for no audio output)\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");
|
||||
@@ -986,7 +983,6 @@ usage ()
|
||||
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 ("\n");
|
||||
printf ("RTL-SDR options:\n");
|
||||
printf (" WARNING! Old CLI Switch Handling has been depreciated in favor of rtl:<parms>\n");
|
||||
@@ -998,10 +994,10 @@ usage ()
|
||||
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 (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf ("\n");
|
||||
printf ("Decoder options:\n");
|
||||
printf (" -fa Legacy Auto Detection (old methods default)\n");
|
||||
printf (" -fa Legacy Auto Detection 8k/1 (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");
|
||||
@@ -1058,8 +1054,7 @@ usage ()
|
||||
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 (" (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 (" -4 Force DMR Privacy Key over FID and SVC bits \n");
|
||||
printf ("\n");
|
||||
printf (" Trunking Options:\n");
|
||||
printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n");
|
||||
@@ -1082,8 +1077,8 @@ usage ()
|
||||
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 ("\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:0:6020 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
||||
printf ("\n");
|
||||
exit (0);
|
||||
}
|
||||
@@ -1142,7 +1137,6 @@ if (opts->audio_in_type == 0)
|
||||
|
||||
if (opts->audio_out_type == 0)
|
||||
{
|
||||
// openPulseInput(opts); //test to see if we still randomly hang up in ncurses and tcp input if we open this and leave it opened
|
||||
openPulseOutput(opts);
|
||||
}
|
||||
|
||||
@@ -1269,9 +1263,8 @@ main (int argc, char **argv)
|
||||
}
|
||||
//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);
|
||||
fprintf (stderr, "Github Build Version: %s \n", GIT_TAG);
|
||||
fprintf (stderr,"MBElib version %s\n", versionstr);
|
||||
|
||||
initOpts (&opts);
|
||||
initState (&state);
|
||||
@@ -1280,7 +1273,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:zi: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)
|
||||
{
|
||||
opterr = 0;
|
||||
switch (c)
|
||||
@@ -1292,7 +1285,7 @@ main (int argc, char **argv)
|
||||
opts.call_alert = 1;
|
||||
break;
|
||||
|
||||
//Free'd up switches include
|
||||
//Free'd up switches include z
|
||||
//make sure to put a colon : after each if they need an argument
|
||||
//or remove colon if no argument required
|
||||
|
||||
@@ -1301,10 +1294,11 @@ main (int argc, char **argv)
|
||||
opts.p25_trunk = 0; //turn off trunking mode if user enabled it
|
||||
break;
|
||||
|
||||
case 'k': //NXDN multi-key loader
|
||||
case 'k': //multi-key loader
|
||||
strncpy(opts.key_in_file, optarg, 1023);
|
||||
opts.key_in_file[1023] = '\0';
|
||||
csvKeyImport(&opts, &state);
|
||||
state.keyloader = 1;
|
||||
break;
|
||||
|
||||
case 'Q': //'DSP' Structured Output file for OKDMRlib
|
||||
@@ -1324,13 +1318,6 @@ main (int argc, char **argv)
|
||||
opts.use_dsp_output = 1;
|
||||
break;
|
||||
|
||||
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 > 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':
|
||||
@@ -1450,17 +1437,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':
|
||||
@@ -1540,8 +1519,7 @@ main (int argc, char **argv)
|
||||
case 'F':
|
||||
opts.aggressive_framesync = 0;
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
//fprintf (stderr,"DMR Stereo Aggressive Resync Disabled!\n");
|
||||
fprintf (stderr, "Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n");
|
||||
fprintf (stderr, "Relax P25 Phase 2 MAC_SIGNAL CRC Pass/Fail\n");
|
||||
fprintf (stderr, "Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
|
||||
fprintf (stderr, "Relax NXDN SACCH/FACCH/CAC/F2U CRC Pass/Fail\n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
@@ -1568,7 +1546,7 @@ main (int argc, char **argv)
|
||||
// fprintf (stderr,"Writing mbe data temporarily disabled!\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'c': //now is symbol capture bin output like FME Lite
|
||||
strncpy(opts.symbol_out_file, optarg, 1023);
|
||||
opts.symbol_out_file[1023] = '\0';
|
||||
fprintf (stderr,"Writing + Appending symbol capture to file %s\n", opts.symbol_out_file);
|
||||
@@ -1619,12 +1597,12 @@ main (int argc, char **argv)
|
||||
opts.frame_dpmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
opts.frame_ysf = 0;
|
||||
opts.pulse_digi_rate_out = 48000; // /dev/dsp does need this set to 48000 to properly process the upsampling
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 1; //switching in 'stereo' for 'mono'
|
||||
opts.dmr_mono = 0;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 1;
|
||||
state.dmr_stereo = 0;
|
||||
//opts.setmod_bw = 7000;
|
||||
// opts.setmod_bw = 7000;
|
||||
sprintf (opts.output_name, "Legacy Auto");
|
||||
}
|
||||
else if (optarg[0] == 'd')
|
||||
@@ -1828,7 +1806,6 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_rate_out = 24000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
sprintf (opts.output_name, "DMR Stereo");
|
||||
|
||||
fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
|
||||
}
|
||||
else if (optarg[0] == 't')
|
||||
@@ -1907,8 +1884,7 @@ main (int argc, char **argv)
|
||||
// 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");
|
||||
|
||||
fprintf (stderr,"Decoding only DMR Mono. \nUsing DMR Stereo or XDMA is highly encouraged.\n");
|
||||
}
|
||||
else if (optarg[0] == 'm')
|
||||
{
|
||||
@@ -2118,14 +2094,12 @@ main (int argc, char **argv)
|
||||
{
|
||||
opts.audio_in_type = 8;
|
||||
state.audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing
|
||||
fprintf (stderr, "TCP Connection Success!\n");
|
||||
// openAudioInDevice(&opts); //do this to see if it makes it work correctly
|
||||
}
|
||||
else
|
||||
{
|
||||
opts.audio_in_type = 5;
|
||||
opts.audio_in_type = 0;
|
||||
fprintf (stderr, "TCP Connection Failure - Using Pulse Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2207,137 +2181,61 @@ main (int argc, char **argv)
|
||||
|
||||
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;
|
||||
fprintf (stderr, "RTL Support not enabled/compiled, falling back to Pulse Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
opts.audio_in_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//doesn't work correctly, so just going to reroute to /dev/dsp instead
|
||||
//still need to work out why I can't use this
|
||||
//issues with samples received, may be using UDP DGRAMS incorrectly, incorrect procedure?
|
||||
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;
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
//also still needs err handling
|
||||
opts.udp_sockfd = UDPBind(opts.udp_hostname, opts.udp_portno);
|
||||
opts.audio_in_type = 6;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
fprintf (stderr, "OSS Input %s.\n", opts.audio_in_dev);
|
||||
opts.audio_in_fd = open (opts.audio_in_dev, O_RDWR);
|
||||
if (opts.audio_in_fd == -1)
|
||||
{
|
||||
fprintf (stderr, "Error, couldn't open %s\n", opts.audio_in_dev);
|
||||
opts.audio_out = 0;
|
||||
}
|
||||
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl reset error \n");
|
||||
}
|
||||
fmt = speed;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl speed error \n");
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl stereo error \n");
|
||||
}
|
||||
fmt = AFMT_S16_LE;
|
||||
if (ioctl (opts.audio_in_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl setfmt error \n");
|
||||
}
|
||||
|
||||
opts.audio_in_type = 5; //5 will become OSS input type
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_in_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
|
||||
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_in_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
fprintf (stderr, "OSS Output %s.\n", opts.audio_out_dev);
|
||||
opts.audio_out_fd = open (opts.audio_out_dev, O_RDWR); //O_WRONLY
|
||||
opts.audio_out_fdR = open (opts.audio_out_dev, O_RDWR);
|
||||
if (opts.audio_out_fd == -1)
|
||||
{
|
||||
fprintf (stderr, "Error, couldn't open #1 %s\n", opts.audio_out_dev);
|
||||
opts.audio_out = 0;
|
||||
exit(1);
|
||||
}
|
||||
sprintf (opts.audio_out_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
}
|
||||
|
||||
if (opts.audio_out_fdR == -1)
|
||||
{
|
||||
fprintf (stderr, "Error, couldn't open #2 %s\n", opts.audio_out_dev);
|
||||
opts.audio_out = 0;
|
||||
exit(1);
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl reset error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl reset error \n");
|
||||
}
|
||||
fmt = speed;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl speed error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl speed error \n");
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl stereo error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl stereo error \n");
|
||||
}
|
||||
fmt = AFMT_S16_LE;
|
||||
if (ioctl (opts.audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl setfmt error \n");
|
||||
}
|
||||
if (ioctl (opts.audio_out_fdR, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
fprintf (stderr, "ioctl setfmt error \n");
|
||||
}
|
||||
|
||||
opts.audio_out_type = 5; //5 will become OSS output type
|
||||
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_out_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "pa", 2) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "pulse", 5) == 0))
|
||||
@@ -2363,15 +2261,14 @@ main (int argc, char **argv)
|
||||
opts.playoffsetR = 0;
|
||||
opts.delay = 0;
|
||||
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 == 5) openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
|
||||
{
|
||||
openWavOutFile (&opts, &state);
|
||||
}
|
||||
else
|
||||
{
|
||||
openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
|
||||
{
|
||||
opts.split = 1;
|
||||
@@ -2404,13 +2301,16 @@ main (int argc, char **argv)
|
||||
|
||||
if (opts.playfiles == 1)
|
||||
{
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
openPulseOutput(&opts); //need to open it up for output
|
||||
state.aout_gain = 25; //BUGFIX: No audio output when playing back .amb/.imb files
|
||||
playMbeFiles (&opts, &state, argc, argv);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
liveScanner (&opts, &state);
|
||||
liveScanner (&opts, &state);
|
||||
}
|
||||
|
||||
cleanupAndExit (&opts, &state);
|
||||
|
||||
@@ -141,13 +141,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
int x;
|
||||
|
||||
//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));
|
||||
|
||||
int preempt = 0; //TDMA dual voice slot preemption(when using OSS output)
|
||||
|
||||
|
||||
for (i = 0; i < 88; i++)
|
||||
{
|
||||
imbe_d[i] = 0;
|
||||
@@ -218,17 +215,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);
|
||||
@@ -305,6 +301,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
//see if we need to hash a value larger than 16-bits
|
||||
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 +310,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)
|
||||
}
|
||||
@@ -432,6 +431,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
//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 +440,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)
|
||||
}
|
||||
@@ -606,14 +608,6 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
//end reverse mute test
|
||||
|
||||
//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)
|
||||
{
|
||||
opts->audio_out = 0;
|
||||
preempt = 1;
|
||||
if (opts->payload == 0) fprintf (stderr, " *MUTED*");
|
||||
}
|
||||
|
||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
||||
{
|
||||
state->debug_audio_errors += state->errs2;
|
||||
@@ -670,14 +664,6 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
//end reverse mute test
|
||||
|
||||
//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)
|
||||
{
|
||||
opts->audio_out = 0;
|
||||
preempt = 1;
|
||||
if (opts->payload == 0) fprintf (stderr, " *MUTED*");
|
||||
}
|
||||
|
||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
||||
{
|
||||
state->debug_audio_errorsR += state->errs2R;
|
||||
@@ -732,12 +718,6 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
|
||||
if (preempt == 1)
|
||||
{
|
||||
opts->audio_out = 1;
|
||||
preempt = 0;
|
||||
}
|
||||
|
||||
//reset audio out flag for next repitition
|
||||
if (strcmp(mode, "B") == 0) opts->audio_out = 1;
|
||||
//restore flag for null output type
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
116
src/dsd_symbol.c
116
src/dsd_symbol.c
@@ -82,24 +82,35 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
}
|
||||
|
||||
// Read the new sample from the input
|
||||
if(opts->audio_in_type == 0) //pulse audio
|
||||
if(opts->audio_in_type == 0) // && state->menuopen == 0 still not quite working
|
||||
{
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
}
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
//look into how processAudio handles playback, not sure if latency issues, or garbage sample values crash pulse when written
|
||||
// if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767)
|
||||
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample != 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
//playback is wrong, depends on samples_per_symbol, maybe make a buffer and store first?
|
||||
//making buffer might also fix raw audio monitoring as well
|
||||
if (opts->wav_out_file_raw[0] != 0) //if set for recording sample raw files
|
||||
{
|
||||
//writeRawSample (opts, state, sample);
|
||||
}
|
||||
|
||||
else if (opts->audio_in_type == 5) //OSS
|
||||
{
|
||||
read (opts->audio_in_fd, &sample, 2);
|
||||
}
|
||||
|
||||
//stdin only, wav files moving to new number
|
||||
else if (opts->audio_in_type == 1) //won't work in windows, needs posix pipe (mintty)
|
||||
else if (opts->audio_in_type == 1)
|
||||
{
|
||||
result = sf_read_short(opts->audio_in_file, &sample, 1);
|
||||
if(result == 0)
|
||||
{
|
||||
//cleanupAndExit (opts, state);
|
||||
sf_close(opts->audio_in_file);
|
||||
cleanupAndExit (opts, state);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //send zero sample
|
||||
}
|
||||
}
|
||||
//wav files, same but using seperate value so we can still manipulate ncurses menu
|
||||
@@ -111,15 +122,10 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
|
||||
sf_close(opts->audio_in_file);
|
||||
fprintf (stderr, "\n\nEnd of .wav file.\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);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //send zero sample
|
||||
|
||||
}
|
||||
}
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -136,33 +142,62 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//tcp socket input from SDR++
|
||||
else if (opts->audio_in_type == 8)
|
||||
{
|
||||
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
|
||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//UDP Socket input...not working correct. Reads samples, but no sync
|
||||
// else if (opts->audio_in_type == 6)
|
||||
// {
|
||||
else if (opts->audio_in_type == 6)
|
||||
{
|
||||
//I think this doesn't get the entire dgram when we run sf_read_short on the udp dgram
|
||||
// result = sf_read_short(opts->udp_file_in, &sample, 1);
|
||||
result = sf_read_short(opts->udp_file_in, &sample, 1);
|
||||
// if (sample != 0)
|
||||
// fprintf (stderr, "Result = %d Sample = %d \n", result, sample);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (opts->use_cosine_filter)
|
||||
{
|
||||
@@ -381,12 +416,6 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
}
|
||||
#endif
|
||||
|
||||
//test throttle on wav input files
|
||||
if (opts->audio_in_type == 2)
|
||||
{
|
||||
if (state->use_throttle == 1) usleep(.003); //very environment specific, tuning to cygwin
|
||||
}
|
||||
|
||||
//read op25/fme symbol bin files
|
||||
if (opts->audio_in_type == 4)
|
||||
{
|
||||
@@ -403,23 +432,14 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
useconds_t stime = state->symbol_throttle;
|
||||
if (state->use_throttle == 1)
|
||||
{
|
||||
// usleep(stime);
|
||||
usleep(.003); //very environment specific, tuning to cygwin
|
||||
usleep(stime);
|
||||
}
|
||||
//fprintf(stderr, "%d", state->symbolc);
|
||||
if( feof(opts->symbolfile) )
|
||||
{
|
||||
// opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
||||
opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
||||
fclose(opts->symbolfile);
|
||||
fprintf (stderr, "\n\nEnd of .bin file\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);
|
||||
openPulseInput(opts);
|
||||
}
|
||||
|
||||
//assign symbol/dibit values based on modulation type
|
||||
|
||||
@@ -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));
|
||||
@@ -119,6 +121,14 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
check = check | trellis_buf[84+i]; //80
|
||||
}
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, " FACCH");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||
|
||||
@@ -130,24 +140,23 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||
{
|
||||
fprintf (stderr, "[%02X]", m_data[i]);
|
||||
}
|
||||
fprintf (stderr, " - %03X %03X", check, crc);
|
||||
// fprintf (stderr, " - %03X %03X", check, crc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//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 +185,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,16 +238,30 @@ 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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, " SACCH NSF");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n SACCH NSF ");
|
||||
@@ -246,8 +269,12 @@ 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, " CRC ERR - %02X %02X", check, crc);
|
||||
}
|
||||
|
||||
//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 +284,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 +295,21 @@ 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);
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, " SACCH SF%d", sf);
|
||||
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;
|
||||
@@ -304,22 +340,24 @@ 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", crc, check);
|
||||
// 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 +379,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 +428,17 @@ 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];
|
||||
if (crc != check)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
if (type == 0) fprintf (stderr, " UDCH");
|
||||
if (type == 1) fprintf (stderr, " FACCH2");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
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,57 @@ 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, " 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 +524,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 +559,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 +568,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 +600,320 @@ 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)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (crc == check) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
||||
else if (opts->aggressive_framesync == 0) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
||||
|
||||
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, " CRC ERR - %02X %02X", check, crc);
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
if (crc[0] != check[0] || crc[1] != check[1])
|
||||
{
|
||||
if (type == 0) fprintf (stderr, " UDCH2");
|
||||
if (type == 1) fprintf (stderr, " FACCH3");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
// 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 +922,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 +1050,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);
|
||||
}
|
||||
1754
src/nxdn_element.c
1754
src/nxdn_element.c
File diff suppressed because it is too large
Load Diff
263
src/nxdn_frame.c
263
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 amoount 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 || 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,112 @@ 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
|
||||
|
||||
//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,16 +447,22 @@ 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 (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
}
|
||||
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);
|
||||
|
||||
if (voice)
|
||||
{
|
||||
@@ -301,26 +470,29 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
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
|
||||
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 +506,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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -299,8 +309,8 @@ 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);
|
||||
@@ -317,8 +327,8 @@ 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);
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
@@ -328,6 +353,7 @@ 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
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -335,6 +361,7 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +371,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 +379,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,6 +412,9 @@ 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))
|
||||
{
|
||||
@@ -396,7 +437,8 @@ 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
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -404,6 +446,7 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,6 @@ 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;
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
@@ -630,10 +626,6 @@ 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;
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
|
||||
@@ -711,12 +703,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 +730,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 +828,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);
|
||||
@@ -846,16 +850,6 @@ void processP2 (dsd_opts * opts, dsd_state * state)
|
||||
//process DUID will run through all collected frames and handle them appropriately
|
||||
process_P2_DUID (opts, 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;
|
||||
}
|
||||
state->p2_is_lcch = 0;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
190
src/p25p2_vpdu.c
190
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++)
|
||||
{
|
||||
@@ -144,7 +145,8 @@ 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
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -152,6 +154,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,7 +182,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++)
|
||||
{
|
||||
@@ -225,7 +229,8 @@ 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
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -233,6 +238,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,7 +273,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;
|
||||
@@ -341,7 +348,8 @@ 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
|
||||
|
||||
}
|
||||
@@ -351,6 +359,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
rtl_udp_tune (opts, state, 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
|
||||
}
|
||||
}
|
||||
@@ -380,12 +389,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,6 +422,9 @@ 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))
|
||||
{
|
||||
@@ -433,6 +459,7 @@ 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
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -440,6 +467,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,11 +499,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++)
|
||||
{
|
||||
@@ -519,7 +551,8 @@ 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
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -527,6 +560,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
rtl_udp_tune (opts, state, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -558,20 +592,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 +642,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)
|
||||
{
|
||||
@@ -636,7 +706,8 @@ 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
|
||||
@@ -645,6 +716,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
rtl_udp_tune (opts, state, 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
|
||||
}
|
||||
}
|
||||
@@ -680,18 +752,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 +808,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)
|
||||
{
|
||||
@@ -763,7 +885,8 @@ 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
|
||||
@@ -773,6 +896,7 @@ 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;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
}
|
||||
@@ -807,11 +931,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;
|
||||
@@ -880,6 +1008,7 @@ 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
|
||||
@@ -889,6 +1018,7 @@ 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;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 8; //break loop
|
||||
}
|
||||
}
|
||||
@@ -916,10 +1046,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,6 +1083,9 @@ 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))
|
||||
{
|
||||
@@ -973,7 +1119,8 @@ 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
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -981,6 +1128,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
rtl_udp_tune (opts, state, freq1);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1218,7 +1366,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);
|
||||
|
||||
@@ -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;
|
||||
@@ -206,6 +209,9 @@ 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)
|
||||
{
|
||||
@@ -236,12 +242,14 @@ 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;
|
||||
if (state->currentslot == 1) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
fprintf (stderr, " MAC_ACTIVE ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
process_MAC_VPDU(opts, state, 1, SMAC);
|
||||
@@ -280,6 +288,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;
|
||||
@@ -433,6 +444,9 @@ 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)
|
||||
@@ -484,12 +498,14 @@ 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;
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
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