mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef07b48540 | ||
|
|
db67a8b227 | ||
|
|
4e2c4577d5 | ||
|
|
e581c96560 | ||
|
|
f3505269d0 | ||
|
|
20ccdbbced | ||
|
|
fc2fb99502 | ||
|
|
143c560958 | ||
|
|
d122d7e935 | ||
|
|
d0f9bb4bad | ||
|
|
ac752029bd | ||
|
|
5b994f5129 | ||
|
|
ec7d7c24a5 | ||
|
|
1d49481f2d | ||
|
|
7ca8cb421c | ||
|
|
4eb44b3c67 | ||
|
|
e16e4b61fc | ||
|
|
fbd04fa869 | ||
|
|
7f9b852f36 | ||
|
|
f5a7ab2b77 | ||
|
|
ffe6098fb8 | ||
|
|
157ca8c043 | ||
|
|
b722e43a3a | ||
|
|
2ba9953d33 | ||
|
|
bb2199ee84 | ||
|
|
4efec4e4ef | ||
|
|
12cf9aa80f | ||
|
|
e5a42dbb11 | ||
|
|
67eaeadc03 |
@@ -1,4 +1,4 @@
|
||||
project(dsd-fme)
|
||||
project(dsd-fme-lite)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
@@ -38,24 +38,24 @@ list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c")
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||
ADD_EXECUTABLE(dsd-fme-lite ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme-lite ${LIBS})
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS dsd-fme-lite DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# man page
|
||||
find_program(HELP2MAN_FOUND help2man)
|
||||
if (HELP2MAN_FOUND)
|
||||
add_custom_command(TARGET dsd-fme POST_BUILD
|
||||
add_custom_command(TARGET dsd-fme-lite POST_BUILD
|
||||
COMMAND help2man
|
||||
ARGS -n "Digital Speech Decoder"
|
||||
--version-string=${GIT_TAG}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1
|
||||
--no-info
|
||||
$<TARGET_FILE:dsd-fme>
|
||||
$<TARGET_FILE:dsd-fme-lite>
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
|
||||
12
README.md
12
README.md
@@ -1,8 +1,11 @@
|
||||
## 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"), [SDTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), 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, etc, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users, so please understand that this version may not compile or run correctly in other environments.
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDTRunk](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, 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 and others for the many hours of wav samples submitted 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. Thank you everybody.
|
||||
|
||||
@@ -16,11 +19,11 @@ Click image below for video of current DMR/P25 trunking capabilities.
|
||||
|
||||
## Information
|
||||
|
||||
See the example folder for information on cloning, installing, example usage, and trunking features.
|
||||
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").
|
||||
|
||||
## Notice
|
||||
|
||||
The pulseaudio branch will hearby be for legacy use as the promotion of this version to main branch will obsolete that branch. Any pre-compiled windows versions found in the release link will be considered legacy as well, and do not feature trunking support and have older handling for some other modes. Users are free to use those, but keep in mind the use case syntax may and will be different between versions. Furthermore, any wiki articles made for windows users may contain outdated information for building the pulseaudio branch, please adjust any information found in those accordingly.
|
||||
The pulseaudio branch has been deleted in favor of the new main branch which also uses Pulse Audio. Users moving to the main branch should review the help file and example usage files for changes in syntax. Users can download the last pulse audio branch version from the release link if they prefer the older version. Any pre-compiled windows versions found in the release link will be considered legacy as well, and do not feature trunking support and have older handling for some other modes. Users are free to use those, but keep in mind the use case syntax may and will be different between versions. Furthermore, any wiki articles with 'auto intstall scripts' made for windows users may contain outdated information for building the deleted pulseaudio branch, please adjust any information found in those accordingly.
|
||||
|
||||
## License
|
||||
Copyright (C) 2010 DSD Author
|
||||
@@ -37,5 +40,4 @@ GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#! /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
|
||||
@@ -1,67 +0,0 @@
|
||||
#! /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-fme.png
BIN
dsd-fme.png
Binary file not shown.
|
Before Width: | Height: | Size: 706 KiB |
BIN
dsd-fme2.png
BIN
dsd-fme2.png
Binary file not shown.
|
Before Width: | Height: | Size: 315 KiB |
BIN
dsd-fme3.png
BIN
dsd-fme3.png
Binary file not shown.
|
Before Width: | Height: | Size: 692 KiB |
@@ -108,7 +108,7 @@ Trunking Note1: All samples above can also be run with the RTL input method and
|
||||
|
||||
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 using channel 0 as the control channel will hardset that frequency to the control channel. 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) 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.
|
||||
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
|
||||
@@ -121,7 +121,7 @@ For Connect Plus, enumerate your list from 1 to the last channel and add the fre
|
||||
|
||||
Currently uncoded/unknown DMR trunking systems include Hytera XPT.
|
||||
|
||||
Trunking Note4: NXDN Trunking may also require a channel map file, depending on the system. If it uses a custom range (above 800), then channels will need to be mapped. If channels do not require mapping (have channels below 800) but you are not tuning properly, then please use a channel_map and please report the issue in the issues along with the channels you are tuning and the actual rf frequency so corrections can be made.
|
||||
Trunking Note4: NXDN TRunking will require a channel map. Please see the example folder for an appropriate channel map. ~NXDN Trunking may also require a channel map file, depending on the system. If it uses a custom range (above 800), then channels will need to be mapped. If channels do not require mapping (have channels below 800) but you are not tuning properly, then please use a channel_map and please report the issue in the issues along with the channels you are tuning and the actual rf frequency so corrections can be made.~
|
||||
|
||||
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.
|
||||
|
||||
@@ -138,18 +138,21 @@ 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/cqpsk 10/4 (everything but phase 2 signal)
|
||||
M - toggle c4fm/cqpsk 8/3 (phase 2 tdma control channel)
|
||||
t - toggle trunking (needs either rtl input, or rigctl setup at CLI)
|
||||
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)
|
||||
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)
|
||||
|
||||
```
|
||||
@@ -1,3 +1,7 @@
|
||||
## Notice
|
||||
|
||||
These should not be followed for the 'lite' branch
|
||||
|
||||
## How to clone and build this branch
|
||||
|
||||
### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer:
|
||||
@@ -71,6 +75,9 @@ 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.
|
||||
|
||||
```
|
||||
|
||||
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), value(dec), load any single keys as key 0
|
||||
0,23466
|
||||
1,12345
|
||||
2,32700
|
||||
63,32767
|
||||
|
@@ -47,11 +47,14 @@
|
||||
|
||||
#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 8000 //8000,
|
||||
#define SAMPLE_RATE_OUT 48000 //8000,
|
||||
|
||||
#ifdef USE_RTLSDR
|
||||
#include <rtl-sdr.h>
|
||||
@@ -190,6 +193,7 @@ 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;
|
||||
|
||||
@@ -199,8 +203,10 @@ typedef struct
|
||||
int playoffsetR;
|
||||
char mbe_out_dir[1024];
|
||||
char mbe_out_file[1024];
|
||||
char mbe_out_fileR[1024]; //second slot on a TDMA system
|
||||
char mbe_out_path[2048]; //1024
|
||||
FILE *mbe_out_f;
|
||||
FILE *mbe_out_fR; //second slot on a TDMA system
|
||||
FILE *symbol_out_f;
|
||||
float audio_gain;
|
||||
float audio_gainR;
|
||||
@@ -214,6 +220,7 @@ typedef struct
|
||||
char szNumbers[1024]; //**tera 10/32/64 char str
|
||||
short int symbol_out;
|
||||
short int mbe_out; //flag for mbe out, don't attempt fclose more than once
|
||||
short int mbe_outR; //flag for mbe out, don't attempt fclose more than once
|
||||
SNDFILE *wav_out_f;
|
||||
SNDFILE *wav_out_fR;
|
||||
SNDFILE *wav_out_raw;
|
||||
@@ -323,7 +330,8 @@ typedef struct
|
||||
//csv import filenames
|
||||
char group_in_file[1024];
|
||||
char lcn_in_file[1024];
|
||||
char chan_in_file[1024];
|
||||
char chan_in_file[1024];
|
||||
char key_in_file[1024];
|
||||
//end import filenames
|
||||
|
||||
//reverse mute
|
||||
@@ -339,12 +347,22 @@ typedef struct
|
||||
//Trunking - Use Group List as Allow List
|
||||
uint8_t trunk_use_allow_list;
|
||||
|
||||
//Trunking - Tune Group Calls
|
||||
uint8_t trunk_tune_group_calls;
|
||||
|
||||
//Trunking - Tune Private Calls
|
||||
uint8_t trunk_tune_private_calls;
|
||||
|
||||
//Trunking - Tune Data Calls...why?
|
||||
//Trunking - Tune Data Calls
|
||||
uint8_t trunk_tune_data_calls;
|
||||
|
||||
//OSS audio - slot preference
|
||||
uint8_t slot_preference;
|
||||
|
||||
//'DSP' Format Output
|
||||
uint8_t use_dsp_output;
|
||||
char dsp_out_file[2048];
|
||||
|
||||
} dsd_opts;
|
||||
|
||||
typedef struct
|
||||
@@ -498,15 +516,16 @@ typedef struct
|
||||
|
||||
unsigned int dmr_fid;
|
||||
unsigned int dmr_so;
|
||||
unsigned int dmr_flco;
|
||||
|
||||
unsigned int dmr_fidR;
|
||||
unsigned int dmr_soR;
|
||||
unsigned int dmr_flcoR;
|
||||
|
||||
char slot1light[8];
|
||||
char slot2light[8];
|
||||
int directmode;
|
||||
|
||||
char dmr_branding[99];
|
||||
int dmr_stereo_payload[144]; //load up 144 dibit buffer for every single DMR TDMA frame
|
||||
uint8_t data_header_blocks[2]; //collect number of blocks to follow from data header per slot
|
||||
uint8_t data_header_padding[2]; //collect number of padding octets in last block per slot
|
||||
@@ -518,8 +537,9 @@ 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*4]; //CSBK Cap+ FL initial and appended block bit storage
|
||||
uint8_t data_block_crc_valid[2][25]; //flag each individual block as good crc on confirmed data
|
||||
char dmr_embedded_signalling[2][6][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
|
||||
char dmr_embedded_signalling[2][7][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
|
||||
|
||||
char dmr_cach_fragment[4][17]; //unsure of size, will need to check/verify
|
||||
int dmr_cach_counter; //counter for dmr_cach_fragments 0-3; not sure if needed yet.
|
||||
@@ -536,8 +556,9 @@ typedef struct
|
||||
|
||||
dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame;
|
||||
|
||||
unsigned char * dpmr_caller_id;
|
||||
unsigned char * dpmr_target_id;
|
||||
char dpmr_caller_id[20];
|
||||
char dpmr_target_id[20];
|
||||
|
||||
int dpmr_color_code;
|
||||
|
||||
short int dmr_stereo; //need state variable for upsample function
|
||||
@@ -562,6 +583,8 @@ typedef struct
|
||||
unsigned long long int p2_wacn;
|
||||
unsigned long long int p2_sysid;
|
||||
unsigned long long int p2_cc; //p1 NAC
|
||||
unsigned long long int p2_siteid;
|
||||
unsigned long long int p2_rfssid;
|
||||
int p2_hardset; //flag for checking whether or not P2 wacn and sysid are hard set by user
|
||||
int p2_scramble_offset; //offset counter for scrambling application
|
||||
int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS)
|
||||
@@ -631,11 +654,15 @@ typedef struct
|
||||
uint32_t nxdn_location_sys_code;
|
||||
uint16_t nxdn_location_site_code;
|
||||
|
||||
//multi-key array for nxdn keys
|
||||
unsigned long long int rkey_array[0x1FF];
|
||||
|
||||
//dmr late entry mi
|
||||
uint64_t late_entry_mi_fragment[2][7][3];
|
||||
|
||||
//char dmr_branding[25]; //may need higher value?
|
||||
char dmr_branding_sub[25];
|
||||
//dmr manufacturer branding and sub_branding (i.e., Motorola and Con+)
|
||||
char dmr_branding[20];
|
||||
char dmr_branding_sub[80];
|
||||
|
||||
//Remus DMR End Call Alert Beep
|
||||
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
||||
@@ -739,13 +766,16 @@ int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_a
|
||||
void skipDibit (dsd_opts * opts, dsd_state * state, int count);
|
||||
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||
void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||
void saveAmbe2450DataR (dsd_opts * opts, dsd_state * state, char *ambe_d); //tdma slot 2
|
||||
void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||
int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||
int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||
void openMbeInFile (dsd_opts * opts, dsd_state * state);
|
||||
void closeMbeOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
|
||||
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);
|
||||
@@ -858,7 +888,7 @@ int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24]);
|
||||
void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output);
|
||||
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3]);
|
||||
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77]);
|
||||
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32]);
|
||||
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd);
|
||||
|
||||
//Reed Solomon (12,9) functions
|
||||
void rs_12_9_calc_syndrome(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome);
|
||||
@@ -871,6 +901,8 @@ uint16_t ComputeCrcCCITT(uint8_t * DMRData);
|
||||
uint16_t ComputeCrcCCITT16d(const uint8_t buf[], uint8_t len);
|
||||
uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask);
|
||||
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);
|
||||
@@ -906,10 +938,14 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state);
|
||||
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, char ambe_fr[4][24], char ambe_fr2[4][24], char ambe_fr3[4][24]);
|
||||
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state);
|
||||
|
||||
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
|
||||
void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power);
|
||||
|
||||
//DMR FEC/CRC from Boatbod - OP25
|
||||
bool Hamming17123(uint8_t* d);
|
||||
uint8_t crc8(uint8_t bits[], unsigned int len);
|
||||
bool crc8_ok(uint8_t bits[], unsigned int len);
|
||||
uint8_t crc7(uint8_t bits[], unsigned int len);
|
||||
|
||||
//LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
void LFSR(dsd_state * state);
|
||||
@@ -998,6 +1034,7 @@ unsigned long long int edacs_bch (unsigned long long int message);
|
||||
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvLCNImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvChanImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvKeyImport(dsd_opts * opts, dsd_state * state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -1023,7 +1060,7 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload);
|
||||
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME
|
||||
int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
|
||||
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
|
||||
unsigned long long int isch_lookup (unsigned long long int isch); //isch map lookup
|
||||
int isch_lookup (unsigned long long int isch); //isch map lookup
|
||||
int bd_bridge (int payload[196], uint8_t decoded[12]); //bridge to Michael Ossmann Block De-interleaver and 1/2 rate trellis decoder
|
||||
int crc16_lb_bridge (int payload[190], int len);
|
||||
int crc12_xb_bridge (int payload[190], int len);
|
||||
|
||||
16
rebuild.sh
16
rebuild.sh
@@ -1,16 +0,0 @@
|
||||
#! /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
|
||||
|
||||
62
src/bptc.c
62
src/bptc.c
@@ -134,6 +134,13 @@ const uint8_t DeInterleaveReverseChannelBptc[32] =
|
||||
24, 9, 26, 11, 28, 13, 30, 15
|
||||
};
|
||||
|
||||
const uint8_t DeInterleaveReverseChannelBptcPlacement[32] =
|
||||
{
|
||||
0, 16, 1, 17, 2, 18, 3, 19,
|
||||
4, 20, 5, 21, 6, 22, 7, 23,
|
||||
8, 24, 9, 25, 10, 26, 11, 27,
|
||||
12, 28, 13, 29, 14, 30, 15, 31
|
||||
};
|
||||
|
||||
/* Functions ----------------------------------------------------------------*/
|
||||
|
||||
@@ -192,18 +199,10 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
|
||||
}
|
||||
}
|
||||
|
||||
/* R(0) to R(2) may be used to transport some
|
||||
* Restricted Access System (RAS) information,
|
||||
* So save these three bytes before reset all of them
|
||||
* See patent US 2013/0288643 A1 */
|
||||
R[0] = DataMatrix[0][2]; /* Save R(0) */
|
||||
R[1] = DataMatrix[0][1]; /* Save R(1) */
|
||||
R[2] = DataMatrix[0][0]; /* Save R(2) */
|
||||
|
||||
/* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */
|
||||
DataMatrix[0][0] = 0; /* R(2) */
|
||||
DataMatrix[0][1] = 0; /* R(1) */
|
||||
DataMatrix[0][2] = 0; /* R(0) */
|
||||
// DataMatrix[0][0] = 0; /* R(2) */
|
||||
// DataMatrix[0][1] = 0; /* R(1) */
|
||||
// DataMatrix[0][2] = 0; /* R(0) */
|
||||
|
||||
/* Init the Hamming (15,11,3) library
|
||||
* Not needed because it has already been done
|
||||
@@ -356,6 +355,14 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
|
||||
}
|
||||
}
|
||||
|
||||
/* R(0) to R(2) may be used to transport some
|
||||
* Restricted Access System (RAS) information,
|
||||
* So save these three bits after hamming correction
|
||||
* See patent US 2013/0288643 A1 */
|
||||
R[0] = DataMatrix[0][2]; /* Save R(0) */
|
||||
R[1] = DataMatrix[0][1]; /* Save R(1) */
|
||||
R[2] = DataMatrix[0][0]; /* Save R(2) */
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors */
|
||||
return HammingIrrecoverableErrorNb;
|
||||
} /* End BPTC_196x96_Extract_Data() */
|
||||
@@ -498,33 +505,38 @@ uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDat
|
||||
* DMRDataExtracted[11..15] = Hamming data
|
||||
* DMRDataExtracted[16..31] = 16 bits of odd parity (to be checked)
|
||||
*
|
||||
* @param ParityCheckTypeOdd : 0 = Parity to check is even (used in Non-Reverse Channel Single Burst BPTC)
|
||||
* 1 = Parity to check is odd (used in Reverse Channel Single Burst BPTC)
|
||||
*
|
||||
* @return 0 = All is OK
|
||||
* Other = Error - Irrecoverable Hamming parity check error number
|
||||
*/
|
||||
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32])
|
||||
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t DataMatrix[32];
|
||||
uint8_t LineUncorrected[16];
|
||||
uint8_t LineCorrected[11];
|
||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||
uint32_t ParityCheckErrorNb = 0;
|
||||
uint32_t ParityCheckOddErrorNb = 0;
|
||||
uint32_t ParityCheckEvenErrorNb = 0;
|
||||
|
||||
//TODO: make this so we can load either rc interleave, or single burst interleave
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
DataMatrix[DeInterleaveReverseChannelBptc[i]] = InputInterleavedData[i] & 1;
|
||||
DataMatrix[DeInterleaveReverseChannelBptcPlacement[DeInterleaveReverseChannelBptc[i]]] = InputInterleavedData[i] & 1;
|
||||
}
|
||||
|
||||
/* Copy the entire input buffer to the output buffer */
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
DMRDataExtracted[i] = DataMatrix[i];
|
||||
DMRDataExtracted[i] = DataMatrix[i] & 1;
|
||||
}
|
||||
|
||||
/* Prepare the line to be corrected */
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
LineUncorrected[i] = DataMatrix[i];
|
||||
LineUncorrected[i] = DataMatrix[i] & 1;
|
||||
}
|
||||
|
||||
/* Apply Hamming (16,11,4) code correction */
|
||||
@@ -536,7 +548,7 @@ uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDat
|
||||
/* Copy the corrected content to the output buffer */
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
DMRDataExtracted[i] = LineCorrected[i];
|
||||
DMRDataExtracted[i] = LineCorrected[i] & 1;
|
||||
}
|
||||
|
||||
/* Check Parity bits */
|
||||
@@ -544,14 +556,24 @@ uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDat
|
||||
{
|
||||
/* Odd parity ==> If data = 1 then parity = 0
|
||||
* If data = 0 then parity = 1 */
|
||||
if(DMRDataExtracted[i] == DMRDataExtracted[i + 16]) ParityCheckErrorNb++;
|
||||
if((DMRDataExtracted[i] & 1) == (DMRDataExtracted[i + 16] & 1)) ParityCheckOddErrorNb++;
|
||||
if((DMRDataExtracted[i] & 1) != (DMRDataExtracted[i + 16] & 1)) ParityCheckEvenErrorNb++;
|
||||
}
|
||||
|
||||
//fprintf(stderr, "Hamming ERR=%u ; Parity ERR=%u", HammingIrrecoverableErrorNb, ParityCheckErrorNb);
|
||||
//fprintf(stderr, "Hamming ERR=%u ; Parity odd ERR=%u, Parity even ERR=%u, ", HammingIrrecoverableErrorNb, ParityCheckOddErrorNb, ParityCheckEvenErrorNb);
|
||||
|
||||
//fprintf(stderr, "Content =\n");
|
||||
//for(i = 0; i < 32; i++)
|
||||
//{
|
||||
// fprintf(stderr, "%u", DMRDataExtracted[i] & 1);
|
||||
// if((i == 15) || (i == 31)) fprintf(stderr, "\n");
|
||||
// else fprintf(stderr, "-");
|
||||
//}
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors +
|
||||
* the number of parity check error */
|
||||
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
||||
if(ParityCheckTypeOdd) return (HammingIrrecoverableErrorNb + ParityCheckOddErrorNb);
|
||||
else return (HammingIrrecoverableErrorNb + ParityCheckEvenErrorNb);
|
||||
|
||||
} /* End BPTC_16x2_Extract_Data() */
|
||||
|
||||
|
||||
136
src/dmr_block.c
136
src/dmr_block.c
@@ -51,7 +51,14 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0xD) //DD_HEAD
|
||||
{
|
||||
state->data_conf_data[slot] = 0;
|
||||
//The Response Requested (A) information element of the header shall be set to 0 for unconfirmed data and shall be set
|
||||
//to 1 for confirmed data. ETSI TS 102 361-3 V1.2.1 (2013-07) - 6.1.2
|
||||
if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit
|
||||
{
|
||||
state->data_conf_data[slot] = 1;
|
||||
}
|
||||
else state->data_conf_data[slot] = 0;
|
||||
|
||||
state->data_header_padding[slot] = dheader[7] & 0xF;
|
||||
state->data_header_blocks[slot] = ( (dheader[0] & 0x30) | ((dheader[1] & 0xF) >> 0) ); //what a pain MSB | LSB
|
||||
fprintf (stderr, "\n Short Data - Defined: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X",
|
||||
@@ -61,7 +68,14 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0xE) //SP_HEAD or R_HEAD
|
||||
{
|
||||
state->data_conf_data[slot] = 0;
|
||||
//The Response Requested (A) information element of the header shall be set to 0 for unconfirmed data and shall be set
|
||||
//to 1 for confirmed data. ETSI TS 102 361-3 V1.2.1 (2013-07) - 6.2.2
|
||||
if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit
|
||||
{
|
||||
state->data_conf_data[slot] = 1;
|
||||
}
|
||||
else state->data_conf_data[slot] = 0;
|
||||
|
||||
state->data_header_padding[slot] = dheader[7] & 0xF;
|
||||
state->data_header_blocks[slot] = ( (dheader[0] & 0x30) | ((dheader[1] & 0xF) >> 0) );
|
||||
fprintf (stderr, "\n Short Data - Raw or Precoded: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X",
|
||||
@@ -81,7 +95,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
//end collecting data header info
|
||||
|
||||
fprintf (stderr, "%s ", KMAG);
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
|
||||
if (state->data_header_sap[slot] == 0x4 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
@@ -247,11 +261,11 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
|
||||
//let user know the data header may have errors
|
||||
fprintf (stderr, "%s", KRED);
|
||||
if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good
|
||||
else if(IrrecoverableErrors == 0) fprintf(stderr, " (FEC OK)");
|
||||
else fprintf(stderr, " (FEC/CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "%s", KRED);
|
||||
// if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good
|
||||
// else if(IrrecoverableErrors == 0) fprintf(stderr, " (FEC OK)");
|
||||
// else fprintf(stderr, " (FEC/CRC ERR)");
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
|
||||
@@ -261,16 +275,17 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
int i, j, k;
|
||||
uint8_t lb = 0; //mbc last block
|
||||
uint8_t pf = 0; //mbc protect flag
|
||||
uint8_t is_conf_data = 0; //internal flag to see if type 1 blocks contain confirmed data crcs and serials
|
||||
// uint8_t is_conf_data = 0; //internal flag to see if type 1 blocks contain confirmed data crcs and serials
|
||||
uint8_t slot = state->currentslot;
|
||||
int blocks;
|
||||
uint8_t blockcounter = state->data_block_counter[slot];
|
||||
uint8_t block_num = state->data_header_blocks[slot];
|
||||
|
||||
//crc specific variables
|
||||
uint8_t len = 24; //len of completed message needing crc32 number of blocks*block_len - 12?
|
||||
uint8_t crclen = 32; //len of the crc32 (obviously)
|
||||
uint8_t start = 12; //starting position (+12 offset loaded up data header)
|
||||
uint8_t n = 12; //number of bytes per block
|
||||
// uint8_t len = 24;
|
||||
// uint8_t crclen = 32; //len of the crc32 (obviously)
|
||||
// uint8_t start = 12; //starting position (+12 offset loaded up data header)
|
||||
// uint8_t n = 12; //number of bytes per block
|
||||
|
||||
//TODO: CRC check on Header, Blocks and full frames as appropriate
|
||||
uint32_t CRCCorrect = 0;
|
||||
@@ -278,7 +293,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
uint32_t CRCExtracted = 0;
|
||||
uint32_t IrrecoverableErrors = 0;
|
||||
|
||||
uint8_t dmr_pdu_sf_bits[18*8*8]; //8 blocks at 18 bytes at 8 bits //just a large value to have plenty storage space
|
||||
uint8_t dmr_pdu_sf_bits[8*8*50]; //give plenty of space so we don't go oob
|
||||
|
||||
//MBC Header and Block CRC
|
||||
uint8_t mbc_crc_good[2]; //header and blocks crc pass/fail local storage
|
||||
@@ -293,7 +308,8 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
if (block_len == 0) block_len = 18;
|
||||
if (block_len > 24) block_len = 24;
|
||||
|
||||
//TODO: add CRC/FEC validation to each data header and each confirmed data block as well - type 1
|
||||
//WIP: CRC32 on Completed Message Working! CRC9 on 3/4 Working! CRC9 or 1/2 and 1 still need testing - type 1
|
||||
//may/will still fail on p_head data and blocks
|
||||
if (type == 1)
|
||||
{
|
||||
//type 1 data block, shuffle method
|
||||
@@ -312,8 +328,79 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
//time to send the completed 'superframe' to the DMR PDU message handler
|
||||
if (state->data_block_counter[slot] == state->data_header_blocks[slot])
|
||||
{
|
||||
//TODO: CRC32 on completed messages
|
||||
dmr_pdu (opts, state, block_len, state->dmr_pdu_sf[slot]);
|
||||
//CRC32 on completed messages
|
||||
for(i = 0, j = 0; i < (block_num * block_len); i++, j+=8)
|
||||
{
|
||||
dmr_pdu_sf_bits[j + 0] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 1] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 2] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 3] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 4] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 5] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 6] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 7] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
|
||||
|
||||
}
|
||||
|
||||
//sanity check to prevent a negative or zero block_num or sending a negative value into the bit array
|
||||
if (block_num < 1 || block_num == 0) block_num = 1;
|
||||
|
||||
CRCExtracted = 0;
|
||||
//extract crc from last block, apply to completed 'superframe' minus header
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
CRCExtracted = CRCExtracted << 1;
|
||||
CRCExtracted = CRCExtracted | (uint32_t)(dmr_pdu_sf_bits[i + (block_len * 8) * block_num - 32] & 1); //96
|
||||
}
|
||||
|
||||
//rearrage for ridiculously stupid CRC32 LSO/MSO ordering
|
||||
for(i = 0, j = 0; i < (block_num * block_len); i+=2, j+=16)
|
||||
{
|
||||
dmr_pdu_sf_bits[j + 0] = (state->dmr_pdu_sf[slot][i+1] >> 7) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 1] = (state->dmr_pdu_sf[slot][i+1] >> 6) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 2] = (state->dmr_pdu_sf[slot][i+1] >> 5) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 3] = (state->dmr_pdu_sf[slot][i+1] >> 4) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 4] = (state->dmr_pdu_sf[slot][i+1] >> 3) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 5] = (state->dmr_pdu_sf[slot][i+1] >> 2) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 6] = (state->dmr_pdu_sf[slot][i+1] >> 1) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 7] = (state->dmr_pdu_sf[slot][i+1] >> 0) & 0x01;
|
||||
|
||||
dmr_pdu_sf_bits[j + 8] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 9] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 10] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 11] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 12] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 13] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 14] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
|
||||
dmr_pdu_sf_bits[j + 15] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
|
||||
|
||||
//increment extra 2 bytes on each nth byte (depends on data type 1/2, 3/4, 1) if conf data
|
||||
if ( i == (block_len - 1) )
|
||||
{
|
||||
if (state->data_conf_data[slot] == 0) i+=2;
|
||||
}
|
||||
}
|
||||
|
||||
//confirmed working now!
|
||||
CRCComputed = (uint32_t)ComputeCrc32Bit(dmr_pdu_sf_bits, ( block_num * block_len * 8) - 32);
|
||||
|
||||
//if the CRC32 is correct, I think its fair to assume we don't need to worry about if the
|
||||
//individual CRC9s are correct on confirmed data blocks (but we can confirm now that they are all good)
|
||||
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
|
||||
|
||||
//test only running on good CRC or CRC/RAS bypass (aggressive_framesync)
|
||||
if (CRCCorrect || opts->aggressive_framesync == 0) dmr_pdu (opts, state, block_len, state->dmr_pdu_sf[slot]);
|
||||
|
||||
if (CRCCorrect) ; //print nothing
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "\n Slot %d - Multi Block PDU Message CRC32 ERR", slot+1);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
state->data_conf_data[slot] = 0; //flag off conf data flag
|
||||
state->data_header_format[slot] = 0; //zero out so we don't keep ascii printing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,6 +474,12 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
CRCCorrect = 1;
|
||||
IrrecoverableErrors = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//cspdu will only act on any fid/opcodes if good CRC to prevent falsing on control signalling
|
||||
dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors);
|
||||
@@ -398,7 +491,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
if (opts->payload == 1 && type == 1 && state->data_block_counter[slot] == state->data_header_blocks[slot])
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, "\n Multi Block PDU Superframe - Slot [%d]\n ", slot+1);
|
||||
fprintf (stderr, "\n Slot %d - Multi Block PDU Message\n ", slot+1);
|
||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
|
||||
@@ -407,6 +500,10 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
fprintf (stderr, "\n ");
|
||||
}
|
||||
}
|
||||
|
||||
//debug print
|
||||
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
@@ -414,7 +511,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
if (opts->payload == 1 && type == 2 && lb == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, "\n MBC Multi Block PDU Superframe - Slot [%d]\n ", slot+1);
|
||||
fprintf (stderr, "\n Slot %d - Multi Block Control Message\n ", slot+1);
|
||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
|
||||
@@ -459,4 +556,5 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
||||
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
|
||||
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));
|
||||
}
|
||||
109
src/dmr_bs.c
109
src/dmr_bs.c
@@ -41,6 +41,11 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t internalslot;
|
||||
uint8_t vc1;
|
||||
uint8_t vc2;
|
||||
|
||||
//assign as nonsensical numbers
|
||||
uint8_t cc = 25;
|
||||
uint8_t power = 9; //power and pre-emption indicator
|
||||
uint8_t lcss = 9;
|
||||
|
||||
//would be ideal to grab all dibits and break them into bits to pass to new data handler?
|
||||
uint8_t dummy_bits[196];
|
||||
@@ -189,13 +194,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 < 6) //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
|
||||
{
|
||||
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 < 6) //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
|
||||
{
|
||||
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
|
||||
@@ -265,6 +270,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
else fprintf (stderr,"Sync: -DMR ");
|
||||
|
||||
vc1 = 1;
|
||||
|
||||
//close MBEout file - slot 1
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
if (internalslot == 1)
|
||||
{
|
||||
@@ -276,6 +284,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
vc2 = 1;
|
||||
|
||||
//close MBEout file - slot 2
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
}
|
||||
dmr_data_sync (opts, state);
|
||||
skipcount++;
|
||||
@@ -294,9 +305,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? ");
|
||||
else if (emb_ok == 1)
|
||||
{
|
||||
uint8_t cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
uint8_t power = EmbeddedSignalling[4];
|
||||
uint8_t lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
power = EmbeddedSignalling[4];
|
||||
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
}
|
||||
|
||||
|
||||
@@ -312,12 +323,16 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
state->dmrburstL = 16;
|
||||
vc = vc1;
|
||||
sprintf (light, "%s", " [SLOT1] slot2 ");
|
||||
//open MBEout file - slot 1
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmrburstR = 16;
|
||||
vc = vc2;
|
||||
sprintf (light, "%s", " slot1 [SLOT2] ");
|
||||
//open MBEout file - slot 2
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
@@ -329,6 +344,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity
|
||||
dmr_sbrc (opts, state, power);
|
||||
}
|
||||
|
||||
if (internalslot == 1 && vc2 == 6)
|
||||
@@ -336,6 +353,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity
|
||||
dmr_sbrc (opts, state, power);
|
||||
}
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||
@@ -347,9 +366,22 @@ 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");
|
||||
@@ -369,12 +401,37 @@ 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)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 98 ", internalslot+1); //'98' is CACH designation value
|
||||
for (i = 0; i < 6; i++) //3 byte CACH
|
||||
{
|
||||
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", cach_byte);
|
||||
}
|
||||
fprintf (pFile, "\n%d 10 ", internalslot+1); //0x10 for voice burst
|
||||
for (i = 6; i < 72; i++) //33 bytes, no CACH
|
||||
{
|
||||
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
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;
|
||||
lcss = 9;
|
||||
|
||||
//Extra safeguards to break loop
|
||||
// if ( (vc1 > 7 && vc2 > 7) ) goto END;
|
||||
@@ -407,6 +464,10 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
state->errs2R = 0;
|
||||
state->errs2 = 0;
|
||||
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
//if we have a tact or emb err, then produce sync pattern/err message
|
||||
if (tact_okay != 1 || emb_ok != 1)
|
||||
{
|
||||
@@ -458,6 +519,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t cach_err = 0;
|
||||
uint8_t sync_okay = 1;
|
||||
|
||||
uint8_t internalslot;
|
||||
|
||||
char cachdata[25];
|
||||
int cachInterleave[24] =
|
||||
@@ -490,10 +552,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
}
|
||||
|
||||
@@ -521,7 +580,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
state->currentslot = tact_bits[1];
|
||||
internalslot = state->currentslot = tact_bits[1];
|
||||
|
||||
//Setup for first AMBE Frame
|
||||
|
||||
@@ -588,6 +647,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -610,6 +670,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+108] = dibit;
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -620,6 +681,26 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//'DSP' output to file
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 98 ", internalslot+1); //'98' is CACH designation value
|
||||
for (i = 0; i < 6; i++) //3 byte CACH
|
||||
{
|
||||
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", cach_byte);
|
||||
}
|
||||
fprintf (pFile, "\n%d 10 ", internalslot+1); //0x10 for "voice burst"
|
||||
for (i = 6; i < 72; i++) //33 bytes, no CACH
|
||||
{
|
||||
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
char polarity[3];
|
||||
char light[18];
|
||||
@@ -627,10 +708,14 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (light, "%s", " [SLOT1] slot2 ");
|
||||
//open MBEout file - slot 1
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (light, "%s", " slot1 [SLOT2] ");
|
||||
//open MBEout file - slot 2
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
@@ -652,7 +737,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
|
||||
//collect the mi fragment
|
||||
dmr_late_entry_mi_fragment (opts, state, 1, ambe_fr, ambe_fr2, ambe_fr3);
|
||||
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
654
src/dmr_csbk.c
654
src/dmr_csbk.c
@@ -37,14 +37,23 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
csbk_pf = ( (cs_pdu[1] & 0x80) >> 7);
|
||||
csbk = ((cs_pdu[0] & 0x3F) << 8) | cs_pdu[1]; //opcode and fid combo set
|
||||
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
if (csbk_fid != 0) state->dmr_mfid = csbk_fid;
|
||||
//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);
|
||||
|
||||
//TIII standard with fid of 0 - (opcodes in decimal)
|
||||
if (0 == 0) //some non-standard fid values (0x58 - tait, 0x68 - hytera, 0x10-motcapmax) also use a good chunk of these
|
||||
if (csbk_pf == 1) //check the protect flag, don't run if set
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "\n Protected Control Signalling Block(s)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (csbk_pf == 0) //okay to run
|
||||
{
|
||||
|
||||
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
if (csbk_fid != 0) state->dmr_mfid = csbk_fid;
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
//7.1.1.1.1 Channel Grant CSBK/MBC PDU
|
||||
@@ -138,18 +147,31 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
(stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
}
|
||||
|
||||
//Skip tuning private calls if private calls are disabled
|
||||
if (opts->trunk_tune_private_calls == 0 && csbk_o != 49) goto SKIPCALL;
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0 && csbk_o == 49) goto SKIPCALL;
|
||||
|
||||
//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)
|
||||
{
|
||||
if (opts->trunk_tune_data_calls == 1) csbk_o = 49;
|
||||
}
|
||||
|
||||
//Skip tuning private calls if private calls are disabled
|
||||
if (opts->trunk_tune_private_calls == 0 && csbk_o != 49) goto SKIPCALL;
|
||||
|
||||
//if not a data channel grant (only tuning to voice channel grants)
|
||||
if (csbk_o == 48 || csbk_o == 49 || csbk_o == 50 || csbk_o == 53) //48, 49, 50 are voice grants, 51 and 52 are data grants, 53 Duplex Private Voice, 54 Duplex Private Data
|
||||
{
|
||||
//TIII tuner fix if voice assignment occurs to the control channel itself,
|
||||
//then it may not want to resume tuning due to no framesync loss after call ends
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
opts->p25_is_tuned = 0;
|
||||
//zero out vc frequencies
|
||||
state->p25_vc_freq[0] = 0;
|
||||
state->p25_vc_freq[1] = 0;
|
||||
}
|
||||
|
||||
//shim in here for ncurses freq display when not trunking (playback, not live)
|
||||
if (opts->p25_trunk == 0 && freq != 0)
|
||||
{
|
||||
@@ -212,7 +234,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Move (C_MOVE) (TODO)");
|
||||
fprintf (stderr, " Move (C_MOVE) ");
|
||||
}
|
||||
|
||||
//Aloha
|
||||
@@ -350,10 +372,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Clear (P_CLEAR) (TODO)");
|
||||
fprintf (stderr, " Clear (P_CLEAR) ");
|
||||
}
|
||||
|
||||
//(P_PROTECT) - Could be a useful way of determining who is on the current timeslot p_kind 2
|
||||
//(P_PROTECT)
|
||||
if (csbk_o == 47)
|
||||
{
|
||||
//initial line break
|
||||
@@ -373,27 +395,6 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Target [%08d] - Source [%08d]", target, source);
|
||||
|
||||
//Illegally Parked is another way to say a private call is outbound on this channel
|
||||
//so, we can use this as a form of 'link control'
|
||||
if (p_kind == 2)
|
||||
{
|
||||
//don't set this if operating out of dmr mono or using call alert beep
|
||||
if (opts->dmr_mono == 0 && opts->call_alert == 0)
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->lasttg = target;
|
||||
state->lastsrc = source;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->lasttgR = target;
|
||||
state->lastsrcR = source;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 40) //0x28 //check to see if these are fid 0 only, or also in other manufacturer fids
|
||||
@@ -463,17 +464,19 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
n = 10;
|
||||
}
|
||||
|
||||
//disabled until this can be sorted/fleshed out by type, going to use aloha only for now
|
||||
|
||||
//honestly can't say that this is accurate, just a guess
|
||||
uint8_t is_capmax = 0; //capmax(mot) flag
|
||||
if (csbk_fid == 0x10)
|
||||
{
|
||||
n = 0;
|
||||
is_capmax = 1;
|
||||
opts->dmr_dmrla_is_set = 1;
|
||||
opts->dmr_dmrla_n = 0;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "CapMax ");
|
||||
}
|
||||
// uint8_t is_capmax = 0; //capmax(mot) flag
|
||||
// if (csbk_fid == 0x10)
|
||||
// {
|
||||
// n = 0;
|
||||
// is_capmax = 1;
|
||||
// opts->dmr_dmrla_is_set = 1;
|
||||
// opts->dmr_dmrla_n = 0;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "CapMax ");
|
||||
// }
|
||||
|
||||
if (opts->dmr_dmrla_is_set == 1) n = opts->dmr_dmrla_n;
|
||||
|
||||
@@ -497,87 +500,175 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
uint32_t parms2 = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
lpchannum = parms2 & 0xFFF; //7.2.19.7, for DSDPlus, this value is (lpchannum << 1) + 1;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
if (n != 0) fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d Cat: %s Cd: %d C+: %d", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
else fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d Cat: %s Cd: %d C+: %d", model_str, net, site, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
if (is_capmax) fprintf (stderr, " Capacity Max");
|
||||
//disabled until this can be sorted/fleshed out by type, going to use aloha only for now
|
||||
|
||||
//add string for ncurses terminal display, if not adjacent site info
|
||||
if (a_type != 6 && n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1);
|
||||
if (a_type != 6 && n == 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
|
||||
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
|
||||
//sprintf(state->dmr_branding_sub, "%s", "");
|
||||
// if (a_type == 2 || a_type == 7)
|
||||
// {
|
||||
// fprintf (stderr, "\n");
|
||||
// if (n != 0) fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d Cat: %s Cd: %d C+: %d", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
// else fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d Cat: %s Cd: %d C+: %d", model_str, net, site, par_str, lpchannum, (lpchannum << 1)+1 );
|
||||
// if (is_capmax) fprintf (stderr, " Capacity Max");
|
||||
|
||||
// //add string for ncurses terminal display, if not adjacent site info
|
||||
// if (a_type != 6 && n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1);
|
||||
// if (a_type != 6 && n == 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
// }
|
||||
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
|
||||
//fprintf (stderr, "\n SYSCODE: %016b", syscode);
|
||||
//fprintf (stderr, "\n SYSCODE: %04X", syscode);
|
||||
|
||||
}
|
||||
|
||||
if (csbk == 28)
|
||||
if (csbk_o == 28)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_AHOY (TODO)");
|
||||
fprintf (stderr, " C_AHOY ");
|
||||
}
|
||||
|
||||
if (csbk == 42)
|
||||
if (csbk_o == 42)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " P_MAINT (TODO)");
|
||||
fprintf (stderr, " P_MAINT ");
|
||||
}
|
||||
|
||||
if (csbk == 30)
|
||||
if (csbk_o == 30)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_ACKVIT (TODO)");
|
||||
fprintf (stderr, " C_ACKVIT ");
|
||||
}
|
||||
|
||||
if (csbk == 31)
|
||||
if (csbk_o == 31)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_RAND (TODO)");
|
||||
fprintf (stderr, " C_RAND ");
|
||||
}
|
||||
|
||||
//tier 2 csbks
|
||||
if (csbk_o == 4)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Unit to Unit Voice Service Request (UU_V_Req) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
}
|
||||
|
||||
if (csbk_o == 5)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Unit to Unit Voice Service Answer Response (UU_Ans_Req) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 7)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Channel Timing CSBK (CT_CSBK) ");
|
||||
}
|
||||
|
||||
if (csbk_o == 38)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Negative Acknowledgement Response (NACK_Rsp) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 56)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " BS Outbound Activation (BS_Dwn_Act) - ");
|
||||
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "Target [%d] - Source [%d] ", target, source);
|
||||
}
|
||||
|
||||
if (csbk_o == 61)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Preamble CSBK - ");
|
||||
uint8_t content = cs_pdu_bits[16];
|
||||
uint8_t gi = cs_pdu_bits[17];
|
||||
uint8_t res = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[18], 6);
|
||||
uint8_t blocks = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24], 8);
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
|
||||
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);
|
||||
}
|
||||
//end tier 2 csbks
|
||||
|
||||
}
|
||||
|
||||
//Capacity+ Section
|
||||
//Reworked Cap+ for Multi Block FL PDU and Private/Data Calls
|
||||
//experimental, but seems to be working well
|
||||
if (csbk_fid == 0x10)
|
||||
{
|
||||
//not quite sure how these tuning rules will go over
|
||||
//if they don't work so well, may just fall back to
|
||||
//a 'follow rest channel on no sync' only approach
|
||||
//Cap+ Channel Status PDU
|
||||
if (csbk_o == 0x3E)
|
||||
{
|
||||
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
|
||||
uint8_t slot = cs_pdu_bits[18];
|
||||
uint8_t rest_channel = cs_pdu[2] & 0xF; //0xF, or 0x1F?
|
||||
|
||||
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
|
||||
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 ch[8]; //one bit per channel
|
||||
uint8_t pch[8]; //private or data call channel bits
|
||||
uint8_t tg = 0;
|
||||
uint32_t tghex = 0; //combined all tgs for debug
|
||||
int i, j, k;
|
||||
|
||||
//tg and channel info for trunking purposes
|
||||
uint8_t t_tg[9];
|
||||
memset (t_tg, 0, sizeof(t_tg));
|
||||
|
||||
k = 0;
|
||||
//initialize group ch and private/data channel bit arrays
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
ch[i] = 0;
|
||||
pch[i] = 0;
|
||||
}
|
||||
|
||||
//treating FL as a form of LCSS
|
||||
if (fl != 1) //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];
|
||||
}
|
||||
else //appended block (fl1)
|
||||
{
|
||||
for (i = 0; i < 7*8; i++) state->cap_plus_csbk_bits[i+80] = cs_pdu_bits[i+24];
|
||||
}
|
||||
|
||||
if (rest_channel != state->dmr_rest_channel)
|
||||
{
|
||||
state->dmr_rest_channel = rest_channel;
|
||||
}
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
ch[i] = cs_pdu_bits[i+24];
|
||||
}
|
||||
|
||||
//assign to cc freq to follow during no sync
|
||||
if (state->trunk_chan_map[rest_channel] != 0)
|
||||
@@ -586,99 +677,302 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//set to always tuned
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
|
||||
fprintf (stderr, " Capacity Plus Channel Status - Rest Channel %d", rest_channel);
|
||||
|
||||
fprintf (stderr, "\n ");
|
||||
for (i = 0; i < 8; i++)
|
||||
fprintf (stderr, " Capacity Plus Channel Status - FL: %d TS: %d RS: %d - Rest Channel %d", fl, ts, res, rest_channel);
|
||||
if (fl == 1) fprintf (stderr, " - Appended Block");
|
||||
if (fl == 2) fprintf (stderr, " - Initial Block");
|
||||
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
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
fprintf (stderr, "Ch%d: ", i+1);
|
||||
if (ch[i] != 0)
|
||||
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
|
||||
}
|
||||
|
||||
//check for private/data calls
|
||||
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;
|
||||
|
||||
//first, check to see if we have a completed PDU
|
||||
if (fl != 2)
|
||||
{
|
||||
//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 != 0) //now looking to see if any appended data was added
|
||||
{
|
||||
tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[k*8+32], 8);
|
||||
fprintf (stderr, " %03d ", tg);
|
||||
//add values to trunking tg/channel potentials
|
||||
t_tg[i] = tg;
|
||||
k++;
|
||||
k = 0; //= 0
|
||||
fprintf (stderr, "\n");
|
||||
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)];
|
||||
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, " TGT %d;", private_target);
|
||||
if (opts->trunk_tune_private_calls == 1) t_tg[i] = private_target; //set here for tuning allow/block
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//end private/data call check
|
||||
|
||||
if (fl != 2)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
fprintf (stderr, "Ch%d: ", 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++;
|
||||
|
||||
}
|
||||
else if (pch[i] == 1) //private or data channels
|
||||
{
|
||||
fprintf (stderr, "P||D ");
|
||||
//flag as available for tuning if enabled
|
||||
if (opts->trunk_tune_private_calls == 1) ch[i] = 1;
|
||||
}
|
||||
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)
|
||||
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;
|
||||
|
||||
//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
|
||||
{
|
||||
char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == t_tg[j])
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
}
|
||||
}
|
||||
|
||||
//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))
|
||||
{
|
||||
if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
|
||||
{
|
||||
//RIGCTL
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} //end tuning
|
||||
|
||||
SKIPCAP: ;
|
||||
//debug print
|
||||
if (fl == 1 && opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s\n", KYEL);
|
||||
fprintf (stderr, " CAP+ Multi Block PDU ");
|
||||
uint8_t fl_bytes = 0;
|
||||
for (i = 0; i < 17; i++)
|
||||
{
|
||||
fl_bytes = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[i*8], 8);
|
||||
fprintf (stderr, "[%02X]", fl_bytes);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
|
||||
} //fl != 2
|
||||
} //opcode == 0x3E
|
||||
} //fid == 0x10
|
||||
|
||||
//Capacity+ Section -- fallback if issues arise
|
||||
// if (csbk_fid == 0x10)
|
||||
// {
|
||||
// //not quite sure how these tuning rules will go over
|
||||
// //if they don't work so well, may just fall back to
|
||||
// //a 'follow rest channel on no sync' only approach
|
||||
// if (csbk_o == 0x3E)
|
||||
// {
|
||||
|
||||
// //initial line break
|
||||
// fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
|
||||
// uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
|
||||
// uint8_t ts = cs_pdu_bits[18]; //accurate?
|
||||
// uint8_t res = cs_pdu_bits[19]; //unknown??
|
||||
// uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
|
||||
|
||||
// uint8_t ch[8]; //one bit per channel
|
||||
// uint8_t tg = 0;
|
||||
// uint32_t tghex = 0; //combined all tgs for debug
|
||||
// int i, j, k;
|
||||
|
||||
// //tg and channel info for trunking purposes
|
||||
// uint8_t t_tg[9];
|
||||
// memset (t_tg, 0, sizeof(t_tg));
|
||||
|
||||
// k = 0;
|
||||
// if (rest_channel != state->dmr_rest_channel)
|
||||
// {
|
||||
// state->dmr_rest_channel = rest_channel;
|
||||
// }
|
||||
// for (int i = 0; i < 8; i++)
|
||||
// {
|
||||
// ch[i] = cs_pdu_bits[i+24];
|
||||
// }
|
||||
|
||||
// //assign to cc freq to follow during no sync
|
||||
// if (state->trunk_chan_map[rest_channel] != 0)
|
||||
// {
|
||||
// state->p25_cc_freq = state->trunk_chan_map[rest_channel];
|
||||
// //set to always tuned
|
||||
// opts->p25_is_tuned = 1;
|
||||
// }
|
||||
|
||||
// fprintf (stderr, " Capacity Plus Channel Status - FL: %d TS: %d RS: %d - Rest Channel %d", fl, ts, res, rest_channel);
|
||||
|
||||
// fprintf (stderr, "\n ");
|
||||
// for (i = 0; i < 8; i++)
|
||||
// {
|
||||
// fprintf (stderr, "Ch%d: ", i+1);
|
||||
// if (ch[i] != 0)
|
||||
// {
|
||||
// tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[k*8+32], 8);
|
||||
// if (tg != 0) fprintf (stderr, " %03d ", tg);
|
||||
// else fprintf (stderr, "Priv "); //observed 000s for TG value seem to appear during a Cap+ Private TXI call
|
||||
// //add values to trunking tg/channel potentials
|
||||
// t_tg[i] = tg;
|
||||
// k++;
|
||||
|
||||
}
|
||||
else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
|
||||
else fprintf (stderr, "Idle ");
|
||||
// }
|
||||
// else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
|
||||
// else fprintf (stderr, "Idle ");
|
||||
|
||||
if (i == 3) fprintf (stderr, "\n ");
|
||||
}
|
||||
tghex = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
//fprintf (stderr, "\n TG Hex = 0x%06X", tghex);
|
||||
state->dmr_mfid = 0x10;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
// if (i == 3) fprintf (stderr, "\n ");
|
||||
// }
|
||||
// tghex = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
// //fprintf (stderr, "\n TG Hex = 0x%06X", tghex);
|
||||
// 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)
|
||||
sprintf(state->dmr_site_parms, "%s", "");
|
||||
// //nullify any previous TIII data (bugfix for bad assignments or system type switching)
|
||||
// sprintf(state->dmr_site_parms, "%s", "");
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//don't tune if currently a 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
|
||||
{
|
||||
char mode[8]; //allow, block, digital, enc, etc
|
||||
// //Skip tuning group calls if group calls are disabled
|
||||
// if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
|
||||
|
||||
//if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
//comparison below will look for an 'A' to write to mode if it is allowed
|
||||
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
// //don't tune if currently a 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
|
||||
// {
|
||||
// char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == t_tg[j])
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
}
|
||||
}
|
||||
// //if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
// //comparison below will look for an 'A' to write to mode if it is allowed
|
||||
// if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
|
||||
|
||||
//no more 0 reporting, that was some bad code that caused that issue
|
||||
//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))
|
||||
{
|
||||
if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
|
||||
{
|
||||
//RIGCTL
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
j = 11; //break loop
|
||||
}
|
||||
// for (int i = 0; i < state->group_tally; i++)
|
||||
// {
|
||||
// if (state->group_array[i].groupNumber == t_tg[j])
|
||||
// {
|
||||
// fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
// strcpy (mode, state->group_array[i].groupMode);
|
||||
// }
|
||||
// }
|
||||
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
j = 11; //break loop
|
||||
}
|
||||
// //no more 0 reporting, that was some bad code that caused that issue
|
||||
// //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))
|
||||
// {
|
||||
// if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
|
||||
// {
|
||||
// //RIGCTL
|
||||
// if (opts->use_rigctl == 1)
|
||||
// {
|
||||
// if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||
// SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
|
||||
// state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
// opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
// j = 11; //break loop
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
// //rtl_udp
|
||||
// else if (opts->audio_in_type == 3)
|
||||
// {
|
||||
// rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
|
||||
// state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
// opts->p25_is_tuned = 1;
|
||||
// j = 11; //break loop
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
// }
|
||||
// SKIPCAP: ; //do nothing
|
||||
// }
|
||||
|
||||
//Connect+ Section
|
||||
if (csbk_fid == 0x06)
|
||||
{
|
||||
|
||||
//maintain this to allow users to hardset the cc freq as map[0]; otherwise, set from rigctl or rtl freq
|
||||
// if (state->p25_cc_freq == 0 && state->trunk_chan_map[0] != 0) state->p25_cc_freq = state->trunk_chan_map[0];
|
||||
|
||||
if (csbk_o == 0x01)
|
||||
{
|
||||
//initial line break
|
||||
@@ -713,6 +1007,9 @@ 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+ ");
|
||||
|
||||
//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
|
||||
@@ -752,7 +1049,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
}
|
||||
|
||||
//don't tune if currently a vc on the control channel
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
if ( (opts->trunk_tune_group_calls == 1) && (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
|
||||
if (state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0) )
|
||||
@@ -784,71 +1081,8 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
SKIPCON: ; //do nothing
|
||||
|
||||
if (csbk_o == 0x06)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 ) ;
|
||||
uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 );
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Data Channel Grant\n");
|
||||
fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
if (csbk_o == 0x0C)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 );
|
||||
uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 );
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Terminate Channel Grant\n");
|
||||
fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
if (csbk_o == 0x11)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Registration Request");
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
if (csbk_o == 0x12)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Registration Response");
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
if (csbk_o == 0x18)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Talkgroup Affiliation");
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
@@ -56,6 +56,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[i];
|
||||
}
|
||||
else state->dmr_stereo_payload[i] = dibit;
|
||||
|
||||
cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1
|
||||
cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
|
||||
@@ -103,6 +104,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[i+12];
|
||||
}
|
||||
else state->dmr_stereo_payload[i+12] = dibit;
|
||||
info[2*i] = (1 & (dibit >> 1)); // bit 1
|
||||
info[(2*i)+1] = (1 & dibit); // bit 0
|
||||
}
|
||||
@@ -118,6 +120,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[61];
|
||||
}
|
||||
else state->dmr_stereo_payload[61] = dibit;
|
||||
|
||||
SlotType[0] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[1] = (1 & dibit); // bit 0
|
||||
@@ -132,6 +135,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[62];
|
||||
}
|
||||
else state->dmr_stereo_payload[62] = dibit;
|
||||
|
||||
SlotType[2] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[3] = (1 & dibit); // bit 0
|
||||
@@ -146,6 +150,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[63];
|
||||
}
|
||||
else state->dmr_stereo_payload[63] = dibit;
|
||||
|
||||
SlotType[4] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[5] = (1 & dibit); // bit 0
|
||||
@@ -160,6 +165,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[64];
|
||||
}
|
||||
else state->dmr_stereo_payload[64] = dibit;
|
||||
|
||||
SlotType[6] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[7] = (1 & dibit); // bit 0
|
||||
@@ -175,6 +181,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
|
||||
|
||||
@@ -191,6 +198,8 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[i+66];
|
||||
}
|
||||
else state->dmr_stereo_payload[i+66] = dibit;
|
||||
|
||||
syncdata[2*i] = (1 & (dibit >> 1)); // bit 1
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
@@ -236,6 +245,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
if (state->dmr_stereo == 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
}
|
||||
if (state->dmr_stereo == 1)
|
||||
{
|
||||
@@ -277,6 +287,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
if (state->dmr_stereo == 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+95] = dibit;
|
||||
}
|
||||
|
||||
if (state->dmr_stereo == 1)
|
||||
@@ -288,10 +299,11 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
info[(2*i) + 99] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
|
||||
//don't run on MS Reverse Channel Data
|
||||
if (state->dmr_ms_rc == 0) dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
|
||||
|
||||
//don't run cach on simplex or mono
|
||||
if (state->dmr_ms_mode == 0 || opts->dmr_mono == 0)
|
||||
if (state->dmr_ms_mode == 0 && opts->dmr_mono == 0)
|
||||
{
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
}
|
||||
@@ -319,8 +331,8 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
//con+ voice channels can have extremely long idle periods without properly tearing down
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->is_con_plus == 1)
|
||||
{
|
||||
//at 3 seconds, the CC was sending back to the VC even without voice present, increased to 5
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 5) )
|
||||
//bug fixed that caused hopping from CC to VC; decreased to 2 seconds.
|
||||
if ( (time(NULL) - state->last_vc_sync_time > 2) )
|
||||
{
|
||||
if (opts->use_rigctl == 1) //rigctl tuning
|
||||
{
|
||||
|
||||
280
src/dmr_dburst.c
280
src/dmr_dburst.c
@@ -9,9 +9,9 @@
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
//TODO: CRC9 on confirmed data blocks; CRC32 on completed data sf;
|
||||
//TODO: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC
|
||||
//TODO: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key
|
||||
//WIP: CRC9 on confirmed data blocks; CRC32 on completed data sf;
|
||||
//WIP: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC
|
||||
//WIP: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
@@ -26,6 +26,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t block = state->data_block_counter[slot];
|
||||
|
||||
//confirmed data
|
||||
uint8_t dbsn = 0; //data block serial number for confirmed data blocks
|
||||
uint8_t blockcounter = 0; //local block count
|
||||
uint8_t confdatabits[250]; //array to reshuffle conf data block bits into sequence for crc9 check
|
||||
memset (confdatabits, 0, sizeof(confdatabits));
|
||||
|
||||
//BPTC 196x96 Specific
|
||||
uint8_t BPTCDeInteleavedData[196];
|
||||
uint8_t BPTCDmrDataBit[96];
|
||||
@@ -45,9 +51,11 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
|
||||
uint8_t R[3];
|
||||
uint8_t BPTCReservedBits = 0;
|
||||
uint8_t is_ras = 0;
|
||||
uint8_t crc_original_validity = 0;
|
||||
|
||||
uint32_t crcmask = 0;
|
||||
uint8_t crclen = 0;
|
||||
uint8_t crclen = 0;
|
||||
|
||||
uint8_t is_bptc = 0;
|
||||
uint8_t is_trellis = 0;
|
||||
@@ -108,32 +116,31 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " DATA");
|
||||
break;
|
||||
//TODO - 1/2 0x0F0 - 3/4 0x1FF - Rate 1 0x10F
|
||||
//going to set crclen and mask according to confirmed data here,
|
||||
//use block assmebler to carry out completed message crc
|
||||
case 0x07: //1/2 Rate Data
|
||||
is_bptc = 1;
|
||||
crclen = 9; //confirmed data only
|
||||
crcmask = 0x0F0;
|
||||
pdu_len = 12; //12 bytes unconfirmed
|
||||
sprintf(state->fsubtype, " R12U ");
|
||||
if (state->data_conf_data[slot] == 1)
|
||||
{
|
||||
pdu_len = 10;
|
||||
pdu_start = 2; //start at plus two when assembling
|
||||
sprintf(state->fsubtype, " R12C ");
|
||||
}
|
||||
sprintf(state->fsubtype, " R12D ");
|
||||
break;
|
||||
case 0x08: //3/4 Rate Data
|
||||
is_trellis = 1;
|
||||
crclen = 9; //confirmed data only
|
||||
crcmask = 0x1FF;
|
||||
pdu_len = 18; //18 bytes unconfirmed
|
||||
sprintf(state->fsubtype, " R34U ");
|
||||
if (state->data_conf_data[slot] == 1)
|
||||
{
|
||||
pdu_len = 16;
|
||||
pdu_start = 2; //start at plus two when assembling
|
||||
sprintf(state->fsubtype, " R34C ");
|
||||
}
|
||||
sprintf(state->fsubtype, " R34D ");
|
||||
break;
|
||||
case 0x09: //Idle
|
||||
//pseudo-random data fill, no need to do anything with this
|
||||
@@ -141,10 +148,16 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
break;
|
||||
case 0x0A: //1 Rate Data
|
||||
crclen = 9; //confirmed data only
|
||||
crcmask = 0x1FF;
|
||||
crcmask = 0x10F;
|
||||
is_full = 1;
|
||||
pdu_len = 25; //196 bits - 24.5 bytes
|
||||
sprintf(state->fsubtype, " R_1D ");
|
||||
pdu_len = 25; //196 bits - 24.5 bytes
|
||||
sprintf(state->fsubtype, " R_1U ");
|
||||
if (state->data_conf_data[slot] == 1)
|
||||
{
|
||||
pdu_len = 23;
|
||||
pdu_start = 2; //start at plus two when assembling
|
||||
sprintf(state->fsubtype, " R_1C ");
|
||||
}
|
||||
break;
|
||||
case 0x0B: //Unified Data
|
||||
is_bptc = 1;
|
||||
@@ -153,13 +166,21 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " UDAT ");
|
||||
break;
|
||||
|
||||
//special types (not real data 'sync' bursts)
|
||||
case 0xEB: //Embedded Signalling
|
||||
crclen = 5;
|
||||
is_emb = 1;
|
||||
pdu_len = 9;
|
||||
break;
|
||||
|
||||
default:
|
||||
//Slot Type FEC should catch this so we never see it,
|
||||
//but if it doesn't, then we can still dump the entire 'packet'
|
||||
//treat like rate 1 unconfirmed data
|
||||
is_full = 1;
|
||||
pdu_len = 25; //196 bits - 24.5 bytes
|
||||
sprintf(state->fsubtype, " _UNK ");
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -168,6 +189,26 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
{
|
||||
if (state->dmr_ms_mode == 0) fprintf(stderr, "| Color Code=%02d ", state->dmr_color_code);
|
||||
fprintf(stderr, "|%s", state->fsubtype);
|
||||
|
||||
//'DSP' output to file
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 98 ", slot+1); //'98' is CACH designation value
|
||||
for (i = 0; i < 6; i++) //3 byte CACH
|
||||
{
|
||||
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", cach_byte);
|
||||
}
|
||||
fprintf (pFile, "\n%d %02X ", slot+1, databurst); //use hex value of current data burst type
|
||||
for (i = 6; i < 72; i++) //33 bytes, no CACH
|
||||
{
|
||||
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
}
|
||||
|
||||
//Most Data Sync Burst types will use the bptc 196x96
|
||||
@@ -184,7 +225,11 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, R);
|
||||
|
||||
/* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */
|
||||
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08);
|
||||
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x04);
|
||||
|
||||
//debug print
|
||||
//fprintf (stderr, " RAS? %X - %d %d %d", BPTCReservedBits, R[0], R[1], R[2]);
|
||||
|
||||
|
||||
/* Convert the 96 bits BPTC data into 12 bytes */
|
||||
k = 0;
|
||||
@@ -213,10 +258,39 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
/* Check/correct the BPTC data and compute the Reed-Solomon (12,9) CRC */
|
||||
if (is_lc) CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
|
||||
|
||||
//TODO: run CRC9 on confirmed 1/2 data blocks
|
||||
else if (state->data_conf_data[slot] == 1)
|
||||
//set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these)
|
||||
else if (state->data_conf_data[slot] == 0 && databurst == 0x7)
|
||||
{
|
||||
//run CRC on individual blocks according to type and validate each individual block
|
||||
CRCComputed = 0;
|
||||
CRCExtracted = 0;
|
||||
CRCCorrect = 1;
|
||||
}
|
||||
|
||||
//set CRC to correct on proprietary data header blocks (unsure if p_head data has valid crcs,
|
||||
//may be ras enabled, manufacturer specific, or none, currently unknown, but possibly RAS on samples I have)
|
||||
// else if (state->data_p_head[slot] == 1 && databurst == 0x06) CRCCorrect = 1;
|
||||
|
||||
//run CRC9 on intermediate and last 1/2 confirmed data blocks
|
||||
else if (state->data_conf_data[slot] == 1 && databurst == 0x7)
|
||||
{
|
||||
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
|
||||
dbsn = (uint32_t)ConvertBitIntoBytes(&BPTCDmrDataBit[0], 7) + 1; //recover data block serial number
|
||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&BPTCDmrDataBit[7], 9); //extract CRC from data
|
||||
CRCExtracted = CRCExtracted ^ crcmask;
|
||||
|
||||
//reorganize the BPTCDmrDataBit array into confdatabits, just for CRC9 check
|
||||
//need to find a sample to confirm this
|
||||
for(i = 0; i < 80; i++) confdatabits[i] = BPTCDmrDataBit[i + 16];
|
||||
for(i = 0; i < 7; i++) confdatabits[i + 80] = BPTCDmrDataBit[i];
|
||||
|
||||
CRCComputed = ComputeCrc9Bit(confdatabits, 87);
|
||||
if (CRCExtracted == CRCComputed)
|
||||
{
|
||||
CRCCorrect = 1;
|
||||
state->data_block_crc_valid[slot][blockcounter] = 1;
|
||||
}
|
||||
else state->data_block_crc_valid[slot][blockcounter] = 0;
|
||||
|
||||
}
|
||||
|
||||
//run CCITT on other data forms
|
||||
@@ -225,6 +299,20 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
|
||||
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
|
||||
else CRCCorrect = 0;
|
||||
}
|
||||
|
||||
//set the 'RAS Flag', if no irrecoverable errors but bad crc, only when enabled by user (to prevent a lot of bad data CSBKs)
|
||||
if (opts->aggressive_framesync == 0 && CRCCorrect == 0 && IrrecoverableErrors == 0 && BPTCReservedBits == 4) is_ras = 1; //!=0, or == 0x4, or just R[2] == 1
|
||||
|
||||
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
|
||||
if (BPTCDmrDataByte[1] == 0x68) is_ras = 0;
|
||||
|
||||
//if this is a RAS system, set the CRC to okay if irrecoverable errors is okay
|
||||
//if we don't do this, then we can't view some data (CSBKs on RAS enabled systems)
|
||||
if (is_ras == 1)
|
||||
{
|
||||
crc_original_validity = CRCCorrect;
|
||||
CRCCorrect = 1;
|
||||
}
|
||||
|
||||
if (databurst == 0x04 || databurst == 0x06) //MBC Header, Data Header
|
||||
@@ -295,11 +383,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit);
|
||||
|
||||
/* Reconstitute the 5 bit CRC */
|
||||
CRCExtracted = (LC_DataBit[72] & 1) << 4;
|
||||
CRCExtracted |= (LC_DataBit[73] & 1) << 3;
|
||||
CRCExtracted |= (LC_DataBit[74] & 1) << 2;
|
||||
CRCExtracted |= (LC_DataBit[75] & 1) << 1;
|
||||
CRCExtracted |= (LC_DataBit[76] & 1) << 0;
|
||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&LC_DataBit[72], 5);
|
||||
|
||||
/* Compute the 5 bit CRC */
|
||||
CRCComputed = ComputeCrc5Bit(LC_DataBit);
|
||||
@@ -348,6 +432,50 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
|
||||
}
|
||||
|
||||
for(i = 0, j = 0; i < 18; i++, j+=8)
|
||||
{
|
||||
DMR_PDU_bits[j + 0] = (TrellisReturn[i] >> 7) & 0x01;
|
||||
DMR_PDU_bits[j + 1] = (TrellisReturn[i] >> 6) & 0x01;
|
||||
DMR_PDU_bits[j + 2] = (TrellisReturn[i] >> 5) & 0x01;
|
||||
DMR_PDU_bits[j + 3] = (TrellisReturn[i] >> 4) & 0x01;
|
||||
DMR_PDU_bits[j + 4] = (TrellisReturn[i] >> 3) & 0x01;
|
||||
DMR_PDU_bits[j + 5] = (TrellisReturn[i] >> 2) & 0x01;
|
||||
DMR_PDU_bits[j + 6] = (TrellisReturn[i] >> 1) & 0x01;
|
||||
DMR_PDU_bits[j + 7] = (TrellisReturn[i] >> 0) & 0x01;
|
||||
}
|
||||
|
||||
//set CRC to correct on unconfirmed 3/4 data blocks (for reporting due to no CRC available on these)
|
||||
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
||||
|
||||
//run CRC9 on intermediate and last 3/4 data blocks
|
||||
else if (state->data_conf_data[slot] == 1)
|
||||
{
|
||||
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
|
||||
dbsn = (uint32_t)ConvertBitIntoBytes(&DMR_PDU_bits[0], 7) + 1; //recover data block serial number
|
||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&DMR_PDU_bits[7], 9); //extract CRC from data
|
||||
CRCExtracted = CRCExtracted ^ crcmask;
|
||||
|
||||
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
|
||||
//confirmed working now!
|
||||
for(i = 0; i < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
|
||||
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
|
||||
|
||||
CRCComputed = ComputeCrc9Bit(confdatabits, 135);
|
||||
if (CRCExtracted == CRCComputed)
|
||||
{
|
||||
CRCCorrect = 1;
|
||||
state->data_block_crc_valid[slot][blockcounter] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix
|
||||
state->data_block_crc_valid[slot][blockcounter] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//reorganize the DMR_PDU_bits into PDU friendly format (minus the dbsn and crc9)
|
||||
memset (DMR_PDU_bits, 0, sizeof(DMR_PDU_bits));
|
||||
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
|
||||
{
|
||||
DMR_PDU_bits[j + 0] = (TrellisReturn[i+pdu_start] >> 7) & 0x01;
|
||||
@@ -360,17 +488,13 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
DMR_PDU_bits[j + 7] = (TrellisReturn[i+pdu_start] >> 0) & 0x01;
|
||||
}
|
||||
|
||||
//TODO: run CRC9 on confirmed 3/4 data blocks
|
||||
|
||||
}
|
||||
|
||||
if (is_full) //Rate 1 Data
|
||||
{
|
||||
CRCExtracted = 0;
|
||||
CRCComputed = 0;
|
||||
IrrecoverableErrors = 0;
|
||||
|
||||
//TODO: run CRC9 on confirmed data
|
||||
IrrecoverableErrors = 0; //implicit, since there is no encoding
|
||||
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
@@ -381,6 +505,32 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
DMR_PDU[25] = (uint8_t)ConvertBitIntoBytes(&info[192], 4);
|
||||
DMR_PDU[25] = DMR_PDU[25] << 4;
|
||||
|
||||
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
|
||||
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
||||
|
||||
//run CRC9 on intermediate and last 1 rate data blocks
|
||||
else if (state->data_conf_data[slot] == 1)
|
||||
{
|
||||
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
|
||||
dbsn = (uint32_t)ConvertBitIntoBytes(&info[0], 7) + 1; //recover data block serial number
|
||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&info[7], 9); //extract CRC from data
|
||||
CRCExtracted = CRCExtracted ^ crcmask;
|
||||
|
||||
//reorganize the info bit array into confdatabits, just for CRC9 check
|
||||
//unconfirmed, haven't seen any samples with rate 1 data
|
||||
for(i = 0; i < 176; i++) confdatabits[i] = info[i + 16];
|
||||
for(i = 0; i < 7; i++) confdatabits[i + 176] = info[i];
|
||||
|
||||
CRCComputed = ComputeCrc9Bit(confdatabits, 183);
|
||||
if (CRCExtracted == CRCComputed)
|
||||
{
|
||||
CRCCorrect = 1;
|
||||
state->data_block_crc_valid[slot][blockcounter] = 1;
|
||||
}
|
||||
else state->data_block_crc_valid[slot][blockcounter] = 0;
|
||||
|
||||
}
|
||||
|
||||
//copy info to dmr_pdu_bits
|
||||
memcpy(DMR_PDU_bits, info, sizeof(DMR_PDU_bits));
|
||||
|
||||
@@ -399,13 +549,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
if (databurst == 0x06) dmr_dheader (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors);
|
||||
if (databurst == 0x07) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //1/2 Rate Data
|
||||
if (databurst == 0x08) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //3/4 Rate Data
|
||||
//if (databurst == 0x0A) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Full Rate Data - Disabled until further testing can be done
|
||||
if (databurst == 0x0A) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Full Rate Data
|
||||
|
||||
//is unified data handled like normal data, or control signalling data?
|
||||
//my best understanding is that unified data carries supplimentary MS data on TIII systems, not control signalling
|
||||
if (databurst == 0x0B) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Unified Data
|
||||
//if (databurst == 0x0B) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors);
|
||||
|
||||
//control signalling types (CSBK, MBC, UDT)
|
||||
//control signalling types (CSBK, MBC)
|
||||
if (databurst == 0x03) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors);
|
||||
|
||||
//both MBC header and MBC continuation will go to the block_assembler - type 2, and then to dmr_cspdu
|
||||
@@ -416,6 +565,44 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
}
|
||||
if (databurst == 0x05) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2);
|
||||
|
||||
//set the original CRCCorrect back to its original value if the RAS flag was tripped
|
||||
if (is_ras == 1) CRCCorrect = crc_original_validity;
|
||||
|
||||
//start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c)
|
||||
if (CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) ; //fprintf(stderr, "(CRC OK)");
|
||||
|
||||
if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " (FEC OK)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
|
||||
if (IrrecoverableErrors != 0 && databurst != 0x09 && databurst != 0x05)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, " (FEC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//print whether or not the 'RAS Field' bits are set to indicate RAS enabled (to be verified)
|
||||
if (is_ras == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " -RAS ");
|
||||
//the value of this field seems to always, or usually, be 4, or just R[2] bit is set
|
||||
if (opts->payload == 1) fprintf (stderr, "%X ", BPTCReservedBits);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if (CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR) ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//print the unified PDU format here, if not slot idle
|
||||
if (opts->payload == 1 && databurst != 0x09)
|
||||
{
|
||||
@@ -427,20 +614,31 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
fprintf (stderr, "[%02X]", DMR_PDU[i]);
|
||||
}
|
||||
|
||||
//debug print
|
||||
// if (dbsn) fprintf (stderr, " SN %X", dbsn);
|
||||
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// fprintf (stderr, "%s", KCYN);
|
||||
// fprintf (stderr, "\n Hex to Ascii - ");
|
||||
// for (i = 0; i < 12; i++)
|
||||
// {
|
||||
// if (DMR_PDU[i] <= 0x7E && DMR_PDU[i] >=0x20)
|
||||
// {
|
||||
// fprintf (stderr, "%c", DMR_PDU[i]);
|
||||
// }
|
||||
// else fprintf (stderr, ".");
|
||||
// }
|
||||
//short data - DD_HEAD, SP_HEAD or R_HEAD (Might do on TMS as well)
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0xD )
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n Hex to Ascii - ");
|
||||
for (i = 0; i < pdu_len; i++)
|
||||
{
|
||||
if (DMR_PDU[i] <= 0x7E && DMR_PDU[i] >=0x20)
|
||||
{
|
||||
fprintf (stderr, "%c", DMR_PDU[i]);
|
||||
}
|
||||
else fprintf (stderr, ".");
|
||||
}
|
||||
|
||||
fprintf (stderr,"%s", KNRM);
|
||||
|
||||
}
|
||||
|
||||
|
||||
fprintf (stderr,"%s", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
186
src/dmr_flco.c
186
src/dmr_flco.c
@@ -25,11 +25,13 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
uint8_t so = 0;
|
||||
uint32_t target = 0;
|
||||
uint32_t source = 0;
|
||||
uint8_t capsite = 0;
|
||||
int restchannel = -1;
|
||||
int is_cap_plus = 0;
|
||||
int is_alias = 0;
|
||||
int is_gps = 0;
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t unk = 0; //flag for unknown FLCO + FID combo
|
||||
|
||||
|
||||
pf = (uint8_t)(lc_bits[0]); //Protect Flag
|
||||
@@ -40,38 +42,108 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
|
||||
|
||||
//check protect flag
|
||||
if (pf == 1)
|
||||
{
|
||||
if (type == 1) fprintf (stderr, "%s \n", KRED);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KRED);
|
||||
if (type == 3) fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " Protected LC ");
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//look for Cap+ on VLC header, then set source and/or rest channel appropriately
|
||||
if (type == 1 && fid == 0x10 && flco == 0x04)
|
||||
if (IrrecoverableErrors == 0 && type == 1 && fid == 0x10 && (flco == 0x04 || flco == 0x07) ) //0x07 appears to be a cap+ txi private call
|
||||
{
|
||||
is_cap_plus = 1;
|
||||
restchannel = (int)ConvertBitIntoBytes(&lc_bits[48], 8);
|
||||
capsite = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 4); //can't verify, just speculating
|
||||
restchannel = (int)ConvertBitIntoBytes(&lc_bits[52], 4); //was 48,8
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (IrrecoverableErrors == 0)
|
||||
{
|
||||
|
||||
if (slot == 0) state->dmr_flco = flco;
|
||||
else state->dmr_flcoR = flco;
|
||||
|
||||
//Embedded Talker Alias Header Only (format and len storage)
|
||||
if (type == 3 && flco == 0x04)
|
||||
if (fid == 0 && type == 3 && flco == 0x04)
|
||||
{
|
||||
dmr_embedded_alias_header(opts, state, lc_bits);
|
||||
}
|
||||
|
||||
//Embedded Talker Alias Header (continuation) and Blocks
|
||||
if (type == 3 && flco > 0x3 && flco < 0x08)
|
||||
if (fid == 0 && type == 3 && flco > 0x3 && flco < 0x08)
|
||||
{
|
||||
is_alias = 1;
|
||||
dmr_embedded_alias_blocks(opts, state, lc_bits);
|
||||
}
|
||||
|
||||
//Embedded GPS
|
||||
if (type == 3 && flco == 0x08)
|
||||
if (fid == 0 && type == 3 && flco == 0x08)
|
||||
{
|
||||
is_gps = 1;
|
||||
if (fid == 0) dmr_embedded_gps(opts, state, lc_bits); //issues with fid 0x10 and flco 0x08
|
||||
dmr_embedded_gps(opts, state, lc_bits);
|
||||
}
|
||||
|
||||
//Unknown CapMax/Moto Things
|
||||
if (fid == 0x10 && (flco == 0x08 || flco == 0x28))
|
||||
{
|
||||
//NOTE: fid 0x10 and flco 0x08 (emb) produces a lot of 'zero' bytes
|
||||
//this has been observed to happen often on CapMax systems, so I believe it could be some CapMax 'thing'
|
||||
//Unknown Link Control - FLCO=0x08 FID=0x10 SVC=0xC1 or FLCO=0x08 FID=0x10 SVC=0xC0 <- probably no SVC bits in the lc
|
||||
//flco 0x28 has also been observed lately but the tg and src values don't match
|
||||
//another flco 0x10 does seem to match, so is probably capmax group call flco
|
||||
if (type == 1) fprintf (stderr, "%s \n", KCYN);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KCYN);
|
||||
if (type == 3) fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " Motorola");
|
||||
unk = 1;
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//7.1.1.1 Terminator Data Link Control PDU - ETSI TS 102 361-3 V1.2.1 (2013-07)
|
||||
if (type == 2 && flco == 0x30)
|
||||
{
|
||||
fprintf (stderr, "%s \n", KRED);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " Data Terminator (TD_LC)");
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//Unknown Tait Things
|
||||
if (fid == 0x58)
|
||||
{
|
||||
//NOTE: fid 0x58 (tait) had a single flco 0x06 emb observed, but without the other blocks (4,5,7) for an alias
|
||||
//will need to observe this one, or just remove it from the list, going to isolate tait lc for now
|
||||
if (type == 1) fprintf (stderr, "%s \n", KCYN);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KCYN);
|
||||
if (type == 3) fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " Tait");
|
||||
unk = 1;
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
//unknown other manufacturer or OTA ENC, etc.
|
||||
if (fid != 0 && fid != 0x68 && fid != 0x10) //removed tait from the list
|
||||
{
|
||||
if (type == 1) fprintf (stderr, "%s \n", KYEL);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KYEL);
|
||||
if (type == 3) fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " Unknown LC ");
|
||||
unk = 1;
|
||||
goto END_FLCO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//will want to continue to observe for different flco and fid combinations to find out their meaning
|
||||
@@ -119,6 +191,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
// state->lastsrc = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_mi = 0;
|
||||
state->payload_keyid = 0;
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
@@ -128,6 +201,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
// state->lastsrcR = 0;
|
||||
state->payload_algidR = 0;
|
||||
state->payload_miR = 0;
|
||||
state->payload_keyidR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,14 +224,32 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
|
||||
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
|
||||
|
||||
if (flco == 3) //UU_V_Ch_Usr
|
||||
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
|
||||
//0x07 on a VLC seems to indicate a Cap+ Private Call Header
|
||||
//0x23 on the Embedded Voice Burst Sync seems to indicate a Cap+ Private Call in progress
|
||||
if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
|
||||
{
|
||||
sprintf (state->call_string[slot], " Private");
|
||||
sprintf (state->call_string[slot], " Cap+");
|
||||
fprintf (stderr, "Cap+ ");
|
||||
if (flco == 0x4)
|
||||
{
|
||||
strcat (state->call_string[slot], " Grp");
|
||||
fprintf (stderr, "Group ");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat (state->call_string[slot], " Pri");
|
||||
fprintf (stderr, "Private ");
|
||||
}
|
||||
}
|
||||
else if (flco == 0x3) //UU_V_Ch_Usr
|
||||
{
|
||||
sprintf (state->call_string[slot], " Private ");
|
||||
fprintf (stderr, "Private ");
|
||||
}
|
||||
}
|
||||
else //Grp_V_Ch_Usr
|
||||
{
|
||||
sprintf (state->call_string[slot], " Group");
|
||||
sprintf (state->call_string[slot], " Group ");
|
||||
fprintf (stderr, "Group ");
|
||||
}
|
||||
|
||||
@@ -194,7 +286,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
{
|
||||
//REMUS! Uncomment Line Below if desired
|
||||
// strcat (state->call_string[slot], " RES");
|
||||
fprintf(stderr, "Reserved=%d ", (so & 0x30) >> 4);
|
||||
fprintf(stderr, "RS%d ", (so & 0x30) >> 4);
|
||||
}
|
||||
}
|
||||
if(so & 0x08)
|
||||
@@ -239,10 +331,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
|
||||
fprintf(stderr, "Call ");
|
||||
|
||||
fprintf (stderr, "%s", KRED);
|
||||
if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good
|
||||
else if(IrrecoverableErrors == 0) fprintf(stderr, "(FEC/RAS)");
|
||||
else fprintf(stderr, "(FEC/CRC ERR)");
|
||||
|
||||
//check Cap+ rest channel info if available and good fec
|
||||
if (is_cap_plus == 1)
|
||||
@@ -287,6 +375,24 @@ 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); //not all LC PDUs contain SVC bits (see TD_LC)
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
if(IrrecoverableErrors != 0)
|
||||
{
|
||||
if (type != 3) fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " SLOT %d", state->currentslot+1);
|
||||
fprintf (stderr, " FLCO FEC ERR ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//externalized dmr cach - tact and slco fragment handling
|
||||
@@ -541,7 +647,9 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
uint8_t con_netid = (uint8_t)ConvertBitIntoBytes(&slco_bits[8], 8);
|
||||
uint8_t con_siteid = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 8);
|
||||
//Cap+
|
||||
uint8_t restchannel = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8);
|
||||
uint8_t capsite = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 4); //can't verify, just speculating
|
||||
uint8_t restchannel = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 4); //was 12,8
|
||||
uint8_t cap_reserved = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //unknown if any significant value?
|
||||
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
@@ -549,24 +657,20 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
|
||||
if (slco == 0x2) //C_SYS_Parms
|
||||
{
|
||||
if (n != 0) fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Reg Req: %d - CSC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg, csc);
|
||||
else fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - CSC: %d ", model_str, net, site, reg, csc);
|
||||
if (n != 0) fprintf (stderr, " SLC_C_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Reg Req: %d - CSC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg, csc);
|
||||
else fprintf (stderr, " SLC_C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - Capacity Max ", model_str, net, site, reg);
|
||||
|
||||
//add string for ncurses terminal display
|
||||
if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
|
||||
else sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
|
||||
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
|
||||
|
||||
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
|
||||
{
|
||||
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||
}
|
||||
|
||||
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
|
||||
//sprintf(state->dmr_branding_sub, "%s", "");
|
||||
|
||||
//debug print
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
||||
//fprintf (stderr, "\n SYSCODE: %014b", syscode);
|
||||
@@ -575,15 +679,13 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
}
|
||||
else if (slco == 0x3) //P_SYS_Parms
|
||||
{
|
||||
fprintf (stderr, " P_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Comp CC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg);
|
||||
if (n != 0) fprintf (stderr, " SLC_P_SYS_PARMS - %s - Net ID: %d Site ID: %d.%d - Comp CC: %d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1, reg);
|
||||
else fprintf (stderr, " SLC_P_SYS_PARMS - %s - Net ID: %d Site ID: %d - Capacity Max", model_str, net, site);
|
||||
|
||||
//add string for ncurses terminal display
|
||||
if (n != 0) sprintf (state->dmr_site_parms, "TIII - %s %d-%d.%d ", model_str, net+1, (site>>n)+1, (site & sub_mask)+1 );
|
||||
else sprintf (state->dmr_site_parms, "TIII - %s %d-%d ", model_str, net, site);
|
||||
|
||||
//nullify any previous branding sub (bugfix for bad assignments or system type switching)
|
||||
//sprintf(state->dmr_branding_sub, "%s", "");
|
||||
|
||||
//debug print
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&slco_bits[4], 14);
|
||||
//fprintf (stderr, "\n SYSCODE: %014b", syscode);
|
||||
@@ -596,18 +698,20 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
fprintf (stderr, " SLCO Activity Update TS1: %X Hash: %02X TS2: %X Hash: %02X", ts1_act, ts1_hash, ts2_act, ts2_hash); //102 361-2 7.1.3.2
|
||||
else if (slco == 0x9)
|
||||
{
|
||||
state->dmr_mfid = 0x10;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "Con+ ");
|
||||
//remove all setting of branding/sub from SLCO, can cause false positives even with seeming good CRC
|
||||
|
||||
// state->dmr_mfid = 0x10;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Con+ ");
|
||||
fprintf (stderr, " SLCO Connect Plus Voice Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
||||
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
||||
}
|
||||
|
||||
else if (slco == 0xA)
|
||||
{
|
||||
state->dmr_mfid = 0x10;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "Con+ ");
|
||||
// state->dmr_mfid = 0x10;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Con+ ");
|
||||
fprintf (stderr, " SLCO Connect Plus Control Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
||||
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
||||
|
||||
@@ -621,11 +725,11 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
|
||||
else if (slco == 0xF)
|
||||
{
|
||||
state->dmr_mfid = 0x10;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
fprintf (stderr, " SLCO Capacity Plus Rest Channel %d", restchannel);
|
||||
state->dmr_rest_channel = restchannel;
|
||||
// state->dmr_mfid = 0x10;
|
||||
// sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest Channel %d - RS: %02X", capsite+1, restchannel, cap_reserved);
|
||||
// state->dmr_rest_channel = restchannel; //test without, may work better
|
||||
//assign to cc freq if available
|
||||
if (state->trunk_chan_map[restchannel] != 0)
|
||||
{
|
||||
@@ -633,7 +737,7 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
}
|
||||
|
||||
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
|
||||
sprintf(state->dmr_site_parms, "%s", "");
|
||||
// sprintf(state->dmr_site_parms, "%s", "");
|
||||
}
|
||||
|
||||
else fprintf (stderr, " SLCO Unknown - %d ", slco);
|
||||
|
||||
154
src/dmr_le.c
154
src/dmr_le.c
@@ -137,3 +137,157 @@ void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
|
||||
state->payload_miP = 0;
|
||||
}
|
||||
|
||||
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
|
||||
//(Embedded or Dedicated Outbound, not Stand Alone (MS sourced) or Direct Mode)
|
||||
//MS Sourced or Direct Mode probably would be handled poorly by the demodulator
|
||||
void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
{
|
||||
int i;
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t sbrc_interleaved[32];
|
||||
uint8_t sbrc_return[32];
|
||||
memset (sbrc_interleaved, 0, sizeof(sbrc_interleaved));
|
||||
memset (sbrc_return, 0, sizeof(sbrc_return));
|
||||
uint32_t irr_err = 0;
|
||||
uint32_t sbrc_hex = 0;
|
||||
uint16_t crc_extracted = 7777;
|
||||
uint16_t crc_computed = 9999;
|
||||
uint8_t crc_okay = 0;
|
||||
|
||||
// 9.3.2 Pre-emption and power control Indicator (PI)
|
||||
// 0 - The embedded signalling carries information associated to the same logical channel or the Null embedded message
|
||||
// 1 - The embedded signalling carries RC information associated to the other logical channel
|
||||
|
||||
for(i = 0; i < 32; i++) sbrc_interleaved[i] = state->dmr_embedded_signalling[slot][5][i + 8];
|
||||
//power == 0 should be single burst
|
||||
if (power == 0) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 0);
|
||||
//power == 1 should be reverse channel -- still need to check the interleave inside of BPTC
|
||||
if (power == 1) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 1);
|
||||
//bad emb burst, never set a valid power indicator value (probably 9)
|
||||
if (power > 1) goto SBRC_END;
|
||||
|
||||
//RC Channel CRC 7 Mask = 0x7A; CRC bits are used as privacy indicators on
|
||||
//Single Voice Burst F (see below), other moto values seem to exist there as well
|
||||
//unknown what the other values are (see Cap+ 0x313)
|
||||
if (power == 1) //RC
|
||||
{
|
||||
crc_extracted = 0;
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
crc_extracted = crc_extracted << 1;
|
||||
crc_extracted = crc_extracted | sbrc_return[i+4];
|
||||
}
|
||||
crc_extracted = crc_extracted ^ 0x7A;
|
||||
crc_computed = crc7((uint8_t *) sbrc_return, 11);
|
||||
if (crc_extracted == crc_computed) crc_okay = 1;
|
||||
}
|
||||
else crc_okay = 1; //SB
|
||||
|
||||
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people right now
|
||||
{
|
||||
fprintf (stderr, "\n %s", KCYN);
|
||||
if (power == 0) fprintf (stderr, " SB: ");
|
||||
if (power == 1) fprintf (stderr, " RC: ");
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
sbrc_hex = sbrc_hex << 1;
|
||||
sbrc_hex |= sbrc_return[i] & 1; //sbrc_return
|
||||
fprintf (stderr, "%d", sbrc_return[i]);
|
||||
}
|
||||
fprintf (stderr, " - %03X", sbrc_hex);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
if (crc_okay == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " (CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
if (opts->payload == 1) fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
|
||||
}
|
||||
}
|
||||
|
||||
//sbrc_hex value of 0x313 seems to be some Cap+ Thing,
|
||||
//also observed 0x643 on another cap+ system (site id, status? something?)
|
||||
//I've observed it in the Private Cap+ TXI calls as well
|
||||
//there also seems to be a correlation between the SVC bits for TXI (reserved=3) and these extra cap+ values
|
||||
uint8_t sbrc_opcode = sbrc_hex;
|
||||
uint8_t alg = sbrc_hex & 3;
|
||||
uint16_t key = (sbrc_hex >> 3) & 0xFF;
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
if (irr_err != 0) fprintf (stderr, "%s (FEC ERR) %d %s", KRED, irr_err, KNRM);
|
||||
if (irr_err == 0)
|
||||
{
|
||||
if (sbrc_hex == 0) ; //NULL
|
||||
else if (sbrc_hex == 0x313)
|
||||
{
|
||||
//Cap+ Thing? Observed On Cap+ Systems
|
||||
// fprintf (stderr, " Cap+ Thing?");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (slot == 0)
|
||||
{
|
||||
//key and alg only present SOME times, not all,
|
||||
//also, intermixed with other signalling
|
||||
//needs more study first!
|
||||
if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
|
||||
{
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 1");
|
||||
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
//needs more study before assignment
|
||||
//state->payload_keyid = key;
|
||||
//state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
}
|
||||
}
|
||||
if (slot == 1)
|
||||
{
|
||||
if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
|
||||
{
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 2");
|
||||
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
//needs more study before assignment
|
||||
//state->payload_keyidR = key;
|
||||
//state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
SBRC_END:
|
||||
|
||||
//'DSP' output to file -- only RC, or RC and SB?
|
||||
if (power == 1 && opts->use_dsp_output == 1 && sbrc_hex != 0) //if not NULL
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 99 ", slot+1); //'99' is RC designation value
|
||||
int k = 0;
|
||||
for (i = 0; i < 24; i++) //12 bytes, SB or RC
|
||||
{
|
||||
//check to see if k++ starts at zero, or at 1
|
||||
int sbrc_nib = (state->dmr_embedded_signalling[slot][5][k++] << 3) | (state->dmr_embedded_signalling[slot][5][k++] << 2) | (state->dmr_embedded_signalling[slot][5][k++] << 1) | (state->dmr_embedded_signalling[slot][5][k++] << 0);
|
||||
fprintf (pFile, "%X", sbrc_nib);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
121
src/dmr_ms.c
121
src/dmr_ms.c
@@ -50,6 +50,11 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t internalslot;
|
||||
uint8_t vc;
|
||||
|
||||
//assign as nonsensical numbers
|
||||
uint8_t cc = 25;
|
||||
uint8_t power = 9; //power and pre-emption indicator
|
||||
uint8_t lcss = 9;
|
||||
|
||||
//dummy bits to pass to dburst for link control
|
||||
uint8_t dummy_bits[196];
|
||||
memset (dummy_bits, 0, sizeof (dummy_bits));
|
||||
@@ -87,7 +92,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||
|
||||
cachdata[i] = dibit;
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
@@ -119,7 +124,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 36; 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+12] = dibit;
|
||||
|
||||
@@ -144,7 +149,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 18; 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+48] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
@@ -171,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 && vc < 6) //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
|
||||
{
|
||||
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
|
||||
@@ -180,17 +185,41 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
sync[24] = 0;
|
||||
|
||||
//test for RC sync pattern in MS sourced audio
|
||||
if ( strcmp (sync, DMR_RC_DATA_SYNC) == 0)
|
||||
{
|
||||
state->dmr_ms_rc = 1;
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
||||
|
||||
fprintf (stderr, "| RC ");
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i];
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40];
|
||||
|
||||
EmbeddedSignallingOk = -1;
|
||||
if(QR_16_7_6_decode(EmbeddedSignalling))
|
||||
{
|
||||
EmbeddedSignallingOk = 1;
|
||||
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
|
||||
for(i = 0; i < 18; 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+90] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
@@ -214,7 +243,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 36; 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+108] = dibit;
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
@@ -227,6 +256,20 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//'DSP' output to file
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 10 ", state->currentslot+1); //0x10 for "voice burst", forced to slot 1
|
||||
for (i = 6; i < 72; i++) //33 bytes, no CACH
|
||||
{
|
||||
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
state->dmr_ms_mode = 1;
|
||||
|
||||
memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2));
|
||||
@@ -238,22 +281,28 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
if (state->directmode == 0)
|
||||
if (state->dmr_ms_rc == 0)
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
if (state->directmode == 0)
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (vc == 6)
|
||||
{
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity
|
||||
dmr_sbrc (opts, state, power);
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
@@ -268,6 +317,12 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
|
||||
vc++;
|
||||
|
||||
//reset emb components
|
||||
cc = 25;
|
||||
power = 9; //power and pre-emption indicator
|
||||
lcss = 9;
|
||||
|
||||
//this is necessary because we need to skip and collect dibits, not just skip them
|
||||
if (vc > 6) goto END;
|
||||
|
||||
@@ -292,7 +347,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
dibit = getDibit(opts, state);
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
dibit = (dibit ^ 2) & 3;
|
||||
}
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
|
||||
@@ -379,7 +434,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
dibit = state->dmr_stereo_payload[i];
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
dibit = (dibit ^ 2) & 3;
|
||||
}
|
||||
cachdata[i] = dibit;
|
||||
}
|
||||
@@ -398,7 +453,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
dibit = state->dmr_stereo_payload[i+12];
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
dibit = (dibit ^ 2) & 3;
|
||||
}
|
||||
state->dmr_stereo_payload[i+12] = dibit;
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
@@ -425,7 +480,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
dibit = state->dmr_stereo_payload[i+48];
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
dibit = (dibit ^ 2) & 3;
|
||||
}
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
@@ -443,8 +498,9 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
dibit = (dibit ^ 2) & 3;
|
||||
}
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -469,8 +525,9 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
dibit = (dibit ^ 2) & 3;
|
||||
}
|
||||
state->dmr_stereo_payload[i+108] = dibit;
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -481,6 +538,20 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//'DSP' output to file
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 10 ", state->currentslot+1); //0x10 for "voice burst", force to slot 1
|
||||
for (i = 6; i < 72; i++) //33 bytes, no CACH
|
||||
{
|
||||
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
@@ -517,7 +588,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
//collect the mi fragment
|
||||
dmr_late_entry_mi_fragment (opts, state, 1, ambe_fr, ambe_fr2, ambe_fr3);
|
||||
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
||||
|
||||
//errors due to skipping other slot
|
||||
// cach_err = dmr_cach (opts, state, cachdata);
|
||||
@@ -558,7 +629,7 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
|
||||
}
|
||||
@@ -566,7 +637,7 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
for (i = 0; i < 54; 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+90] = dibit;
|
||||
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR
|
||||
//maybe one day we will have more things to do here
|
||||
state->data_conf_data[slot] = 0; //flag off confirmed data after processing it
|
||||
state->data_p_head[slot] = 0; //flag off prop_head data after processing it
|
||||
state->data_header_format[slot] = 0; //zero out so we don't keep ascii printing
|
||||
|
||||
}
|
||||
|
||||
|
||||
23
src/dmr_pi.c
23
src/dmr_pi.c
@@ -29,7 +29,7 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 1");
|
||||
fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||||
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 2");
|
||||
fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
||||
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
@@ -73,21 +73,6 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if((IrrecoverableErrors == 0) && CRCCorrect)
|
||||
{
|
||||
//fprintf (stderr, " (PI CRC Okay)");
|
||||
}
|
||||
else if((IrrecoverableErrors == 0))
|
||||
{
|
||||
//fprintf (stderr, " (PI FEC Okay)");
|
||||
}
|
||||
else {
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, (" (PI FEC ERR)"));
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LFSR(dsd_state * state)
|
||||
@@ -114,7 +99,7 @@ void LFSR(dsd_state * state)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Slot 1");
|
||||
fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
|
||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
|
||||
fprintf(stderr, " Next MI: 0x%08X", lfsr);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
@@ -127,7 +112,7 @@ void LFSR(dsd_state * state)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Slot 2");
|
||||
fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
|
||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
|
||||
fprintf(stderr, " Next MI: 0x%08X", lfsr);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
112
src/dmr_utils.c
112
src/dmr_utils.c
@@ -4,7 +4,7 @@
|
||||
//Original Source - https://github.com/LouisErigHerve/dsd
|
||||
|
||||
//Additional Functions
|
||||
//Hamming17123, crc8, crc8ok functions
|
||||
//Hamming17123, crc7, crc8, crc8ok functions
|
||||
//Original Souce - https://github.com/boatbod/op25
|
||||
|
||||
#include "dsd.h"
|
||||
@@ -121,6 +121,31 @@ bool crc8_ok(uint8_t bits[], unsigned int len)
|
||||
return (crc == crc8(bits,len));
|
||||
}
|
||||
|
||||
uint8_t crc7(uint8_t bits[], unsigned int len)
|
||||
{
|
||||
uint8_t crc=0;
|
||||
unsigned int K = 7;
|
||||
//G7(x) = x7 + x5 + x2 + x + 1 check poly below for correct (dmr rc crc7)
|
||||
uint8_t poly[8] = {1,0,1,0,0,1,1,1}; // crc7 poly
|
||||
uint8_t buf[256];
|
||||
if (len+K > sizeof(buf)) {
|
||||
// fprintf (stderr, "crc8: buffer length %u exceeds maximum %lu\n", len+K, sizeof(buf));
|
||||
return 0;
|
||||
}
|
||||
memset (buf, 0, sizeof(buf));
|
||||
for (unsigned int i=0; i<len; i++){
|
||||
buf[i] = bits[i];
|
||||
}
|
||||
for (unsigned int i=0; i<len; i++)
|
||||
if (buf[i])
|
||||
for (unsigned int j=0; j<K+1; j++)
|
||||
buf[i+j] ^= poly[j];
|
||||
for (unsigned int i=0; i<K; i++){
|
||||
crc = (crc << 1) + buf[len + i];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief : This function compute the CRC-CCITT of the DMR data
|
||||
* by using the polynomial x^16 + x^12 + x^5 + 1
|
||||
@@ -329,4 +354,87 @@ uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
|
||||
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
|
||||
*
|
||||
* @return The 9 bit CRC
|
||||
*/
|
||||
*/
|
||||
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData)
|
||||
{
|
||||
uint32_t i;
|
||||
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
|
||||
/* Polynomial x^9 + x^6 + x^4 + x^3 + 1
|
||||
* Normal = 0x059
|
||||
* Reciprocal = 0x134
|
||||
* Reversed reciprocal = 0x12C */
|
||||
uint16_t Polynome = 0x059;
|
||||
for(i = 0; i < NbData; i++)
|
||||
{
|
||||
if(((CRC >> 8) & 1) ^ (DMRData[i] & 1))
|
||||
{
|
||||
CRC = (CRC << 1) ^ Polynome;
|
||||
}
|
||||
else
|
||||
{
|
||||
CRC <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Conserve only the 9 LSBs */
|
||||
CRC &= 0x01FF;
|
||||
|
||||
/* Invert the CRC */
|
||||
CRC ^= 0x01FF;
|
||||
|
||||
/* Return the CRC */
|
||||
return CRC;
|
||||
} /* End ComputeCrc9Bit() */
|
||||
|
||||
/*
|
||||
* @brief : This function compute the CRC-32 of the DMR data
|
||||
* by using the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
|
||||
*
|
||||
* @param Input : A buffer pointer of the DMR data (80 bytes)
|
||||
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
|
||||
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
|
||||
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
|
||||
*
|
||||
* @param NbData : The number of bit to compute
|
||||
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
|
||||
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
|
||||
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
|
||||
*
|
||||
* @return The 32 bit CRC
|
||||
*/
|
||||
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t CRC = 0x00000000; /* Initialization value = 0x00000000 */
|
||||
/* Polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
|
||||
* Normal = 0x04C11DB7
|
||||
* Reversed = 0xEDB88320
|
||||
* Reciprocal = 0xDB710641
|
||||
* Reversed reciprocal = 0x82608EDB */
|
||||
uint32_t Polynome = 0x04C11DB7;
|
||||
for(i = 0; i < NbData; i++)
|
||||
{
|
||||
if(((CRC >> 31) & 1) ^ (DMRData[i] & 1))
|
||||
{
|
||||
CRC = (CRC << 1) ^ Polynome;
|
||||
}
|
||||
else
|
||||
{
|
||||
CRC <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//for whatever reason, we get the CRC returned in a reversed byte order (MSO LSO b***s***)
|
||||
uint32_t a, b, c, d;
|
||||
a = b = c = d = 0;
|
||||
a = (CRC & 0xFF) << 24;
|
||||
b = (CRC & 0xFF00) >> 8;
|
||||
b = b << 16;
|
||||
c = (CRC & 0xFF0000) >> 16;
|
||||
c = c << 8;
|
||||
d = (CRC & 0xFF000000) >> 24;
|
||||
|
||||
CRC = a + b + c + d;
|
||||
/* Return the CRC */
|
||||
return CRC;
|
||||
} /* End ComputeCrc32Bit() */
|
||||
|
||||
261
src/dpmr_voice.c
261
src/dpmr_voice.c
@@ -24,11 +24,18 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t CCH[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
|
||||
uint8_t CCHDescrambled[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
|
||||
uint8_t CCHDeInterleaved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
|
||||
uint8_t CCHDataHammingCorrected[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][48] = {0};
|
||||
uint8_t CCHDataCRC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
|
||||
uint8_t CCHDataCRCComputed[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
|
||||
uint8_t CCHDataHammingCorrected[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][48];
|
||||
uint8_t CCHDataCRC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
||||
|
||||
memset (CCHDataHammingCorrected, 1, sizeof(CCHDataHammingCorrected));
|
||||
memset (CCHDataCRC, 1, sizeof(CCHDataCRC));
|
||||
|
||||
uint8_t CCHDataCRCComputed[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
|
||||
memset (CCHDataCRCComputed, 0, sizeof(CCHDataCRCComputed));
|
||||
|
||||
uint8_t CC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE / 2][24] = {0};
|
||||
char ambe_fr[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][4][24] = {0};
|
||||
char ambe_fr[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][4][24];
|
||||
memset (ambe_fr, 0, sizeof (ambe_fr));
|
||||
const int *w, *x, *y, *z;
|
||||
uint32_t ScramblerLFSR = 0;
|
||||
bool correctable = true;
|
||||
@@ -56,11 +63,6 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t CalledID[8] = {0};
|
||||
uint8_t CallingID[8] = {0};
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
//fprintf(stderr, "VOICE e:");
|
||||
}
|
||||
|
||||
/* First CCH (Control CHannel) - 72 bit */
|
||||
k = 0;
|
||||
|
||||
@@ -76,7 +78,6 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
CCH[0][(i * 2)] = (1 & (dibit >> 1)); // bit 1
|
||||
CCH[0][(i * 2) + 1] = (1 & dibit); // bit 0
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */
|
||||
@@ -148,9 +149,6 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
/* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */
|
||||
|
||||
//Sync issues occur when FS2 occurs immediatly after the 4th rep, so cutting of 4 early to gain constant resync
|
||||
//probably can't resync fast enough when the next sync starts immediately after the 4th rep of 36 dibits
|
||||
//consider writing a method that will loop this entire process based on the frame numbering found inside the CCH info, is that possible?
|
||||
k = 0;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
@@ -177,16 +175,10 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
//should be fixed now with the frame_sync t_max setup
|
||||
//no more early breaking required
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the Hamming (12,8) error code detection
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_12_8_init();
|
||||
|
||||
/* Decoding all CCH (Control CHannel) */
|
||||
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
|
||||
{
|
||||
@@ -207,22 +199,8 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
if(HammingCorrectable[i][j] == false) correctable = false;
|
||||
}
|
||||
|
||||
if(correctable)
|
||||
{
|
||||
|
||||
//fprintf(stderr, "CCH data corrected successfully\n");
|
||||
|
||||
|
||||
HammingOk[i] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//fprintf(stderr, "ERROR !!! CCH data contains uncorrectable bit\n");
|
||||
|
||||
|
||||
HammingOk[i] = 0;
|
||||
}
|
||||
if(correctable) HammingOk[i] = 1;
|
||||
else HammingOk[i] = 0;
|
||||
|
||||
/* Reconstitute the 7 bit CRC */
|
||||
CCHDataCRC[i] = 0;
|
||||
@@ -237,24 +215,8 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
/* Compute the 7 bit CRC */
|
||||
CCHDataCRCComputed[i] = CRC7BitdPMR(CCHDataHammingCorrected[i], 41);
|
||||
|
||||
if(CCHDataCRC[i] == CCHDataCRCComputed[i])
|
||||
{
|
||||
|
||||
//fprintf(stderr, "Good CCH CRCs ! CRC received = 0x%02X, CRC computed = 0x%02X\n",
|
||||
// CCHDataCRC[i], CCHDataCRCComputed[i]);
|
||||
|
||||
|
||||
CrcOk[i] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//fprintf(stderr, "ERROR !!! CCH CRCs are different ! CRC received = 0x%02X, CRC computed = 0x%02X\n",
|
||||
// CCHDataCRC[i], CCHDataCRCComputed[i]);
|
||||
|
||||
|
||||
CrcOk[i] = 0;
|
||||
}
|
||||
if(CCHDataCRC[i] == CCHDataCRCComputed[i]) CrcOk[i] = 1;
|
||||
else CrcOk[i] = 0;
|
||||
|
||||
/* Fill the frame number */
|
||||
CCH_FrameNumber[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][0], 2);
|
||||
@@ -300,45 +262,18 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
CallingID[7] = '\0';
|
||||
|
||||
|
||||
/* Print Hamming debug info */
|
||||
//fprintf(stderr, " | ");
|
||||
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
|
||||
{
|
||||
//fprintf(stderr, "Hamming[%u]=", i);
|
||||
for(j = 0; j < 6; j++)
|
||||
{
|
||||
//if(HammingCorrectable[i][j]) fprintf(stderr, "1");
|
||||
//else fprintf(stderr, "0");
|
||||
}
|
||||
//fprintf(stderr, " HammingOk[%u]=%u", i, HammingOk[i]);
|
||||
//fprintf(stderr, " CrcOk[%u]=%u", i, CrcOk[i]);
|
||||
//fprintf(stderr, " Bit[%u]=", i);
|
||||
//for(j = 0; j < 7; j++)
|
||||
//{
|
||||
// if(CCHDataHammingCorrected[i][j + 41]) fprintf(stderr, "1");
|
||||
// else fprintf(stderr, "0");
|
||||
//}
|
||||
//fprintf(stderr, " CRCrec=0x%02X CRCcomp=0x%02X", CCHDataCRC[i], CCHDataCRCComputed[i]);
|
||||
//if(i < (NB_OF_DPMR_VOICE_FRAME_TO_DECODE - 1)) fprintf(stderr, " - ");
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if (NB_OF_DPMR_VOICE_FRAME_TO_DECODE == 2)
|
||||
/* To determine the part of the payload frame, we need to check the
|
||||
* Hamming code result, the CRC and the frame number */
|
||||
|
||||
// if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 0)) ||
|
||||
// (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 1)))
|
||||
|
||||
if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 0)) ||
|
||||
((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 1)))
|
||||
{
|
||||
/* First part of the super frame */
|
||||
PartOfSuperFrame = 1;
|
||||
|
||||
|
||||
//fprintf(stderr, "\nFirst part of the Super Frame");
|
||||
|
||||
|
||||
/* The next part will normally be the second part */
|
||||
opts->dPMR_next_part_of_superframe = 2;
|
||||
|
||||
@@ -366,20 +301,19 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
/* BUGFIX : Copy in all case the TG ID */
|
||||
strcpy((char *)state->dPMRVoiceFS2Frame.CalledID, (char *)CalledID);
|
||||
}
|
||||
|
||||
/* To determine the part of the payload frame, we need to check the
|
||||
* Hamming code result, the CRC and the frame number */
|
||||
|
||||
// else if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 2)) ||
|
||||
// (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 3)))
|
||||
|
||||
else if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 2)) ||
|
||||
((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 3)))
|
||||
{
|
||||
/* Second part of the super frame */
|
||||
PartOfSuperFrame = 2;
|
||||
|
||||
|
||||
//fprintf(stderr, "\nSecond part of the Super Frame");
|
||||
|
||||
|
||||
/* The next part will normally be the first part */
|
||||
opts->dPMR_next_part_of_superframe = 1;
|
||||
|
||||
@@ -392,7 +326,9 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
CallingID[7] = '\0';
|
||||
|
||||
/* Determine if the calling SRC ID is correct */
|
||||
|
||||
//if(HammingOk[0] && CrcOk[0] && HammingOk[1] && CrcOk[1])
|
||||
|
||||
if((CrcOk[0] || (HammingCorrectable[0][0] && HammingCorrectable[0][1])) &&
|
||||
(CrcOk[1] || (HammingCorrectable[1][0] && HammingCorrectable[1][1])))
|
||||
{
|
||||
@@ -420,132 +356,143 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
/* Set the next part of the superframe to receive */
|
||||
if(opts->dPMR_next_part_of_superframe == 1)
|
||||
{
|
||||
|
||||
|
||||
//fprintf(stderr, "Supposed first part of the Super Frame\n");
|
||||
|
||||
|
||||
/* Set the next part as the second part */
|
||||
opts->dPMR_next_part_of_superframe = 2;
|
||||
}
|
||||
else if(opts->dPMR_next_part_of_superframe == 2)
|
||||
{
|
||||
|
||||
//fprintf(stderr, "Supposed second part of the Super Frame\n");
|
||||
|
||||
|
||||
/* Set the next part as the first part */
|
||||
opts->dPMR_next_part_of_superframe = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
//fprintf(stderr, "Unknown part of the Super Frame\n");
|
||||
|
||||
|
||||
/* Unknown current part, set to 0 */
|
||||
opts->dPMR_next_part_of_superframe = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1))
|
||||
{
|
||||
//only print the CC and src/tg info if CRC is good
|
||||
/* Display the color code */
|
||||
//fprintf(stderr, " | Color Code=%02d ", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown color code, display "??" */
|
||||
//fprintf(stderr, " | Color Code=?? ");
|
||||
}
|
||||
|
||||
/* Display the destination ID (talk group - TG) */
|
||||
//fprintf(stderr, "| TG=%s", CalledID);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
if(state->dPMRVoiceFS2Frame.CalledIDOk)
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf(stderr, "\n| TG=%s", CalledID);
|
||||
fprintf(stderr, " TG=%s", CalledID);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//strcpy (state->dpmr_target_id, CalledID); //HERE HERE
|
||||
state->dpmr_target_id = CalledID;
|
||||
//fprintf(stderr, " (CRC OK) ");
|
||||
|
||||
//check other as well before assigning
|
||||
if(state->dPMRVoiceFS2Frame.CallingIDOk) sprintf (state->dpmr_target_id, "%s", CalledID);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, " TG=(CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
/* Display the source ID */
|
||||
if(state->dPMRVoiceFS2Frame.CallingIDOk)
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf(stderr, " Src=%s", CallingID);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//check other as well before assigning
|
||||
if(state->dPMRVoiceFS2Frame.CalledIDOk) sprintf (state->dpmr_caller_id, "%s", CallingID);
|
||||
|
||||
//stashed channel code in here, more likely to be correct, but no guarantee
|
||||
if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1))
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf(stderr, " | Color Code=%02d ", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
|
||||
fprintf(stderr, " Channel Code=%02d", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
state->dpmr_color_code = (int)state->dPMRVoiceFS2Frame.ColorCode[0];
|
||||
|
||||
//check other as well before assigning
|
||||
if(state->dPMRVoiceFS2Frame.CalledIDOk) state->dpmr_color_code = (int)state->dPMRVoiceFS2Frame.ColorCode[0];
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf(stderr, " (CRC ERR) ");
|
||||
}
|
||||
|
||||
/* Display the source ID */
|
||||
//fprintf(stderr, "| Src=%s", CallingID);
|
||||
if(state->dPMRVoiceFS2Frame.CallingIDOk)
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf(stderr, "| Src=%s", CallingID);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//strcpy (state->dpmr_caller_id, CallingID);
|
||||
state->dpmr_caller_id = CallingID;
|
||||
|
||||
//fprintf(stderr, " (CRC OK) \n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, " (CRC ERR) \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf(stderr, " Src=(CRC ERR) Channel Code =(CRC ERR)");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
#endif /* (NB_OF_DPMR_VOICE_FRAME_TO_DECODE == 2) */
|
||||
if (state->dPMRVoiceFS2Frame.Version[0] == 3)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " Scrambler");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
if (state->R != 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Key %05lld ", state->R );
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
//Play only voice frames by first looking to see if there is a TCH voice in CommunicationMode,
|
||||
//then sending it to be processed by processMbeFrame, its much cleaner this way
|
||||
short start = 0;
|
||||
short end = 4;
|
||||
|
||||
//not really even sure why I made this loop
|
||||
//I probably should actually read the manual again
|
||||
for (short o = 0; o < 2; o++)
|
||||
{
|
||||
|
||||
//reset scrambler key seed on frame 0
|
||||
if (state->dPMRVoiceFS2Frame.FrameNumbering[o] == 0) state->payload_miN = 0;
|
||||
|
||||
//depending on first or second TCH, set start and end variables appropriately
|
||||
if (o == 1)
|
||||
{
|
||||
start = 4;
|
||||
end = 8;
|
||||
//add extra line break on second repitition only when dumping payload to console
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
//fprintf (stderr, "\nCommunication Mode: %d\n", state->dPMRVoiceFS2Frame.CommunicationMode[o]);
|
||||
//fprintf (stderr, "Encryption Mode: %d\n", state->dPMRVoiceFS2Frame.Version[o]);
|
||||
//fprintf (stderr, "Superframe Number: %d", state->dPMRVoiceFS2Frame.FrameNumbering[o]); //should be 1-4, but may be same number on TCH 1 or TCH 2
|
||||
|
||||
//this is used so we can simply pass the voice here to the
|
||||
//nxdn scrambler by telling mbe these are nxdn frames and to
|
||||
//apply the same descramble method to them if necessary
|
||||
int realsynctype = state->synctype;
|
||||
|
||||
// fprintf (stderr, "\nCommunication Mode: %d\n", state->dPMRVoiceFS2Frame.CommunicationMode[o]);
|
||||
// fprintf (stderr, "Encryption Mode: %d\n", state->dPMRVoiceFS2Frame.Version[o]); //shows as 3 (manufacturer specific, 5.16) on the dPMR scrambler values received
|
||||
// fprintf (stderr, "Superframe Number: %d", state->dPMRVoiceFS2Frame.FrameNumbering[o]);
|
||||
|
||||
if((state->dPMRVoiceFS2Frame.CommunicationMode[o] == 0) ||
|
||||
(state->dPMRVoiceFS2Frame.CommunicationMode[o] == 1) ||
|
||||
(state->dPMRVoiceFS2Frame.CommunicationMode[o] == 5))
|
||||
{
|
||||
|
||||
//There are 4 AMBE voice samples per TCH
|
||||
//check to see if we are using scrambler
|
||||
if (state->dPMRVoiceFS2Frame.Version[o] == 3) //!= 0
|
||||
{
|
||||
state->synctype = 28; //fake it as nxdn
|
||||
state->nxdn_cipher_type = 0x01; //turn on nxdn scrambler cipher
|
||||
state->dmr_encL = 1; //flag on enc bit here so we can mute if no key provided
|
||||
}
|
||||
|
||||
//flag back off if key is provided
|
||||
if (state->R != 0) state->dmr_encL = 0;
|
||||
|
||||
//There are 4 AMBE voice frames per TCH
|
||||
for(i = start; i < end; i++)
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
|
||||
} //End for(i = start; i < end); i++)
|
||||
} //if comms and not encrypted
|
||||
}//End for TCH for o loop
|
||||
}
|
||||
|
||||
//set the correct sync type again and flag off the cipher
|
||||
state->synctype = realsynctype;
|
||||
state->nxdn_cipher_type = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
//keep code below, could be handy cheat sheet for other info
|
||||
#ifdef dPMR_PRINT_DEBUG_INFO
|
||||
|
||||
@@ -444,17 +444,18 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (state->audio_out_idx > opts->delay)
|
||||
{
|
||||
// output synthesized speech to sound card
|
||||
if(opts->audio_out_type == 2)
|
||||
{
|
||||
//go F yourself PA
|
||||
}
|
||||
else
|
||||
if (opts->audio_out_type == 5) //OSS
|
||||
{
|
||||
//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.
|
||||
//OSS
|
||||
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
||||
state->audio_out_idx = 0;
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
}
|
||||
@@ -478,15 +479,18 @@ 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 == 2)
|
||||
{
|
||||
//go F yourself PA
|
||||
}
|
||||
else
|
||||
if (opts->audio_out_type == 5) //OSS
|
||||
{
|
||||
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.
|
||||
//OSS
|
||||
result = write (opts->audio_out_fdR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2));
|
||||
state->audio_out_idxR = 0;
|
||||
}
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
@@ -558,6 +562,7 @@ openAudioInDevice (dsd_opts * opts)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strncmp(opts->audio_in_dev, "tcp", 3) == 0)
|
||||
{
|
||||
opts->audio_in_type = 8;
|
||||
@@ -567,13 +572,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;
|
||||
@@ -598,6 +603,10 @@ openAudioInDevice (dsd_opts * opts)
|
||||
{
|
||||
opts->audio_in_type = 0;
|
||||
}
|
||||
else if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
opts->audio_in_type = 5;
|
||||
}
|
||||
else if (strncmp(extension, ".bin", 3) == 0)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
@@ -645,9 +654,11 @@ openAudioInDevice (dsd_opts * opts)
|
||||
|
||||
}
|
||||
//open pulse audio if no bin or wav
|
||||
else
|
||||
else //seems this condition is never met
|
||||
{
|
||||
opts->audio_in_type = 0; //not sure if this works or needs to openPulse here
|
||||
//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);
|
||||
}
|
||||
}
|
||||
if (opts->split == 1)
|
||||
|
||||
237
src/dsd_file.c
237
src/dsd_file.c
@@ -34,7 +34,7 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
|
||||
}
|
||||
|
||||
char * getDateF(void) {
|
||||
char datename[120]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
||||
char datename[80]; //32-bit needs this to be 80
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
@@ -45,8 +45,7 @@ char * getDateF(void) {
|
||||
return curr2;
|
||||
}
|
||||
|
||||
void
|
||||
saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
@@ -56,36 +55,22 @@ saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
fputc (err, opts->mbe_out_f);
|
||||
|
||||
k = 0;
|
||||
if (opts->payload == 1) //make opt variable later on to toggle this
|
||||
{
|
||||
//fprintf(stderr, "\n IMBE ");
|
||||
}
|
||||
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
b = 0;
|
||||
{
|
||||
b = 0;
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + imbe_d[k];
|
||||
k++;
|
||||
}
|
||||
if (opts->payload == 1) //make opt variable later on to toggle this
|
||||
{
|
||||
//fprintf (stderr, "%02X", b);
|
||||
}
|
||||
fputc (b, opts->mbe_out_f);
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
//fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
|
||||
}
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + imbe_d[k];
|
||||
k++;
|
||||
}
|
||||
fputc (b, opts->mbe_out_f);
|
||||
}
|
||||
fflush (opts->mbe_out_f);
|
||||
}
|
||||
|
||||
void
|
||||
saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
@@ -95,42 +80,49 @@ saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
fputc (err, opts->mbe_out_f);
|
||||
|
||||
k = 0;
|
||||
if (opts->payload == 1) //make opt variable later on to toggle this
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
//fprintf(stderr, "\n AMBE ");
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
}
|
||||
fputc (b, opts->mbe_out_f);
|
||||
}
|
||||
//for (i = 0; i < 6; i++)
|
||||
for (i = 0; i < 6; i++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more
|
||||
{
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
}
|
||||
if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this
|
||||
{
|
||||
//fprintf (stderr, "%02X", b);
|
||||
}
|
||||
if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit? value will be either 0x00 or 0x80?
|
||||
{
|
||||
//fprintf (stderr, "%02X", b & 0x80); //7th octet should only contain 1 bit?
|
||||
}
|
||||
|
||||
fputc (b, opts->mbe_out_f);
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
//fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
|
||||
}
|
||||
b = ambe_d[48];
|
||||
fputc (b, opts->mbe_out_f);
|
||||
fflush (opts->mbe_out_f);
|
||||
}
|
||||
|
||||
void
|
||||
PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and ProVoice
|
||||
void saveAmbe2450DataR (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
unsigned char err;
|
||||
|
||||
err = (unsigned char) state->errs2R;
|
||||
fputc (err, opts->mbe_out_fR);
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
}
|
||||
fputc (b, opts->mbe_out_fR);
|
||||
}
|
||||
b = ambe_d[48];
|
||||
fputc (b, opts->mbe_out_fR);
|
||||
fflush (opts->mbe_out_fR);
|
||||
}
|
||||
|
||||
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and ProVoice
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
@@ -165,8 +157,7 @@ PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and
|
||||
//fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
@@ -333,14 +324,21 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
|
||||
cookie[2] = fgetc (opts->mbe_in_f);
|
||||
cookie[3] = fgetc (opts->mbe_in_f);
|
||||
cookie[4] = 0;
|
||||
//ambe+2
|
||||
if (strstr (cookie, ".amb") != NULL)
|
||||
{
|
||||
state->mbe_file_type = 1;
|
||||
}
|
||||
{
|
||||
state->mbe_file_type = 1;
|
||||
}
|
||||
//p1 and pv
|
||||
else if (strstr (cookie, ".imb") != NULL)
|
||||
{
|
||||
state->mbe_file_type = 0;
|
||||
}
|
||||
{
|
||||
state->mbe_file_type = 0;
|
||||
}
|
||||
//d-star ambe
|
||||
else if (strstr (cookie, ".dmb") != NULL)
|
||||
{
|
||||
state->mbe_file_type = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->mbe_file_type = -1;
|
||||
@@ -349,7 +347,7 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//much simpler version
|
||||
//slot 1
|
||||
void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if (opts->mbe_out == 1)
|
||||
@@ -360,48 +358,67 @@ void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
fclose (opts->mbe_out_f);
|
||||
opts->mbe_out_f = NULL;
|
||||
opts->mbe_out = 0;
|
||||
fprintf (stderr, "\nClosing MBE out file.");
|
||||
fprintf (stderr, "\nClosing MBE out file 1.\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
//slot 2
|
||||
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if (opts->mbe_outR == 1)
|
||||
{
|
||||
if (opts->mbe_out_fR != NULL)
|
||||
{
|
||||
fflush (opts->mbe_out_fR);
|
||||
fclose (opts->mbe_out_fR);
|
||||
opts->mbe_out_fR = NULL;
|
||||
opts->mbe_outR = 0;
|
||||
fprintf (stderr, "\nClosing MBE out file 2.\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int i, j;
|
||||
char ext[5];
|
||||
|
||||
if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
|
||||
{
|
||||
sprintf (ext, ".imb");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (ext, ".amb");
|
||||
}
|
||||
//phase 1 and provoice
|
||||
if ( (state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15) )
|
||||
{
|
||||
sprintf (ext, ".imb");
|
||||
}
|
||||
//d-star
|
||||
else if ( (state->synctype == 6) || (state->synctype == 7) || (state->synctype == 18) || (state->synctype == 19) )
|
||||
{
|
||||
sprintf (ext, ".dmb"); //new dstar file extension to make it read in and process properly
|
||||
}
|
||||
//dmr, nxdn, phase 2, x2-tdma
|
||||
else sprintf (ext, ".amb");
|
||||
|
||||
// reset talkgroup id buffer
|
||||
//reset talkgroup id buffer
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
for (j = 0; j < 25; j++)
|
||||
{
|
||||
for (j = 0; j < 25; j++)
|
||||
{
|
||||
state->tg[j][i] = 0;
|
||||
}
|
||||
state->tg[j][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
state->tgcount = 0;
|
||||
|
||||
sprintf (opts->mbe_out_file, "%s %s%s", getDateF(), getTimeF(), ext);
|
||||
sprintf (opts->mbe_out_file, "%s %s S1%s", getDateF(), getTimeF(), ext);
|
||||
|
||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
|
||||
|
||||
opts->mbe_out_f = fopen (opts->mbe_out_path, "w");
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
fprintf (stderr,"Error, couldn't open %s\n", opts->mbe_out_path);
|
||||
fprintf (stderr,"\nError, couldn't open %s for slot 1\n", opts->mbe_out_path);
|
||||
}
|
||||
else opts->mbe_out = 1;
|
||||
|
||||
@@ -411,8 +428,54 @@ openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
fflush (opts->mbe_out_f);
|
||||
}
|
||||
|
||||
void
|
||||
openWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int i, j;
|
||||
char ext[5];
|
||||
|
||||
//phase 1 and provoice
|
||||
if ( (state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15) )
|
||||
{
|
||||
sprintf (ext, ".imb");
|
||||
}
|
||||
//d-star
|
||||
else if ( (state->synctype == 6) || (state->synctype == 7) || (state->synctype == 18) || (state->synctype == 19) )
|
||||
{
|
||||
sprintf (ext, ".dmb"); //new dstar file extension to make it read in and process properly
|
||||
}
|
||||
//dmr, nxdn, phase 2, x2-tdma
|
||||
else sprintf (ext, ".amb");
|
||||
|
||||
//reset talkgroup id buffer
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
for (j = 0; j < 25; j++)
|
||||
{
|
||||
state->tg[j][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
state->tgcount = 0;
|
||||
|
||||
sprintf (opts->mbe_out_fileR, "%s %s S2%s", getDateF(), getTimeF(), ext);
|
||||
|
||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_fileR);
|
||||
|
||||
opts->mbe_out_fR = fopen (opts->mbe_out_path, "w");
|
||||
if (opts->mbe_out_fR == NULL)
|
||||
{
|
||||
fprintf (stderr,"\nError, couldn't open %s for slot 2\n", opts->mbe_out_path);
|
||||
}
|
||||
else opts->mbe_outR = 1;
|
||||
|
||||
//
|
||||
fprintf (opts->mbe_out_fR, "%s", ext);
|
||||
|
||||
fflush (opts->mbe_out_fR);
|
||||
}
|
||||
|
||||
void openWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
SF_INFO info;
|
||||
|
||||
451
src/dsd_frame.c
451
src/dsd_frame.c
@@ -87,8 +87,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
//NXDN FSW
|
||||
if ((state->synctype == 28) || (state->synctype == 29))
|
||||
{
|
||||
nxdn_frame (opts, state);
|
||||
//no MBEout...use symbol capture bin instead!
|
||||
//MBEout restored, is not handled internally by nxdn_frame.c
|
||||
nxdn_frame (opts, state);
|
||||
return;
|
||||
}
|
||||
else if ((state->synctype == 6) || (state->synctype == 7))
|
||||
@@ -107,7 +107,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
state->nac = 0;
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
openMbeOutFile (opts, state); //dstar ambe files are read back incorrectly, need to change file extension to differentiate when doing a playback
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processDSTAR (opts, state);
|
||||
@@ -128,9 +128,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
state->nac = 0;
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
{
|
||||
openMbeOutFile (opts, state); //dstar ambe files are read back incorrectly, need to change file extension to differentiate when doing a playback
|
||||
}
|
||||
sprintf (state->fsubtype, " DATA ");
|
||||
processDSTAR_HD (opts, state);
|
||||
return;
|
||||
@@ -141,9 +141,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//print manufacturer strings to branding, disabled 0x10 moto other systems can use that fid set
|
||||
//0x06 is trident, but when searching, apparently, they developed con+, but was bought by moto?
|
||||
if (state->dmr_mfid == 0x10) ; //sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
else if (state->dmr_mfid == 0x68) sprintf (state->dmr_branding, "%s", "Hytera");
|
||||
else if (state->dmr_mfid == 0x58) sprintf (state->dmr_branding, "%s", "Tait");
|
||||
if (state->dmr_mfid == 0x10) ; //sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
else if (state->dmr_mfid == 0x68) sprintf (state->dmr_branding, "%s", " Hytera");
|
||||
else if (state->dmr_mfid == 0x58) sprintf (state->dmr_branding, "%s", " Tait");
|
||||
|
||||
//disabling these due to random data decodes setting an odd mfid, could be legit, but only for that one packet?
|
||||
//or, its just a decode error somewhere
|
||||
@@ -164,70 +164,58 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//disable so radio id doesn't blink in and out during ncurses and aggressive_framesync
|
||||
state->nac = 0;
|
||||
//state->lastsrc = 0;
|
||||
//state->lasttg = 0;
|
||||
//state->lastsrcR = 0;
|
||||
//state->lasttgR = 0;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
level = (int) state->max / 164;
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
if ( (state->synctype == 11) || (state->synctype == 12) || (state->synctype == 32) ) //DMR Voice Modes
|
||||
{
|
||||
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
|
||||
{
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL) && opts->dmr_stereo == 0)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
|
||||
{
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_mono == 1 && state->synctype == 32)
|
||||
{
|
||||
// fprintf (stderr, "%s", KRED);
|
||||
// fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
||||
{
|
||||
state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames
|
||||
if (state->synctype > 31 )
|
||||
{
|
||||
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
|
||||
}
|
||||
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
|
||||
}
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_mono == 1 && state->synctype == 32)
|
||||
{
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
||||
{
|
||||
state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames
|
||||
if (state->synctype > 31 )
|
||||
{
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
|
||||
}
|
||||
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
|
||||
}
|
||||
}
|
||||
else if ( (state->synctype == 33) || (state->synctype == 34) ) //MS Data and RC data
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
dmrMSData (opts, state);
|
||||
// if (opts->dmr_stereo == 0)
|
||||
// {
|
||||
// closeMbeOutFile (opts, state);
|
||||
// state->err_str[0] = 0;
|
||||
// fprintf (stderr, "%s", KRED);
|
||||
// fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// }
|
||||
// if (opts->dmr_stereo == 1)
|
||||
// {
|
||||
// dmrMSData (opts, state);
|
||||
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts->dmr_stereo == 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
@@ -237,6 +225,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
|
||||
if (opts->dmr_stereo == 1)
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
state->dmr_stereo = 0; //set the state to zero for handling pure data frames
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
@@ -246,7 +237,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if ((state->synctype >= 2) && (state->synctype <= 5))
|
||||
//X2-TDMA
|
||||
else if ((state->synctype >= 2) && (state->synctype <= 5))
|
||||
{
|
||||
state->nac = 0;
|
||||
if (opts->errorbars == 1)
|
||||
@@ -256,15 +248,15 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if ((state->synctype == 3) || (state->synctype == 4))
|
||||
{
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processX2TDMAvoice (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
state->err_str[0] = 0;
|
||||
processX2TDMAdata (opts, state);
|
||||
}
|
||||
@@ -272,21 +264,18 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else if ((state->synctype == 14) || (state->synctype == 15))
|
||||
{
|
||||
//state->nac = 0;
|
||||
//state->lastsrc = 0;
|
||||
//state->lasttg = 0;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
level = (int) state->max / 164;
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processProVoice (opts, state);
|
||||
return;
|
||||
@@ -294,6 +283,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
//edacs
|
||||
else if ((state->synctype == 37) || (state->synctype == 38))
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
edacs (opts, state);
|
||||
return;
|
||||
}
|
||||
@@ -313,13 +303,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
//P25 P2
|
||||
else if ((state->synctype == 35) || (state->synctype == 36))
|
||||
{
|
||||
//Do stuff
|
||||
//fprintf(stderr, "YSF Sync! \n");
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
//openMbeOutFile (opts, state);
|
||||
}
|
||||
//sprintf(state->fsubtype, " VOICE ");
|
||||
//relocate MBEout to inside frame handling
|
||||
processP2(opts, state);
|
||||
return;
|
||||
}
|
||||
@@ -328,6 +312,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
/* dPMR Frame Sync 1 */
|
||||
fprintf(stderr, "dPMR Frame Sync 1 ");
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
else if ((state->synctype == 21) || (state->synctype == 25))
|
||||
{
|
||||
@@ -346,12 +331,12 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
state->nac = 0;
|
||||
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf(state->fsubtype, " VOICE ");
|
||||
processdPMRvoice (opts, state);
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf(state->fsubtype, " VOICE ");
|
||||
processdPMRvoice (opts, state);
|
||||
|
||||
return;
|
||||
|
||||
@@ -360,11 +345,13 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
/* dPMR Frame Sync 3 */
|
||||
fprintf(stderr, "dPMR Frame Sync 3 ");
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
else if ((state->synctype == 23) || (state->synctype == 27))
|
||||
{
|
||||
/* dPMR Frame Sync 4 */
|
||||
fprintf(stderr, "dPMR Frame Sync 4 ");
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
//dPMR
|
||||
else //P25
|
||||
@@ -463,15 +450,15 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// Header Data Unit
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," HDU\n");
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," HDU\n");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_f == NULL) openMbeOutFile (opts, state);
|
||||
}
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->lastp25type = 2;
|
||||
state->dmrburstL = 25;
|
||||
@@ -483,17 +470,17 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// Logical Link Data Unit 1
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," LDU1 ");
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," LDU1 ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
state->lastp25type = 1;
|
||||
state->dmrburstL = 26;
|
||||
state->currentslot = 0;
|
||||
@@ -514,27 +501,27 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (state->lastp25type != 1)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr,"\n Ignoring LDU2 not preceeded by LDU1\n");
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr,"\n Ignoring LDU2 not preceeded by LDU1\n");
|
||||
}
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," LDU2 ");
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," LDU2 ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
state->lastp25type = 2;
|
||||
sprintf (state->fsubtype, " LDU2 ");
|
||||
state->numtdulc = 0;
|
||||
@@ -546,14 +533,14 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
// Terminator with subsequent Link Control
|
||||
state->dmrburstL = 28;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," TDULC\n");
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," TDULC\n");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
@@ -562,9 +549,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
sprintf (state->fsubtype, " TDULC ");
|
||||
state->numtdulc++;
|
||||
if ((opts->resume > 0) && (state->numtdulc > opts->resume))
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
processTDULC (opts, state);
|
||||
state->err_str[0] = 0;
|
||||
}
|
||||
@@ -573,14 +560,14 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
// Terminator without subsequent Link Control
|
||||
state->dmrburstL = 28;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," TDU\n");
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," TDU\n");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
@@ -594,120 +581,126 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
state->dmrburstL = 29;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," TSBK");
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," TSBK");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
if (opts->resume > 0)
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lastp25type = 3;
|
||||
sprintf (state->fsubtype, " TSBK ");
|
||||
|
||||
// Now processing NID
|
||||
processTSBK(opts, state);
|
||||
|
||||
}
|
||||
else if (strcmp (duid, "30") == 0)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," PDU\n");
|
||||
}
|
||||
if (opts->resume > 0)
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," PDU\n"); //multi block/packet PDU
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
{
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
if (opts->resume > 0)
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
state->lastp25type = 4;
|
||||
sprintf (state->fsubtype, " PDU ");
|
||||
}
|
||||
// try to guess based on previous frame if unknown type
|
||||
else if (state->lastp25type == 1)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr,"(LDU2) ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
//state->lastp25type = 0;
|
||||
// Guess that the state is LDU2
|
||||
state->lastp25type = 2;
|
||||
sprintf (state->fsubtype, "(LDU2) ");
|
||||
state->numtdulc = 0;
|
||||
processLDU2 (opts, state);
|
||||
}
|
||||
else if (state->lastp25type == 2)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr,"(LDU1) ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
//state->lastp25type = 0;
|
||||
// Guess that the state is LDU1
|
||||
state->lastp25type = 1;
|
||||
sprintf (state->fsubtype, "(LDU1) ");
|
||||
state->numtdulc = 0;
|
||||
processLDU1 (opts, state);
|
||||
}
|
||||
else if (state->lastp25type == 3)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," (TSBK)\n");
|
||||
}
|
||||
//state->lastp25type = 0;
|
||||
// Guess that the state is TSBK
|
||||
state->lastp25type = 3;
|
||||
sprintf (state->fsubtype, "(TSBK) ");
|
||||
|
||||
// Now processing NID
|
||||
skipDibit (opts, state, 328-25);
|
||||
}
|
||||
else if (state->lastp25type == 4)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," (PDU)\n");
|
||||
}
|
||||
state->lastp25type = 0;
|
||||
}
|
||||
// try to guess based on previous frame if unknown type
|
||||
// disabling the guessing game on P1
|
||||
|
||||
// else if (state->lastp25type == 1)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr,"(LDU2) ");
|
||||
// }
|
||||
// // if (opts->mbe_out_dir[0] != 0)
|
||||
// // {
|
||||
// // if (opts->mbe_out_f == NULL)
|
||||
// // {
|
||||
// // openMbeOutFile (opts, state);
|
||||
// // }
|
||||
// // }
|
||||
// //state->lastp25type = 0;
|
||||
// // Guess that the state is LDU2
|
||||
// state->lastp25type = 2;
|
||||
// sprintf (state->fsubtype, "(LDU2) ");
|
||||
// state->numtdulc = 0;
|
||||
// processLDU2 (opts, state);
|
||||
// }
|
||||
// else if (state->lastp25type == 2)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr,"(LDU1) ");
|
||||
// }
|
||||
// if (opts->mbe_out_dir[0] != 0)
|
||||
// {
|
||||
// if (opts->mbe_out_f == NULL)
|
||||
// {
|
||||
// openMbeOutFile (opts, state);
|
||||
// }
|
||||
// }
|
||||
// //state->lastp25type = 0;
|
||||
// // Guess that the state is LDU1
|
||||
// state->lastp25type = 1;
|
||||
// sprintf (state->fsubtype, "(LDU1) ");
|
||||
// state->numtdulc = 0;
|
||||
// processLDU1 (opts, state);
|
||||
// }
|
||||
// else if (state->lastp25type == 3)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr," (TSBK)\n");
|
||||
// }
|
||||
// //state->lastp25type = 0;
|
||||
// // Guess that the state is TSBK
|
||||
// state->lastp25type = 3;
|
||||
// sprintf (state->fsubtype, "(TSBK) ");
|
||||
|
||||
// // Now processing NID
|
||||
// skipDibit (opts, state, 328-25);
|
||||
// }
|
||||
// else if (state->lastp25type == 4)
|
||||
// {
|
||||
// if (opts->errorbars == 1)
|
||||
// {
|
||||
// printFrameInfo (opts, state);
|
||||
// fprintf (stderr," (PDU)\n");
|
||||
// }
|
||||
// state->lastp25type = 0;
|
||||
// }
|
||||
|
||||
else
|
||||
{
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
|
||||
// fprintf (stderr, "\n"); //prints on dPMR frame 3
|
||||
}
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
|
||||
// fprintf (stderr, "\n"); //prints on dPMR frame 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,3 +145,48 @@ int csvChanImport(dsd_opts * opts, dsd_state * state) //channel map import
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support for NXDN
|
||||
{
|
||||
char filename[1024] = "filename.csv";
|
||||
sprintf (filename, "%s", opts->key_in_file);
|
||||
|
||||
char buffer[BSIZE];
|
||||
FILE * fp;
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
printf("Unable to open file '%s'\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
int row_count = 0;
|
||||
int field_count = 0;
|
||||
unsigned long long int keynumber;
|
||||
|
||||
while (fgets(buffer, BSIZE, fp)) {
|
||||
field_count = 0;
|
||||
row_count++;
|
||||
if (row_count == 1)
|
||||
continue; //don't want labels
|
||||
char * field = strtok(buffer, ","); //seperate by comma
|
||||
while (field) {
|
||||
|
||||
if (field_count == 0)
|
||||
{
|
||||
sscanf (field, "%lld", &keynumber);
|
||||
}
|
||||
|
||||
if (field_count == 1)
|
||||
{
|
||||
sscanf (field, "%lld", &state->rkey_array[keynumber]);
|
||||
}
|
||||
|
||||
field = strtok(NULL, ",");
|
||||
field_count++;
|
||||
}
|
||||
fprintf (stderr, "Key [%03lld] [%05lld]", keynumber, state->rkey_array[keynumber]);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
433
src/dsd_main.c
433
src/dsd_main.c
@@ -52,7 +52,7 @@ char * FM_banner[9] = {
|
||||
" ██║ ██║ ╚═══██╗██║ ██║ ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
|
||||
" ██████╔╝██████╔╝██████╔╝ ██║ ██║ ╚═╝ ██║███████╗",
|
||||
" ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝",
|
||||
" "
|
||||
" 'Lite' Edition v2.0.0-28-ga02f992 Windows 32-bit RC3 "
|
||||
};
|
||||
|
||||
int
|
||||
@@ -69,6 +69,7 @@ comp (const void *a, const void *b)
|
||||
//struct for checking existence of directory to write to
|
||||
struct stat st = {0};
|
||||
char wav_file_directory[1024] = {0};
|
||||
char dsp_filename[1024] = {0};
|
||||
unsigned long long int p2vars = 0;
|
||||
|
||||
char * pEnd; //bugfix
|
||||
@@ -125,6 +126,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
//zero out vc frequencies?
|
||||
state->p25_vc_freq[0] = 0;
|
||||
state->p25_vc_freq[1] = 0;
|
||||
|
||||
state->is_con_plus = 0; //flag off
|
||||
}
|
||||
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
@@ -133,10 +136,11 @@ 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
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
|
||||
//close MBE out files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
state->jitter = -1;
|
||||
state->lastsynctype = -1;
|
||||
state->carrier = 0;
|
||||
@@ -299,6 +303,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//initialize unified dmr pdu 'superframe'
|
||||
memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf));
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
|
||||
//init confirmed data individual block crc as invalid
|
||||
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
|
||||
@@ -317,8 +322,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
||||
|
||||
//REMUS! multi-purpose call_string
|
||||
sprintf (state->call_string[0], "%s", " "); //20 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //20 spaces
|
||||
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
|
||||
{
|
||||
@@ -332,6 +337,17 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
opts->p25_is_tuned = 0;
|
||||
}
|
||||
|
||||
opts->dPMR_next_part_of_superframe = 0;
|
||||
|
||||
state->dPMRVoiceFS2Frame.CalledIDOk = 0;
|
||||
state->dPMRVoiceFS2Frame.CallingIDOk = 0;
|
||||
memset(state->dPMRVoiceFS2Frame.CalledID, 0, 8);
|
||||
memset(state->dPMRVoiceFS2Frame.CallingID, 0, 8);
|
||||
memset(state->dPMRVoiceFS2Frame.Version, 0, 8);
|
||||
|
||||
sprintf (state->dpmr_caller_id, "%s", " ");
|
||||
sprintf (state->dpmr_target_id, "%s", " ");
|
||||
|
||||
} //nocarrier
|
||||
|
||||
void
|
||||
@@ -350,19 +366,22 @@ initOpts (dsd_opts * opts)
|
||||
opts->p25status = 0;
|
||||
opts->p25tg = 0;
|
||||
opts->scoperate = 15;
|
||||
sprintf (opts->audio_in_dev, "pulse");
|
||||
sprintf (opts->audio_in_dev, "/dev/dsp");
|
||||
opts->audio_in_fd = -1;
|
||||
|
||||
sprintf (opts->audio_out_dev, "pulse");
|
||||
sprintf (opts->audio_out_dev, "/dev/dsp");
|
||||
opts->audio_out_fd = -1;
|
||||
opts->audio_out_fdR = -1;
|
||||
|
||||
opts->split = 0;
|
||||
opts->playoffset = 0;
|
||||
opts->playoffsetR = 0;
|
||||
opts->mbe_out_dir[0] = 0;
|
||||
opts->mbe_out_file[0] = 0;
|
||||
opts->mbe_out_fileR[0] = 0; //second slot on a TDMA system
|
||||
opts->mbe_out_path[0] = 0;
|
||||
opts->mbe_out_f = NULL;
|
||||
opts->mbe_out_fR = NULL; //second slot on a TDMA system
|
||||
opts->audio_gain = 0; //0
|
||||
opts->audio_gainR = 0; //0
|
||||
opts->audio_out = 1;
|
||||
@@ -375,11 +394,13 @@ initOpts (dsd_opts * opts)
|
||||
opts->group_in_file[0] = 0;
|
||||
opts->lcn_in_file[0] = 0;
|
||||
opts->chan_in_file[0] = 0;
|
||||
opts->key_in_file[0] = 0;
|
||||
//end import filenames
|
||||
opts->szNumbers[0] = 0;
|
||||
opts->symbol_out_f = NULL;
|
||||
opts->symbol_out = 0;
|
||||
opts->mbe_out = 0;
|
||||
opts->mbe_outR = 0; //second slot on a TDMA system
|
||||
opts->wav_out_f = NULL;
|
||||
opts->wav_out_fR = NULL;
|
||||
opts->wav_out_raw = NULL;
|
||||
@@ -442,10 +463,10 @@ initOpts (dsd_opts * opts)
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->dmr_mono = 0;
|
||||
opts->dmr_stereo = 1;
|
||||
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->aggressive_framesync = 1;
|
||||
|
||||
opts->audio_in_type = 5;
|
||||
opts->audio_out_type = 5;
|
||||
|
||||
opts->lrrp_file_output = 0;
|
||||
|
||||
@@ -492,12 +513,27 @@ initOpts (dsd_opts * opts)
|
||||
//Trunking - Use Group List as Allow List
|
||||
opts->trunk_use_allow_list = 0; //disabled by default
|
||||
|
||||
//Trunking - Tune Group Calls
|
||||
opts->trunk_tune_group_calls = 1; //enabled by default
|
||||
|
||||
//Trunking - Tune Private Calls
|
||||
opts->trunk_tune_private_calls = 1; //enabled by default
|
||||
|
||||
//Trunking - Tune Data Calls
|
||||
opts->trunk_tune_data_calls = 0; //disabled by default
|
||||
|
||||
opts->dPMR_next_part_of_superframe = 0;
|
||||
|
||||
//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;
|
||||
|
||||
//dsp structured file
|
||||
opts->dsp_out_file[0] = 0;
|
||||
opts->use_dsp_output = 0;
|
||||
|
||||
} //initopts
|
||||
|
||||
void
|
||||
@@ -637,8 +673,6 @@ initState (dsd_state * state)
|
||||
state->payload_miN = 0;
|
||||
|
||||
state->dpmr_color_code = -1;
|
||||
state->dpmr_caller_id = 0;
|
||||
state->dpmr_target_id = 0;
|
||||
|
||||
state->payload_mi = 0;
|
||||
state->payload_miR = 0;
|
||||
@@ -671,10 +705,12 @@ initState (dsd_state * state)
|
||||
state->dmr_stereo = 0; //1, or 0?
|
||||
state->dmrburstL = 17; //initialize at higher value than possible
|
||||
state->dmrburstR = 17; //17 in char array is set for ERR
|
||||
state->dmr_so = 0;
|
||||
state->dmr_soR = 0;
|
||||
state->dmr_fid = 0;
|
||||
state->dmr_fidR = 0;
|
||||
state->dmr_so = 0;
|
||||
state->dmr_soR = 0;
|
||||
state->dmr_fid = 0;
|
||||
state->dmr_fidR = 0;
|
||||
state->dmr_flco = 0;
|
||||
state->dmr_flcoR = 0;
|
||||
state->dmr_ms_mode = 0;
|
||||
|
||||
state->HYTL = 0;
|
||||
@@ -718,12 +754,14 @@ initState (dsd_state * state)
|
||||
state->p2_wacn = 0;
|
||||
state->p2_sysid = 0;
|
||||
state->p2_cc = 0;
|
||||
state->p2_siteid = 0;
|
||||
state->p2_rfssid = 0;
|
||||
state->p2_hardset = 0;
|
||||
state->p2_is_lcch = 0;
|
||||
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 = 0; //throttle speed
|
||||
state->symbol_throttle = 100; //throttle speed
|
||||
state->use_throttle = 0; //only use throttle if set to 1
|
||||
|
||||
state->p2_scramble_offset = 0;
|
||||
@@ -767,9 +805,6 @@ initState (dsd_state * state)
|
||||
//dmr trunking/ncurses stuff
|
||||
state->dmr_rest_channel = -1; //init on -1
|
||||
state->dmr_mfid = -1; //
|
||||
state->dmr_tuned_lcn = -1; //logical slot, lcn * ts?
|
||||
state->dmr_vc_lcn = -1; //
|
||||
state->dmr_vc_lsn = -1;
|
||||
|
||||
//new nxdn stuff
|
||||
state->nxdn_part_of_frame = 0;
|
||||
@@ -783,7 +818,10 @@ initState (dsd_state * state)
|
||||
//site/srv/cch info
|
||||
state->nxdn_location_site_code = 0;
|
||||
state->nxdn_location_sys_code = 0;
|
||||
sprintf (state->nxdn_location_category, "%s", " ");
|
||||
sprintf (state->nxdn_location_category, "%s", " ");
|
||||
|
||||
//multi-key array
|
||||
memset (state->rkey_array, 0, sizeof(state->rkey_array));
|
||||
|
||||
//Remus DMR End Call Alert Beep
|
||||
state->dmr_end_alert[0] = 0;
|
||||
@@ -795,6 +833,7 @@ initState (dsd_state * state)
|
||||
|
||||
//initialize unified dmr pdu 'superframe'
|
||||
memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf));
|
||||
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
|
||||
|
||||
//init confirmed data individual block crc as invalid
|
||||
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
|
||||
@@ -814,14 +853,23 @@ initState (dsd_state * state)
|
||||
memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
||||
|
||||
//REMUS! multi-purpose call_string
|
||||
sprintf (state->call_string[0], "%s", " "); //20 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //20 spaces
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
|
||||
//late entry mi fragments
|
||||
memset (state->late_entry_mi_fragment, 0, sizeof (state->late_entry_mi_fragment));
|
||||
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
|
||||
state->dPMRVoiceFS2Frame.CalledIDOk = 0;
|
||||
state->dPMRVoiceFS2Frame.CallingIDOk = 0;
|
||||
memset(state->dPMRVoiceFS2Frame.CalledID, 0, 8);
|
||||
memset(state->dPMRVoiceFS2Frame.CallingID, 0, 8);
|
||||
memset(state->dPMRVoiceFS2Frame.Version, 0, 8);
|
||||
|
||||
sprintf (state->dpmr_caller_id, "%s", " ");
|
||||
sprintf (state->dpmr_target_id, "%s", " ");
|
||||
|
||||
} //init_state
|
||||
|
||||
void
|
||||
@@ -829,28 +877,18 @@ usage ()
|
||||
{
|
||||
|
||||
printf ("\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 ("Usage: dsd-fme-lite [options] Decoder/Trunking Mode\n");
|
||||
printf (" or: dsd-fme-lite [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" or: dsd-fme-lite -h Show help\n");
|
||||
printf ("\n");
|
||||
printf ("Display Options:\n");
|
||||
printf (" -N Use NCurses Terminal\n");
|
||||
printf (" dsd-fme -N 2> log.ans \n");
|
||||
printf (" dsd-fme-lite -N 2> log.ans \n");
|
||||
printf (" -Z Log MBE/PDU Payloads to console\n");
|
||||
// printf (" -e Show Frame Info and errorbars (default)\n");
|
||||
// printf (" -pe Show P25 encryption sync bits\n");
|
||||
// printf (" -pl Show P25 link control bits\n");
|
||||
// printf (" -ps Show P25 status bits and low speed data\n");
|
||||
// printf (" -pt Show P25 talkgroup info\n");
|
||||
// printf (" -q Don't show Frame Info/errorbars\n");
|
||||
//printf (" -s Datascope (disables other display options)\n");
|
||||
//printf (" -t Show symbol timing during sync\n");
|
||||
// printf (" -v <num> Frame information Verbosity\n");
|
||||
// printf (" -z <num> Frame rate for datascope\n");
|
||||
printf ("\n");
|
||||
printf ("Input/Output options:\n");
|
||||
printf (" -i <device> Audio input device (default is pulse audio)\n");
|
||||
printf (" - for piped stdin\n");
|
||||
printf (" -i <device> Audio input device (default is /dev/dsp)\n");
|
||||
printf (" pulse for pulse audio \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");
|
||||
@@ -858,9 +896,12 @@ 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 (" -s <rate> Sample Rate of wav input files (usually 48000 or 96000) Mono only!\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\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 (" -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");
|
||||
printf (" -w <file> Output synthesized speech to a .wav file, legacy auto modes only.\n");
|
||||
@@ -870,9 +911,12 @@ usage ()
|
||||
printf (" -a Enable Call Alert Beep (NCurses Terminal Only)\n");
|
||||
printf (" (Warning! Might be annoying.)\n");
|
||||
printf (" -L <file> Specify Filename for LRRP Data Output.\n");
|
||||
printf (" -Q <file> Specify Filename for DSP Structured File Output. (placed in DSP folder)\n");
|
||||
printf (" -c <file> Output symbol capture to .bin file\n");
|
||||
printf (" -n Throttle Symbol Capture Bin Input\n");
|
||||
printf (" (useful when reading files still being written to by OP25)");
|
||||
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");
|
||||
@@ -883,19 +927,13 @@ usage ()
|
||||
printf (" ppm <num> RTL-SDR PPM Error (default = 0)\n");
|
||||
printf (" bw <num> RTL-SDR VFO Bandwidth kHz (default = 12)(6, 8, 12, 24) \n");
|
||||
printf (" sq <num> RTL-SDR Squelch Level (0 - Open, 25 - Little, 50 - Higher)\n");
|
||||
// printf (" -V <num> RTL-SDR Sample Gain Multiplier (default = 1)\n");
|
||||
printf (" udp <num> RTL-SDR UDP Remote Port (default = 6020)\n");
|
||||
printf (" Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf (" Example: dsd-fme-lite -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
|
||||
printf ("\n");
|
||||
// printf ("Scanner control options:\n");
|
||||
// printf (" -B <num> Serial port baud rate (default=115200)\n");
|
||||
// printf (" -C <device> Serial port for scanner control (default=/dev/ttyUSB0)\n");
|
||||
// printf (" -R <num> Resume scan after <num> TDULC frames or any PDU or TSDU\n");
|
||||
// printf ("\n");
|
||||
printf ("Decoder options:\n");
|
||||
printf (" -fa Legacy Auto Detection (old methods default)\n");
|
||||
printf (" -ft XDMA P25 and DMR BS/MS frame types (new default)\n");
|
||||
printf (" -fs DMR Stereo BS and MS Simplex only\n");
|
||||
printf (" -fs DMR Stereo BS and MS Simplex\n");
|
||||
printf (" -f1 Decode only P25 Phase 1\n");
|
||||
printf (" -fd Decode only D-STAR\n");
|
||||
printf (" -fr Decode only DMR Mono - Single Slot Voice\n");
|
||||
@@ -904,8 +942,7 @@ usage ()
|
||||
printf (" -fn Decode only NXDN96* (12.5 kHz)\n");
|
||||
printf (" -fp Decode only EDACS/ProVoice*\n");
|
||||
printf (" -fm Decode only dPMR*\n");
|
||||
printf (" -l Disable DMR and NXDN input filtering\n");
|
||||
// printf (" -pu Unmute Encrypted P25\n");
|
||||
printf (" -l Disable DMR, dPMR, and NXDN input filtering\n");
|
||||
printf (" -u <num> Unvoiced speech quality (default=3)\n");
|
||||
printf (" -xx Expect non-inverted X2-TDMA signal\n");
|
||||
printf (" -xr Expect inverted DMR signal\n");
|
||||
@@ -932,10 +969,9 @@ usage ()
|
||||
printf (" -m2 Use P25p2 6000 sps CQPSK modulation optimizations\n");
|
||||
//printf (" (4 Level, not 8 Level LSM) (this is honestly unknown since I can't verify what local systems are using)\n");
|
||||
printf (" -F Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n");
|
||||
printf (" Use this feature to allow MAC_SIGNAL even if bad CRC errors.\n");
|
||||
printf (" -F Relax DMR CACH/Burst FEC Pass/Fail - Passive Frame Sync\n");
|
||||
printf (" Use if skipping occurs, but may cause wonky audio due to loss of good sync\n");
|
||||
|
||||
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
|
||||
printf (" -F Relax DMR CACH/Burst FEC or RAS/CRC CSBK Pass/Fail\n");
|
||||
printf (" Enabling on some systems could lead to bad voice/data decoding if bad or marginal signal\n");
|
||||
printf ("\n");
|
||||
printf (" -K <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
|
||||
printf ("\n");
|
||||
@@ -945,27 +981,31 @@ usage ()
|
||||
printf (" -H '736B9A9C5645288B 243AD5CB8701EF8A' \n");
|
||||
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
|
||||
printf ("\n");
|
||||
printf (" -R <dec> Manually Enter NXDN 4800/9600 EHR Scrambler Key Value (Decimal Value)\n");
|
||||
printf (" -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n");
|
||||
printf (" -k <file> Import NXDN Scrambler Key List from csv file.\n");
|
||||
printf (" \n");
|
||||
printf (" -4 Force Privacy Key over FID and SVC bits \n");
|
||||
printf ("\n");
|
||||
printf (" New and Experimental Functions and Features---------------------------------------------------\n");
|
||||
printf (" Trunking Options:\n");
|
||||
printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n");
|
||||
printf (" (See channel_map.csv for example)\n");
|
||||
printf (" -G <file> Import Group List Allow/Block and Label from csv file.\n");
|
||||
printf (" (See group.csv for example)\n");
|
||||
printf (" -T Enable Trunking Features (NXDN/P25/EDACS/DMR) with RIGCTL/TCP or RTL Input\n");
|
||||
printf (" -W Use Imported Group List as a Trunking Allow/White List -- Only Tune with Mode A\n");
|
||||
printf (" -p Don't Tune to Private Calls (DMR TIII and P25)\n");
|
||||
printf (" -p Disable Tune to Private Calls (DMR TIII and P25)\n");
|
||||
printf (" -E Disable Tune to Group Calls (DMR TIII, Con+, Cap+ and P25)\n");
|
||||
printf (" (NOTE: NXDN and EDACS, simply disable trunking if desired) \n");
|
||||
printf (" -e Enable Tune to Data Calls (DMR TIII)\n");
|
||||
printf (" (NOTE: DMR Con+ and P25 Data Channels Not Enabled (no handling) \n");
|
||||
printf (" (NOTE: P25 Data Channels Not Enabled (no handling) \n");
|
||||
printf (" -U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)\n");
|
||||
printf (" -B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)\n");
|
||||
printf (" P25 - 7000; NXDN48 - 4000; DMR - 7000; EDACS/PV - 12500; May vary based on system stregnth, etc.\n");
|
||||
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 4000; DMR - 7000; EDACS/PV - 12500;\n");
|
||||
printf (" May vary based on system stregnth, etc.\n");
|
||||
printf (" -t <secs> Set Trunking VC/sync loss hangtime in seconds. (default = 1 second)\n");
|
||||
printf (" -q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice\n");
|
||||
printf (" -V Enable Audio Smoothing on Upsampled Audio (XDMA and DMR Stereo 24k/2 output) (Capital V)\n");
|
||||
printf (" (Audio Smoothing is now disabled on all upsampled output by default -- fix crackle/buzz bug)\n");
|
||||
printf ("\n");
|
||||
printf (" Trunking Example TCP: dsd-fme-lite -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-lite -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);
|
||||
}
|
||||
@@ -1024,6 +1064,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1093,10 +1134,10 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
closeSymbolOutFile (opts, state);
|
||||
}
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
|
||||
//close MBE out files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
fprintf (stderr,"\n");
|
||||
fprintf (stderr,"Total audio errors: %i\n", state->debug_audio_errors);
|
||||
@@ -1166,8 +1207,9 @@ main (int argc, char **argv)
|
||||
}
|
||||
//fprintf (stderr,"%s", KNRM); //change back to normal
|
||||
|
||||
fprintf (stderr, "Github Build Version: %s \n", GIT_TAG);
|
||||
fprintf (stderr,"MBElib version %s\n", versionstr);
|
||||
// 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);
|
||||
|
||||
initOpts (&opts);
|
||||
initState (&state);
|
||||
@@ -1177,7 +1219,7 @@ main (int argc, char **argv)
|
||||
exitflag = 0;
|
||||
// signal (SIGINT, sigfun);
|
||||
|
||||
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:Y:K:H:X:NQWrlZTF01:2:345:6:7:89:")) != -1)
|
||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:Y:K:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1)
|
||||
{
|
||||
opterr = 0;
|
||||
switch (c)
|
||||
@@ -1195,6 +1237,36 @@ main (int argc, char **argv)
|
||||
|
||||
//Disabled the Serial Port Dev and Baud Rate, etc, If somebody uses that function, sorry...
|
||||
|
||||
case 'k': //NXDN multi-key loader
|
||||
strncpy(opts.key_in_file, optarg, 1023);
|
||||
opts.key_in_file[1023] = '\0';
|
||||
csvKeyImport(&opts, &state);
|
||||
break;
|
||||
|
||||
case 'Q': //'DSP' Structured Output file for OKDMRlib
|
||||
sprintf (wav_file_directory, "./DSP");
|
||||
wav_file_directory[1023] = '\0';
|
||||
if (stat(wav_file_directory, &st) == -1)
|
||||
{
|
||||
fprintf (stderr, "-Q %s DSP file directory does not exist\n", wav_file_directory);
|
||||
fprintf (stderr, "Creating directory %s to save DSP Structured files\n", wav_file_directory);
|
||||
mkdir(wav_file_directory, 0700); //user read write execute, needs execute for some reason or segfault
|
||||
}
|
||||
//read in filename
|
||||
//sprintf (opts.wav_out_file, "./WAV/DSD-FME-X1.wav");
|
||||
strncpy(dsp_filename, optarg, 1023);
|
||||
sprintf(opts.dsp_out_file, "%s/%s", wav_file_directory, dsp_filename);
|
||||
fprintf (stderr, "Saving DSP Structured files to %s\n", opts.dsp_out_file);
|
||||
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':
|
||||
@@ -1207,6 +1279,12 @@ main (int argc, char **argv)
|
||||
fprintf (stderr, "Using Group List as Allow/White List. \n");
|
||||
break;
|
||||
|
||||
//Trunking - Tune Group Calls
|
||||
case 'E':
|
||||
opts.trunk_tune_group_calls = 0; //disable
|
||||
fprintf (stderr, "Disable Tuning to Group Calls. \n");
|
||||
break;
|
||||
|
||||
//Trunking - Tune Private Calls
|
||||
case 'p':
|
||||
opts.trunk_tune_private_calls = 0; //disable
|
||||
@@ -1442,7 +1520,7 @@ main (int argc, char **argv)
|
||||
wav_file_directory[1023] = '\0';
|
||||
if (stat(wav_file_directory, &st) == -1)
|
||||
{
|
||||
fprintf (stderr, "-T %s WAV file directory does not exist\n", wav_file_directory);
|
||||
fprintf (stderr, "-P %s WAV file directory does not exist\n", wav_file_directory);
|
||||
fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory);
|
||||
mkdir(wav_file_directory, 0700); //user read write execute, needs execute for some reason or segfault
|
||||
}
|
||||
@@ -1459,7 +1537,7 @@ main (int argc, char **argv)
|
||||
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 DMR CACH/Burst FEC Pass/Fail\n");
|
||||
fprintf (stderr, "Relax DMR CACH/Burst FEC or RAS/CRC CSBK Pass/Fail\n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
break;
|
||||
|
||||
@@ -1561,10 +1639,10 @@ main (int argc, char **argv)
|
||||
opts.frame_dpmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
opts.frame_ysf = 0;
|
||||
opts.pulse_digi_rate_out = 48000;
|
||||
opts.pulse_digi_rate_out = 48000; // /dev/dsp does need this set to 48000 to properly process the upsampling
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 1;
|
||||
opts.dmr_stereo = 1; //switching in 'stereo' for 'mono'
|
||||
opts.dmr_mono = 0;
|
||||
state.dmr_stereo = 0;
|
||||
opts.setmod_bw = 7000;
|
||||
sprintf (opts.output_name, "Legacy Auto");
|
||||
@@ -1764,11 +1842,11 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
opts.dmr_mono = 0;
|
||||
// opts.setmod_bw = 7000;
|
||||
opts.setmod_bw = 7000;
|
||||
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')
|
||||
@@ -1847,7 +1925,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 or XDMA is highly encouraged.\n");
|
||||
fprintf (stderr,"Decoding only DMR Mono. \nUsing DMR Stereo '-fs' or XDMA '-ft' is highly encouraged.\n");
|
||||
//dmr stereo below
|
||||
// opts.frame_dstar = 0;
|
||||
// opts.frame_x2tdma = 0;
|
||||
@@ -1931,7 +2009,7 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 1;
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 1;
|
||||
opts.setmod_bw = 12500;
|
||||
opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling only QPSK modulation optimizations.\n");
|
||||
}
|
||||
else if (optarg[0] == '2')
|
||||
@@ -1942,7 +2020,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 1;
|
||||
state.samplesPerSymbol = 8;
|
||||
state.symbolCenter = 3;
|
||||
opts.setmod_bw = 12500;
|
||||
opts.setmod_bw = 12000;
|
||||
fprintf (stderr,"Enabling 6000 sps P25p2 CQPSK.\n");
|
||||
}
|
||||
break;
|
||||
@@ -2056,12 +2134,14 @@ 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 = 0;
|
||||
opts.audio_in_type = 5;
|
||||
fprintf (stderr, "TCP Connection Failure - Using Pulse Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2143,61 +2223,137 @@ 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 Pulse Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
opts.audio_in_type = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//still need to work out why I can't use this
|
||||
//issues with samples received, may be using UDP DGRAMS incorrectly, incorrect procedure?
|
||||
//doesn't work correctly, so just going to reroute to /dev/dsp instead
|
||||
if((strncmp(opts.audio_in_dev, "udp", 3) == 0)) //udp socket input from SDR++, GQRX, and others
|
||||
{
|
||||
//also still needs err handling
|
||||
opts.udp_sockfd = UDPBind(opts.udp_hostname, opts.udp_portno);
|
||||
opts.audio_in_type = 6;
|
||||
fprintf (stderr, "UDP Input not working, falling back to OSS /dev/dsp Audio Input.\n");
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
opts.audio_in_type = 5;
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "/dev/dsp", 8) == 0))
|
||||
{
|
||||
sprintf (opts.audio_in_dev, "%s", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_in_type = 0;
|
||||
}
|
||||
int fmt;
|
||||
int speed = 48000;
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "/dev/audio", 10) == 0))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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, "/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;
|
||||
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", "pulse");
|
||||
fprintf (stderr, "OSS and PA Handling Disabled; Using Pulse Audio.\n");
|
||||
opts.audio_out_type = 0;
|
||||
sprintf (opts.audio_in_dev, "%s", "/dev/dsp");
|
||||
fprintf (stderr, "Switching to /dev/dsp.\n");
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if((strncmp(opts.audio_out_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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_in_dev, "pulse", 5) == 0))
|
||||
@@ -2223,14 +2379,15 @@ 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
|
||||
{
|
||||
opts.split = 1;
|
||||
@@ -2263,15 +2420,13 @@ 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);
|
||||
|
||||
221
src/dsd_mbe.c
221
src/dsd_mbe.c
@@ -17,8 +17,42 @@
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
||||
int Pr[256] = {
|
||||
0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903,
|
||||
0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306,
|
||||
0x2618, 0x3918, 0xC518, 0xDA18, 0x031B, 0x1C1B, 0xE01B, 0xFF1B,
|
||||
0x6C1D, 0x731D, 0x8F1D, 0x901D, 0x491E, 0x561E, 0xAA1E, 0xB51E, //31
|
||||
0x4B28, 0x5428, 0xA828, 0xB728, 0x6E2B, 0x712B, 0x8D2B, 0x922B,
|
||||
0x012D, 0x1E2D, 0xE22D, 0xFD2D, 0x242E, 0x3B2E, 0xC72E, 0xD82E,
|
||||
0x6D30, 0x7230, 0x8E30, 0x9130, 0x4833, 0x5733, 0xAB33, 0xB433,
|
||||
0x2735, 0x3835, 0xC435, 0xDB35, 0x0236, 0x1D36, 0xE136, 0xFE36, //63
|
||||
0x2B49, 0x3449, 0xC849, 0xD749, 0x0E4A, 0x114A, 0xED4A, 0xF24A,
|
||||
0x614C, 0xAE4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F,
|
||||
0x0D51, 0x1251, 0xEE51, 0xF151, 0x2852, 0x3752, 0xCB52, 0xD452,
|
||||
0x4754, 0x5854, 0xA454, 0xBB54, 0x6257, 0x7D57, 0x8157, 0x9E57, //95
|
||||
0x6061, 0x7F61, 0x8361, 0x9C61, 0x4562, 0x5A62, 0xA662, 0xB962,
|
||||
0x2A64, 0x3564, 0xC964, 0xD664, 0x0F67, 0x1067, 0xEC67, 0xF367,
|
||||
0x4679, 0x5979, 0xA579, 0xBA79, 0x637A, 0x7C7A, 0x807A, 0x9F7A,
|
||||
0x0C7C, 0x137C, 0xEF7C, 0xF07C, 0x297F, 0x367F, 0xCA7F, 0xD57F, //127
|
||||
0x4D89, 0x5289, 0xAE89, 0xB189, 0x688A, 0x778A, 0x8B8A, 0x948A,
|
||||
0x078C, 0x188C, 0xE48C, 0xFB8C, 0x228F, 0x3D8F, 0xC18F, 0xDE8F,
|
||||
0x6B91, 0x7491, 0x8891, 0x9791, 0x4E92, 0x5192, 0xAD92, 0xB292,
|
||||
0x2194, 0x3E94, 0xC294, 0xDD94, 0x0497, 0x1B97, 0xE797, 0xF897, //159
|
||||
0x06A1, 0x19A1, 0xE5A1, 0xFAA1, 0x23A2, 0x3CA2, 0xC0A2, 0xDFA2,
|
||||
0x4CA4, 0x53A4, 0xAFA4, 0xB0A4, 0x69A7, 0x76A7, 0x8AA7, 0x95A7,
|
||||
0x20B9, 0x3FB9, 0xC3B9, 0xDCB9, 0x05BA, 0x1ABA, 0xE6BA, 0xF9BA,
|
||||
0x6ABC, 0x75BC, 0x89BC, 0x96BC, 0x4FBF, 0x50BF, 0xACBF, 0xB3BF, //191
|
||||
0x66C0, 0x79C0, 0x85C0, 0x9AC0, 0x43C3, 0x5CC3, 0xA0C3, 0xBFC3,
|
||||
0x2CC5, 0x33C5, 0xCFC5, 0xD0C5, 0x09C6, 0x16C6, 0xEAC6, 0xF5C6,
|
||||
0x84D0, 0x85DF, 0x8AD3, 0x8BDC, 0xB6D5, 0xB7DA, 0xB8D6, 0xB9D9,
|
||||
0xD0DA, 0xD1D5, 0xDED9, 0xDFD6, 0xE2DF, 0xE3D0, 0xECDC, 0xEDD3, //223
|
||||
0x2DE8, 0x32E8, 0xCEE8, 0xD1E8, 0x08EB, 0x17EB, 0xEBEB, 0xF4EB,
|
||||
0x67ED, 0x78ED, 0x84ED, 0x9BED, 0x42EE, 0x5DEE, 0xA1EE, 0xBEEE,
|
||||
0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3,
|
||||
0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255
|
||||
};
|
||||
|
||||
void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
||||
{
|
||||
|
||||
int i;
|
||||
@@ -26,99 +60,79 @@ playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
||||
char ambe_d[49];
|
||||
|
||||
for (i = state->optind; i < argc; i++)
|
||||
{
|
||||
sprintf (opts->mbe_in_file, "%s", argv[i]);
|
||||
openMbeInFile (opts, state);
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
fprintf (stderr, "playing %s\n", opts->mbe_in_file);
|
||||
while (feof (opts->mbe_in_f) == 0)
|
||||
{
|
||||
sprintf (opts->mbe_in_file, "%s", argv[i]);
|
||||
openMbeInFile (opts, state);
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
fprintf (stderr, "playing %s\n", opts->mbe_in_file);
|
||||
while (feof (opts->mbe_in_f) == 0)
|
||||
if (state->mbe_file_type == 0)
|
||||
{
|
||||
readImbe4400Data (opts, state, imbe_d);
|
||||
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
if (state->mbe_file_type == 0)
|
||||
{
|
||||
readImbe4400Data (opts, state, imbe_d);
|
||||
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
processAudio(opts, state);
|
||||
}
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
|
||||
playSynthesizedVoice (opts, state);
|
||||
|
||||
}
|
||||
}
|
||||
else if (state->mbe_file_type == 1)
|
||||
{
|
||||
readAmbe2450Data (opts, state, ambe_d);
|
||||
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
processAudio(opts, state);
|
||||
}
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
}
|
||||
}
|
||||
if (exitflag == 1)
|
||||
{
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
processAudio(opts, state);
|
||||
}
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
|
||||
playSynthesizedVoice (opts, state);
|
||||
|
||||
}
|
||||
}
|
||||
else if (state->mbe_file_type > 0) //ambe files
|
||||
{
|
||||
readAmbe2450Data (opts, state, ambe_d);
|
||||
int j, x;
|
||||
unsigned long long int k;
|
||||
if (state->K != 0) //apply Pr key
|
||||
{
|
||||
k = Pr[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
for (short int j = 0; j < 48; j++) //49
|
||||
{
|
||||
x = ( ((k << j) & 0x800000000000) >> 47 );
|
||||
ambe_d[j] ^= x;
|
||||
}
|
||||
}
|
||||
|
||||
//ambe+2
|
||||
if (state->mbe_file_type == 1) mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
//dstar ambe
|
||||
if (state->mbe_file_type == 2) mbe_processAmbe2400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
processAudio(opts, state);
|
||||
}
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
}
|
||||
}
|
||||
if (exitflag == 1)
|
||||
{
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
|
||||
{
|
||||
|
||||
//
|
||||
int Pr[256] = {
|
||||
0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903,
|
||||
0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306,
|
||||
0x2618, 0x3918, 0xC518, 0xDA18, 0x031B, 0x1C1B, 0xE01B, 0xFF1B,
|
||||
0x6C1D, 0x731D, 0x8F1D, 0x901D, 0x491E, 0x561E, 0xAA1E, 0xB51E, //31
|
||||
0x4B28, 0x5428, 0xA828, 0xB728, 0x6E2B, 0x712B, 0x8D2B, 0x922B,
|
||||
0x012D, 0x1E2D, 0xE22D, 0xFD2D, 0x242E, 0x3B2E, 0xC72E, 0xD82E,
|
||||
0x6D30, 0x7230, 0x8E30, 0x9130, 0x4833, 0x5733, 0xAB33, 0xB433,
|
||||
0x2735, 0x3835, 0xC435, 0xDB35, 0x0236, 0x1D36, 0xE136, 0xFE36, //63
|
||||
0x2B49, 0x3449, 0xC849, 0xD749, 0x0E4A, 0x114A, 0xED4A, 0xF24A,
|
||||
0x614C, 0xAE4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F,
|
||||
0x0D51, 0x1251, 0xEE51, 0xF151, 0x2852, 0x3752, 0xCB52, 0xD452,
|
||||
0x4754, 0x5854, 0xA454, 0xBB54, 0x6257, 0x7D57, 0x8157, 0x9E57, //95
|
||||
0x6061, 0x7F61, 0x8361, 0x9C61, 0x4562, 0x5A62, 0xA662, 0xB962,
|
||||
0x2A64, 0x3564, 0xC964, 0xD664, 0x0F67, 0x1067, 0xEC67, 0xF367,
|
||||
0x4679, 0x5979, 0xA579, 0xBA79, 0x637A, 0x7C7A, 0x807A, 0x9F7A,
|
||||
0x0C7C, 0x137C, 0xEF7C, 0xF07C, 0x297F, 0x367F, 0xCA7F, 0xD57F, //127
|
||||
0x4D89, 0x5289, 0xAE89, 0xB189, 0x688A, 0x778A, 0x8B8A, 0x948A,
|
||||
0x078C, 0x188C, 0xE48C, 0xFB8C, 0x228F, 0x3D8F, 0xC18F, 0xDE8F,
|
||||
0x6B91, 0x7491, 0x8891, 0x9791, 0x4E92, 0x5192, 0xAD92, 0xB292,
|
||||
0x2194, 0x3E94, 0xC294, 0xDD94, 0x0497, 0x1B97, 0xE797, 0xF897, //159
|
||||
0x06A1, 0x19A1, 0xE5A1, 0xFAA1, 0x23A2, 0x3CA2, 0xC0A2, 0xDFA2,
|
||||
0x4CA4, 0x53A4, 0xAFA4, 0xB0A4, 0x69A7, 0x76A7, 0x8AA7, 0x95A7,
|
||||
0x20B9, 0x3FB9, 0xC3B9, 0xDCB9, 0x05BA, 0x1ABA, 0xE6BA, 0xF9BA,
|
||||
0x6ABC, 0x75BC, 0x89BC, 0x96BC, 0x4FBF, 0x50BF, 0xACBF, 0xB3BF, //191
|
||||
0x66C0, 0x79C0, 0x85C0, 0x9AC0, 0x43C3, 0x5CC3, 0xA0C3, 0xBFC3,
|
||||
0x2CC5, 0x33C5, 0xCFC5, 0xD0C5, 0x09C6, 0x16C6, 0xEAC6, 0xF5C6,
|
||||
0x84D0, 0x85DF, 0x8AD3, 0x8BDC, 0xB6D5, 0xB7DA, 0xB8D6, 0xB9D9,
|
||||
0xD0DA, 0xD1D5, 0xDED9, 0xDFD6, 0xE2DF, 0xE3D0, 0xECDC, 0xEDD3, //223
|
||||
0x2DE8, 0x32E8, 0xCEE8, 0xD1E8, 0x08EB, 0x17EB, 0xEBEB, 0xF4EB,
|
||||
0x67ED, 0x78ED, 0x84ED, 0x9BED, 0x42EE, 0x5DEE, 0xA1EE, 0xBEEE,
|
||||
0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3,
|
||||
0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255
|
||||
};
|
||||
//
|
||||
|
||||
int i;
|
||||
char imbe_d[88];
|
||||
char ambe_d[49];
|
||||
@@ -126,6 +140,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
unsigned long long int k;
|
||||
int x;
|
||||
|
||||
int preempt = 0; //TDMA dual voice slot preemption(when using OSS output)
|
||||
|
||||
|
||||
for (i = 0; i < 88; i++)
|
||||
{
|
||||
@@ -362,6 +378,13 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
PrintAMBEData (opts, state, ambe_d);
|
||||
}
|
||||
|
||||
//restore MBE file save, slot 1 -- consider saving even if enc
|
||||
if (opts->mbe_out_f != NULL && (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) )
|
||||
{
|
||||
saveAmbe2450Data (opts, state, ambe_d);
|
||||
}
|
||||
|
||||
}
|
||||
//stereo slots and slot 1 (right slot)
|
||||
if (state->currentslot == 1) //&& opts->dmr_stereo == 1
|
||||
@@ -456,6 +479,12 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
PrintAMBEData (opts, state, ambe_d);
|
||||
}
|
||||
|
||||
//restore MBE file save, slot 2 -- consider saving even if enc
|
||||
if (opts->mbe_out_fR != NULL && (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) )
|
||||
{
|
||||
saveAmbe2450DataR (opts, state, ambe_d);
|
||||
}
|
||||
}
|
||||
|
||||
//X2-TDMA? Not sure what still makes it this far to run under Framef
|
||||
@@ -522,6 +551,14 @@ 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;
|
||||
@@ -578,6 +615,14 @@ 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;
|
||||
@@ -632,6 +677,12 @@ 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
|
||||
|
||||
@@ -125,7 +125,7 @@ char * DMRBusrtTypes[32] = {
|
||||
"R-S ERR ",
|
||||
"CRC ERR ",
|
||||
"NULL ",
|
||||
"Voice ",
|
||||
"Voice ",
|
||||
" ",
|
||||
"INIT ",
|
||||
"INIT ",
|
||||
@@ -150,9 +150,10 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
|
||||
FILE *beep;
|
||||
char wav_name[1024] = {0};
|
||||
|
||||
if (opts->pulse_digi_rate_out == 8000) strncpy(wav_name, "/usr/share/tone8.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 48000) strncpy(wav_name, "/usr/share/tone48.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 24000) strncpy(wav_name, "/usr/share/tone24.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 8000) strncpy(wav_name, "tone8.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 48000) strncpy(wav_name, "tone48.wav", 1023);
|
||||
if (opts->pulse_digi_rate_out == 24000) strncpy(wav_name, "tone24.wav", 1023);
|
||||
if (opts->audio_out_type == 5) strncpy(wav_name, "tone48.wav", 1023);
|
||||
wav_name[1023] = '\0';
|
||||
struct stat stat_buf;
|
||||
if (stat(wav_name, &stat_buf) == 0)
|
||||
@@ -174,17 +175,20 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
|
||||
//only beep on R if dmr_stereo is active and slot 2, else beep on L
|
||||
if (type == 0 && opts->dmr_stereo == 1 && opts->audio_out == 1)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 0) pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 5) write (opts->audio_out_fd, buf, sizeof(buf));
|
||||
//fprintf (stderr, "BEEP 0 24\n");
|
||||
}
|
||||
if (type == 1 && opts->dmr_stereo == 1 && opts->audio_out == 1)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_outR, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 0) pa_simple_write(opts->pulse_digi_dev_outR, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 5) write (opts->audio_out_fd, buf, sizeof(buf));
|
||||
//fprintf (stderr, "BEEP 1 24\n");
|
||||
}
|
||||
if (opts->dmr_stereo == 0 && opts->audio_out == 1)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 0) pa_simple_write(opts->pulse_digi_dev_out, buf, sizeof(buf), NULL);
|
||||
if (opts->audio_out_type == 5) write (opts->audio_out_fd, buf, sizeof(buf));
|
||||
//fprintf (stderr, "BEEP 0 8\n");
|
||||
}
|
||||
|
||||
@@ -199,7 +203,7 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
|
||||
}
|
||||
|
||||
char * getDateN(void) {
|
||||
char datename[99]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
||||
char datename[80]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
@@ -410,7 +414,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->audio_in_type == 5) //close UDP input SF file so we don't buffer audio while not decoding
|
||||
{
|
||||
sf_close(opts->udp_file_in); //disable for testing
|
||||
// sf_close(opts->udp_file_in); //disable for testing
|
||||
}
|
||||
|
||||
state->payload_keyid = 0;
|
||||
@@ -836,8 +840,13 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
if(opts->tcp_file_in == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||||
sprintf (opts->audio_in_dev, "%s", "pulse");
|
||||
opts->audio_in_type = 0;
|
||||
if (opts->audio_out_type == 0)
|
||||
{
|
||||
sprintf (opts->audio_in_dev, "%s", "pulse");
|
||||
opts->audio_in_type = 0;
|
||||
}
|
||||
else opts->audio_in_type = 5;
|
||||
|
||||
}
|
||||
|
||||
state->audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing
|
||||
@@ -967,7 +976,8 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
}
|
||||
opts->audio_in_type = 0; //set after closing to prevent above crash condition
|
||||
if (opts->audio_out_type == 0) opts->audio_in_type = 0; //set after closing to prevent above crash condition
|
||||
else (opts->audio_in_type = 5);
|
||||
|
||||
choicec = 18; //exit
|
||||
}
|
||||
@@ -1041,7 +1051,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
mvwprintw(entry_win, 3, 2, " ");
|
||||
mvwprintw(entry_win, 4, 2, "1 - Basic Privacy ");
|
||||
mvwprintw(entry_win, 5, 2, "2 - **tera Privacy ");
|
||||
mvwprintw(entry_win, 6, 2, "3 - NXDN Scrambler ");
|
||||
mvwprintw(entry_win, 6, 2, "3 - NXDN/dPMR Scrambler ");
|
||||
mvwprintw(entry_win, 7, 2, "4 - Force Key Priority ");
|
||||
mvwprintw(entry_win, 8, 3, " ");
|
||||
echo();
|
||||
@@ -1121,7 +1131,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
state->R = 0;
|
||||
entry_win = newwin(6, WIDTH+6, starty+10, startx+10);
|
||||
box (entry_win, 0, 0);
|
||||
mvwprintw(entry_win, 2, 2, "NXDN Scrambler Key Value (DEC):");
|
||||
mvwprintw(entry_win, 2, 2, "NXDN/dPMR Scrambler Key Value (DEC):");
|
||||
mvwprintw(entry_win, 3, 3, " ");
|
||||
echo();
|
||||
refresh();
|
||||
@@ -1160,7 +1170,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
opts->dmr_mono = 0;
|
||||
opts->dmr_stereo = 0; //this value is the end user option
|
||||
state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling
|
||||
opts->pulse_digi_rate_out = 48000;
|
||||
opts->pulse_digi_rate_out = 8000;
|
||||
opts->pulse_digi_out_channels = 1;
|
||||
opts->frame_dstar = 1;
|
||||
opts->frame_x2tdma = 1;
|
||||
@@ -1663,7 +1673,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->audio_in_type == 5) //re-open UDP input 'file'
|
||||
{
|
||||
opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||
// opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||
}
|
||||
|
||||
//update sync time on cc sync so we don't immediately go CC hunting when exiting the menu
|
||||
@@ -1680,35 +1690,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN -
|
||||
{
|
||||
timeout(0);
|
||||
c = getch();
|
||||
timeout(0); //
|
||||
c = getch(); //
|
||||
}
|
||||
|
||||
//testing sending UDP commands to the socket inside of rtl_sdr_fm.cpp
|
||||
//this works, but we will want to make an init func open one time, and have sendto here
|
||||
//use rtl_udp_tune
|
||||
#ifdef USE_RTLSDR
|
||||
if (temp_freq == opts->rtlsdr_center_freq)
|
||||
{
|
||||
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
memset((char * ) & address, 0, sizeof(address));
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = inet_addr(SRV_IP); //address of host
|
||||
address.sin_port = htons(udp_port);
|
||||
sendto(handle, data, UDP_BUFLEN, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
||||
|
||||
rtl_udp_tune (opts, state, temp_freq);
|
||||
temp_freq = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//Variable reset/set section
|
||||
|
||||
//carrier reset
|
||||
// if (state->carrier == 0) //reset these to 0 when no carrier
|
||||
// {
|
||||
// sprintf(state->dmr_branding, "%s", "");
|
||||
// }
|
||||
|
||||
//set lls sync types
|
||||
if (state->synctype >= 0 && state->synctype < 39)
|
||||
{
|
||||
@@ -1904,7 +1900,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||||
}
|
||||
|
||||
if (opts->call_alert == 1)
|
||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||||
{
|
||||
//fprintf (stderr, "BEEP 0 MS LEFT\n");
|
||||
beeper (opts, state, 0);
|
||||
@@ -1947,7 +1943,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||||
}
|
||||
|
||||
if (opts->call_alert == 1)
|
||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||||
{
|
||||
//fprintf (stderr, "BEEP 0 BS LEFT\n");
|
||||
beeper (opts, state, 0);
|
||||
@@ -1989,7 +1985,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
||||
}
|
||||
|
||||
if (opts->call_alert == 1)
|
||||
if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
||||
{
|
||||
//fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
||||
beeper (opts, state, 1);
|
||||
@@ -2044,11 +2040,19 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
// {
|
||||
// beeper (opts, state, 0);
|
||||
// state->dmr_end_alert[0] = 1; //don't play again until new voice frames
|
||||
// state->lasttg = 0;
|
||||
// state->lastsrc = 0;
|
||||
// rd = 0;
|
||||
// tg = 0;
|
||||
// }
|
||||
// if (state->dmrburstR == 2 && state->dmr_end_alert[1] == 0) //if TLC and flag not tripped
|
||||
// {
|
||||
// beeper (opts, state, 1);
|
||||
// state->dmr_end_alert[1] = 1; //don't play again until new voice frames
|
||||
// state->lasttgR = 0;
|
||||
// state->lastsrcR = 0;
|
||||
// rdR = 0;
|
||||
// tgR = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -2057,7 +2061,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->ncurses_compact == 1)
|
||||
{
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
printw ("| Digital Speech Decoder: Florida Man Edition %s \n", GIT_TAG);
|
||||
printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-28-ga02f992 RC3");
|
||||
}
|
||||
if (opts->ncurses_compact == 0)
|
||||
{
|
||||
@@ -2067,8 +2071,9 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw("%s", FM_bannerN[i]);
|
||||
if (i == 1) printw (" ESC to Menu");
|
||||
if (i == 2) printw (" 'q' to Quit ");
|
||||
if (i == 5) printw (" MBElib %s", versionstr);
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
if (i == 4) printw (" MBElib %s", versionstr);
|
||||
if (i == 5) printw (" %s ", "Win32 RC3"); //printw (" %s \n", GIT_TAG);
|
||||
if (i == 6) printw (" %s \n", "v2.0.0-28-ga02f992"); //printw (" %s \n", GIT_TAG);
|
||||
else printw ("\n");
|
||||
}
|
||||
attroff(COLOR_PAIR(6)); //6
|
||||
@@ -2080,6 +2085,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
printw ("| Pulse Audio Input: [%2i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels);
|
||||
}
|
||||
if (opts->audio_in_type == 5)
|
||||
{
|
||||
printw ("| OSS Audio Input: [%2i] kHz [1] Channel\n", SAMPLE_RATE_IN);
|
||||
}
|
||||
if (opts->audio_in_type == 4)
|
||||
{
|
||||
printw ("| Direct Symbol Bin Input: %s \n", opts->audio_in_dev);
|
||||
@@ -2114,6 +2123,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
||||
printw (" \n");
|
||||
}
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
printw ("| OSS Audio Output: [%2i] kHz [1] Channel", SAMPLE_RATE_IN);
|
||||
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
||||
printw (" \n");
|
||||
}
|
||||
if (opts->monitor_input_audio == 1)
|
||||
{
|
||||
printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected\n");
|
||||
@@ -2145,11 +2160,18 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (opts->p25_trunk == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3) )
|
||||
{
|
||||
printw ("| Trunk Tracking Active (P25/EDACS/NXDN/DMR)");
|
||||
if (opts->trunk_use_allow_list == 1)
|
||||
{
|
||||
printw (" - White List Mode\n");
|
||||
}
|
||||
printw ("| Trunk Tracking Active -");
|
||||
if (opts->trunk_tune_group_calls == 0) attron(COLOR_PAIR(2));
|
||||
printw (" Group(g)");
|
||||
attron(COLOR_PAIR(4));
|
||||
if (opts->trunk_tune_private_calls == 0) attron(COLOR_PAIR(2));
|
||||
printw (" Private(u)");
|
||||
attron(COLOR_PAIR(4));
|
||||
if (opts->trunk_tune_data_calls == 0) attron(COLOR_PAIR(2));
|
||||
printw (" Data(d)");
|
||||
attron(COLOR_PAIR(4));
|
||||
printw (" Calls");
|
||||
if (opts->trunk_use_allow_list == 1) printw (" - White List Mode\n");
|
||||
else printw (" - Black List Mode\n");
|
||||
}
|
||||
if (opts->reverse_mute == 1)
|
||||
@@ -2326,19 +2348,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (lls > 1 && lls < 30)
|
||||
{
|
||||
printw ("DMR BS - DCC: [%02i] ", dcc);
|
||||
printw ("%s %s", state->dmr_branding, state->dmr_branding_sub);
|
||||
// printw ("%s %s", state->dmr_branding, state->dmr_branding_sub);
|
||||
printw ("%s ", state->dmr_branding);
|
||||
printw ("%s", state->dmr_branding_sub);
|
||||
printw ("%s", state->dmr_site_parms); //site id, net id, etc
|
||||
if (state->dmr_rest_channel > 0)
|
||||
{
|
||||
printw ("Rest Channel: [%02d] ", state->dmr_rest_channel);
|
||||
if (state->trunk_chan_map[state->dmr_rest_channel] != 0)
|
||||
{
|
||||
printw ("%.06lf Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000);
|
||||
printw ("Freq: [%.06lf] Mhz", (double)state->trunk_chan_map[state->dmr_rest_channel]/1000000);
|
||||
}
|
||||
}
|
||||
else if (state->p25_cc_freq != 0)
|
||||
{
|
||||
printw ("%.06lf MHz", (double)state->p25_cc_freq/1000000);
|
||||
printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2348,7 +2372,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else if (lls == 0 || lls == 1) //P1
|
||||
{
|
||||
printw ("P25 P1 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
|
||||
// printw ("P25 P1 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
|
||||
printw ("P25 P1 - [%05llX][%03llX][%03llX] RFSS: [%llX] SITE: [%llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
|
||||
if (state->p25_cc_freq != 0)
|
||||
{
|
||||
printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000);
|
||||
@@ -2356,7 +2381,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else if (lls == 35 || lls == 36) //P2
|
||||
{
|
||||
printw ("P25 P2 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
|
||||
// printw ("P25 P2 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
|
||||
printw ("P25 P2 - [%05llX][%03llX][%03llX] RFSS: [%llX] SITE: [%llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
|
||||
if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0)
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
@@ -2397,6 +2423,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//This is the new one
|
||||
printw ("%s | ", state->call_string[0]);
|
||||
printw ("%s ", DMRBusrtTypes[state->dmrburstL]);
|
||||
if (opts->slot_preference == 1 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstR == 16 && state->dmrburstL == 16) printw ("*M*");
|
||||
printw ("\n");
|
||||
|
||||
printw ("| V XTRA | "); //10 spaces
|
||||
@@ -2592,6 +2619,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//THIS IS THE NEW ONE
|
||||
printw ("%s | ", state->call_string[1]);
|
||||
printw ("%s ", DMRBusrtTypes[state->dmrburstR]);
|
||||
if (opts->slot_preference == 0 && opts->audio_out_type == 5 && opts->audio_out == 1 && state->dmrburstR == 16 && state->dmrburstL == 16) printw ("*M*");
|
||||
printw ("\n");
|
||||
|
||||
printw ("| V XTRA | "); //10 spaces
|
||||
@@ -2770,7 +2798,23 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27)
|
||||
{
|
||||
printw ("| DCC: [%i] ", state->dpmr_color_code);
|
||||
printw ("TID: [%s] RID: [%s] \n", state->dpmr_target_id, state->dpmr_caller_id);
|
||||
printw ("TGT: [%s] SRC: [%s] ", state->dpmr_target_id, state->dpmr_caller_id);
|
||||
printw ("\n| ");
|
||||
if (state->dPMRVoiceFS2Frame.Version[0] == 3)
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw ("Scrambler ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
if (state->R != 0)
|
||||
{
|
||||
attron(COLOR_PAIR(1));
|
||||
printw ("KEY VALUE: [%05lld] ", state->R );
|
||||
//printw ("SEED: [%04llX]", state->payload_miN);
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
}
|
||||
printw ("\n");
|
||||
}
|
||||
|
||||
//EDACS and ProVoice
|
||||
@@ -2878,8 +2922,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("--Call History----------------------------------------------------------------\n");
|
||||
for (short int j = 0; j < 10; j++)
|
||||
{
|
||||
//only print if a valid time was assigned to the matrix, and not EDACS/PV
|
||||
if ( ((time(NULL) - call_matrix[9-j][5]) < 999999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 )
|
||||
//only print if a valid time was assigned to the matrix, and not EDACS/PV, and source is not zero
|
||||
if ( ((time(NULL) - call_matrix[9-j][5]) < 999999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 && call_matrix[9-j][2] != 0) //
|
||||
{
|
||||
printw ("| %s ", SyncTypes[call_matrix[9-j][0]]);
|
||||
if (lls == 28 || lls == 29)
|
||||
@@ -3080,21 +3124,24 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
if (c == 32) //'space bar' replay last bin file (rework to do wav files too?)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||||
{
|
||||
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||||
goto SKIPR;
|
||||
}
|
||||
if (S_ISREG(stat_buf.st_mode))
|
||||
{
|
||||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||||
opts->audio_in_type = 4; //symbol capture bin files
|
||||
}
|
||||
SKIPR: ; //do nothing
|
||||
}
|
||||
//
|
||||
// if (c == 32) //'space bar' replay last bin file (rework to do wav files too?)
|
||||
// {
|
||||
// struct stat stat_buf;
|
||||
// if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||||
// {
|
||||
// fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||||
// goto SKIPR;
|
||||
// }
|
||||
// if (S_ISREG(stat_buf.st_mode))
|
||||
// {
|
||||
// opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||||
// opts->audio_in_type = 4; //symbol capture bin files
|
||||
// }
|
||||
// SKIPR: ; //do nothing
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
if (c == 80) //'P' key - start per call wav files
|
||||
{
|
||||
@@ -3127,28 +3174,34 @@ if (c == 112) //'p' key - stop all per call wav files
|
||||
opts->dmr_stereo_wav = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// if (c == 115) //'s' key, stop playing wav or symbol in files
|
||||
// {
|
||||
// if (opts->symbolfile != NULL)
|
||||
// {
|
||||
// if (opts->audio_in_type == 4)
|
||||
// {
|
||||
// fclose(opts->symbolfile);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (c == 115) //'s' key, stop playing wav or symbol in files
|
||||
{
|
||||
if (opts->symbolfile != NULL)
|
||||
{
|
||||
if (opts->audio_in_type == 4)
|
||||
{
|
||||
fclose(opts->symbolfile);
|
||||
}
|
||||
}
|
||||
// if (opts->audio_in_type == 2) //wav input file
|
||||
// {
|
||||
// sf_close(opts->audio_in_file);
|
||||
// }
|
||||
|
||||
if (opts->audio_in_type == 2) //wav input file
|
||||
{
|
||||
sf_close(opts->audio_in_file);
|
||||
}
|
||||
// if (opts->audio_out_type == 0)
|
||||
// {
|
||||
// opts->audio_in_type = 0;
|
||||
// openPulseInput(opts);
|
||||
// }
|
||||
// else opts->audio_in_type = 5;//cleanupAndExit(opts, state);
|
||||
|
||||
// }
|
||||
//
|
||||
|
||||
opts->audio_in_type = 0;
|
||||
openPulseInput(opts);
|
||||
}
|
||||
|
||||
//Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet
|
||||
//WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!!
|
||||
// //Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet
|
||||
// //WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!!
|
||||
if (opts->frame_provoice != 1 && c == 49) //'1' key, lockout slot 1 or conventional tg from tuning/playback during session
|
||||
{
|
||||
state->group_array[state->group_tally].groupNumber = state->lasttg;
|
||||
@@ -3193,6 +3246,56 @@ if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mo
|
||||
else opts->trunk_use_allow_list = 1;
|
||||
}
|
||||
|
||||
if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls
|
||||
{
|
||||
if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0;
|
||||
else opts->trunk_tune_private_calls = 1;
|
||||
}
|
||||
|
||||
if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls
|
||||
{
|
||||
if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0;
|
||||
else opts->trunk_tune_data_calls = 1;
|
||||
}
|
||||
|
||||
if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls
|
||||
{
|
||||
if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0;
|
||||
else opts->trunk_tune_group_calls = 1;
|
||||
}
|
||||
|
||||
if (c == 70) //'F' key - toggle agressive sync/crc failure/ras
|
||||
{
|
||||
if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1;
|
||||
else opts->aggressive_framesync = 0;
|
||||
}
|
||||
|
||||
if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc.
|
||||
{
|
||||
//dmr trunking/ncurses stuff
|
||||
state->dmr_rest_channel = -1; //init on -1
|
||||
state->dmr_mfid = -1; //
|
||||
|
||||
//dmr mfid branding and site parms
|
||||
sprintf(state->dmr_branding_sub, "%s", "");
|
||||
sprintf(state->dmr_branding, "%s", "");
|
||||
sprintf (state->dmr_site_parms, "%s", "");
|
||||
|
||||
//DMR Location Area - DMRLA B***S***
|
||||
opts->dmr_dmrla_is_set = 0;
|
||||
opts->dmr_dmrla_n = 0;
|
||||
|
||||
}
|
||||
|
||||
//Debug/Troubleshooting Option
|
||||
if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z)
|
||||
{
|
||||
// opts->p25_is_tuned = 0;
|
||||
state->last_cc_sync_time = 0;
|
||||
state->last_vc_sync_time = 0;
|
||||
noCarrier(opts, state);
|
||||
}
|
||||
|
||||
//anything with an entry box will need the inputs and outputs stopped first
|
||||
//so probably just write a function to handle c input, and when c = certain values
|
||||
//needing an entry box, then stop all of those
|
||||
|
||||
@@ -273,4 +273,9 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
||||
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //make user configurable later
|
||||
address.sin_port = htons(udp_port);
|
||||
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
||||
|
||||
//BUGFIX: This was causing an indefinite number of UDP sockets to stay open on each tune request
|
||||
//we open a new socket with each request, so we need to close the socket after writing to it
|
||||
//this would cause the tuning to stop after x number of tune attempts (few hours? on a busy system)
|
||||
close (handle); //close socket after sending.
|
||||
}
|
||||
@@ -82,35 +82,24 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
}
|
||||
|
||||
// Read the new sample from the input
|
||||
if(opts->audio_in_type == 0) // && state->menuopen == 0 still not quite working
|
||||
if(opts->audio_in_type == 0) //pulse audio
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||
}
|
||||
|
||||
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)
|
||||
else if (opts->audio_in_type == 1) //won't work in windows, needs posix pipe (mintty)
|
||||
{
|
||||
result = sf_read_short(opts->audio_in_file, &sample, 1);
|
||||
if(result == 0)
|
||||
{
|
||||
//cleanupAndExit (opts, state);
|
||||
sf_close(opts->audio_in_file);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //send zero sample
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
}
|
||||
//wav files, same but using seperate value so we can still manipulate ncurses menu
|
||||
@@ -122,10 +111,15 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
|
||||
sf_close(opts->audio_in_file);
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse inpput
|
||||
sample = 0; //send zero sample
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
else if (opts->audio_in_type == 3)
|
||||
@@ -147,24 +141,28 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
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 inpput
|
||||
sample = 0; //zero sample on bad result, keep the ball rolling
|
||||
|
||||
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
|
||||
//open pulse input if we are pulse output AND using ncurses terminal
|
||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
opts->audio_in_type = 0; //set input type
|
||||
openPulseInput(opts); //open pulse input
|
||||
}
|
||||
//else cleanup and exit
|
||||
else cleanupAndExit(opts, state);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//UDP Socket input...not working correct. Reads samples, but no sync
|
||||
else if (opts->audio_in_type == 6)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
@@ -383,6 +381,12 @@ 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)
|
||||
{
|
||||
@@ -399,14 +403,23 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
useconds_t stime = state->symbol_throttle;
|
||||
if (state->use_throttle == 1)
|
||||
{
|
||||
usleep(stime);
|
||||
// usleep(stime);
|
||||
usleep(.003); //very environment specific, tuning to cygwin
|
||||
}
|
||||
//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);
|
||||
openPulseInput(opts);
|
||||
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);
|
||||
}
|
||||
|
||||
//assign symbol/dibit values based on modulation type
|
||||
|
||||
@@ -480,7 +480,8 @@ decode_bch()
|
||||
}
|
||||
}
|
||||
|
||||
long int messagepp = 0x0;
|
||||
//bugfix on 32-bit cygwin, probably overflowed here
|
||||
unsigned long long int messagepp = 0x0;
|
||||
|
||||
//very simplified version, just to encode, get frame and compare
|
||||
unsigned long long int edacs_bch (unsigned long long int message)
|
||||
|
||||
@@ -47,12 +47,13 @@ char * getTimeE(void) //get pretty hh:mm:ss timestamp
|
||||
|
||||
void edacs(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
unsigned long long fr_1 = 0xFFFFFFFFFF; //40-bit frames
|
||||
unsigned long long fr_2 = 0; //each is a 40 bit frame that repeats 3 times
|
||||
unsigned long long fr_3 = 0; //two messages per frame
|
||||
unsigned long long fr_4 = 0xFFFFFFFFFF;
|
||||
unsigned long long fr_5 = 0;
|
||||
unsigned long long fr_6 = 0;
|
||||
//changed to ulli here for 32-bit cygwin (not sure if was an issue, but playing it safe)
|
||||
unsigned long long int fr_1 = 0xFFFFFFFFFF; //40-bit frames
|
||||
unsigned long long int fr_2 = 0; //each is a 40 bit frame that repeats 3 times
|
||||
unsigned long long int fr_3 = 0; //two messages per frame
|
||||
unsigned long long int fr_4 = 0xFFFFFFFFFF;
|
||||
unsigned long long int fr_5 = 0;
|
||||
unsigned long long int fr_6 = 0;
|
||||
|
||||
//BCH stuff
|
||||
unsigned long long int fr_1m = 0xFFFFFFF; //28-bit 7X message portion to pass to bch handler
|
||||
|
||||
@@ -312,11 +312,11 @@ void map_isch()
|
||||
isch_map["fb063f092"] = 127;
|
||||
}
|
||||
|
||||
unsigned long long int isch_lookup (unsigned long long int isch)
|
||||
int isch_lookup (unsigned long long int isch)
|
||||
{
|
||||
map_isch(); //initialize the lookup map
|
||||
char s[64];
|
||||
unsigned long long int decoded = -2; //initialize lookup to an invalid number
|
||||
int decoded = -2; //initialize lookup to an invalid number
|
||||
sprintf(s, "%llx", isch);
|
||||
decoded = isch_map[s];
|
||||
return(decoded);
|
||||
|
||||
@@ -287,6 +287,13 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
//extra safeguards due to sync issues with NXDN
|
||||
memset (state->nxdn_sacch_frame_segment, 0, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
state->lastsynctype = -1;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//
|
||||
|
||||
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;
|
||||
@@ -295,6 +302,13 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
//extra safeguards due to sync issues with NXDN
|
||||
memset (state->nxdn_sacch_frame_segment, 0, sizeof(state->nxdn_sacch_frame_segment));
|
||||
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||
state->lastsynctype = -1;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
//
|
||||
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
@@ -653,6 +667,9 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//check the rkey array for a scrambler key value
|
||||
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
|
||||
|
||||
if (state->nxdn_cipher_type == 0x01 && state->R > 0) //scrambler key value
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
@@ -247,7 +247,30 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits);
|
||||
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
|
||||
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
|
||||
if (voice) nxdn_voice (opts, state, voice, dbuf);
|
||||
if (voice)
|
||||
{
|
||||
//restore MBE file open here
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
//update last voice sync time
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
//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 ( (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
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
END: ; //do nothing
|
||||
|
||||
@@ -76,7 +76,7 @@ int vc_counter = 0;
|
||||
int framing_counter = 0;
|
||||
|
||||
unsigned long long int isch = 0;
|
||||
unsigned long long int isch_decoded = 0;
|
||||
int isch_decoded = -1;
|
||||
int p2_duid[8] = {0};
|
||||
int16_t duid_decoded = 0;
|
||||
|
||||
@@ -369,7 +369,7 @@ void process_ISCH (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
isch_decoded = isch_lookup(isch);
|
||||
|
||||
if (isch_decoded > 0)
|
||||
if (isch_decoded > -1)
|
||||
{
|
||||
int uf_count = isch_decoded & 0x3;
|
||||
int free = (isch_decoded >> 2) & 0x1;
|
||||
@@ -411,6 +411,7 @@ void process_ISCH (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
isch_decoded = -1; //reset to bad value after running
|
||||
|
||||
}
|
||||
|
||||
@@ -474,6 +475,10 @@ 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);
|
||||
@@ -625,6 +630,10 @@ 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);
|
||||
|
||||
@@ -685,10 +694,20 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
if (state->currentslot == 0 && duid_decoded != 3 && duid_decoded != 12)
|
||||
{
|
||||
fprintf (stderr, "VCH 0 ");
|
||||
//open MBEout file - slot 1 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
|
||||
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
|
||||
{
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
else if (state->currentslot == 1 && duid_decoded != 3 && duid_decoded != 12)
|
||||
{
|
||||
fprintf (stderr, "VCH 1 ");
|
||||
//open MBEout file - slot 2 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
|
||||
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
|
||||
{
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
|
||||
}
|
||||
}
|
||||
else fprintf (stderr, "VCH S ");
|
||||
|
||||
@@ -827,6 +846,16 @@ 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;
|
||||
state->p2_is_lcch = 0;
|
||||
|
||||
//bugfix for OSS dmrbust 16 shim, reset both to 0 upon exit
|
||||
//in case or marginal signal and both get stuck on 16, indefinitely muting the non-preferred slot
|
||||
//but...this can also cause at least one 4v/2v to get through on the other slot if the sync lines up that way
|
||||
if (opts->audio_out_type == 5)
|
||||
{
|
||||
//set both to blank value
|
||||
state->dmrburstL = 17;
|
||||
state->dmrburstR = 17;
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
@@ -105,6 +105,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;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -170,6 +173,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;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -233,6 +239,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//monstrocity below should get us evaluating and tuning groups...hopefully, will be first come first served though, no priority
|
||||
//see how many loops we need to run on when to tune if first group is blocked
|
||||
int loop = 1;
|
||||
@@ -343,6 +352,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;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -460,7 +472,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
SKIPCALL: ; //do nothing
|
||||
}
|
||||
|
||||
//Group Voice Channel Grant Update Multiple - Explicit
|
||||
@@ -486,6 +497,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
freq1t = process_channel_to_freq (opts, state, channelt2);
|
||||
freq1r = process_channel_to_freq (opts, state, channelr2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 1;
|
||||
if (channelt2 == channelt2) loop = 1;
|
||||
else loop = 2;
|
||||
@@ -590,6 +604,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 3 [%04X] Group 3 [%d][%04X]", channel3, group3, group3);
|
||||
freq3 = process_channel_to_freq (opts, state, channel3);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 3;
|
||||
|
||||
long int tunable_freq = 0;
|
||||
@@ -693,6 +710,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 1;
|
||||
if (channel1 == channel2) loop = 1;
|
||||
else loop = 2;
|
||||
@@ -805,6 +825,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;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
{
|
||||
@@ -892,6 +915,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n RFSS Status Broadcast - Implicit \n");
|
||||
fprintf (stderr, " LRA [%02X] SYSID [%03X] RFSS ID [%02X] SITE ID [%02X] CHAN [%04X] SSC [%02X] ", lra, lsysid, rfssid, siteid, channel, sysclass);
|
||||
process_channel_to_freq (opts, state, channel);
|
||||
|
||||
state->p2_siteid = siteid;
|
||||
state->p2_rfssid = rfssid;
|
||||
}
|
||||
|
||||
//RFSS Status Broadcast - Explicit
|
||||
@@ -908,6 +934,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, " LRA [%02X] SYSID [%03X] RFSS ID [%02X] SITE ID [%02X]\n CHAN-T [%04X] CHAN-R [%02X] SSC [%02X] ", lra, lsysid, rfssid, siteid, channelt, channelr, sysclass);
|
||||
process_channel_to_freq (opts, state, channelt);
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
|
||||
state->p2_siteid = siteid;
|
||||
state->p2_rfssid = rfssid;
|
||||
}
|
||||
|
||||
//Unit-to-Unit Answer Request (UU_ANS_REQ)
|
||||
@@ -1056,6 +1085,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
process_channel_to_freq (opts, state, channelr);
|
||||
}
|
||||
|
||||
state->p2_siteid = siteid;
|
||||
state->p2_rfssid = rfssid;
|
||||
|
||||
}
|
||||
|
||||
//Secondary Control Channel Broadcast, Implicit
|
||||
@@ -1085,7 +1117,10 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
state->trunk_lcn_freq[1] = freq1;
|
||||
state->trunk_lcn_freq[2] = freq2;
|
||||
state->lcn_freq_count = 3; //increment to three
|
||||
}
|
||||
}
|
||||
|
||||
state->p2_siteid = siteid;
|
||||
state->p2_rfssid = rfssid;
|
||||
|
||||
}
|
||||
|
||||
@@ -1315,6 +1350,8 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
}
|
||||
|
||||
SKIPCALL: ; //do nothing
|
||||
|
||||
if ( (len_b + len_c) < 24 && len_c != 0)
|
||||
{
|
||||
len_a = len_b;
|
||||
|
||||
@@ -202,6 +202,10 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
//print it and then zero out
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
|
||||
}
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
@@ -218,6 +222,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
//print it and then zero out
|
||||
state->lastsrcR = 0;
|
||||
state->lasttgR = 0;
|
||||
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
@@ -232,8 +239,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
}
|
||||
if (opcode == 0x4 && err == 0)
|
||||
{
|
||||
if (state->currentslot == 1) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
|
||||
//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);
|
||||
@@ -241,8 +249,18 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
}
|
||||
if (opcode == 0x6 && err == 0)
|
||||
{
|
||||
if (state->currentslot == 1) state->dmrburstL = 22;
|
||||
else state->dmrburstR = 22;
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
state->dmrburstL = 21;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmrburstR = 21;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
fprintf (stderr, " MAC_HANGTIME ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
process_MAC_VPDU(opts, state, 1, SMAC);
|
||||
@@ -412,6 +430,10 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
//print it and then zero out
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
@@ -428,6 +450,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
//print it and then zero out
|
||||
state->lastsrcR = 0;
|
||||
state->lasttgR = 0;
|
||||
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
@@ -462,8 +487,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
}
|
||||
if (opcode == 0x4 && err == 0)
|
||||
{
|
||||
if (state->currentslot == 0) state->dmrburstL = 21;
|
||||
else state->dmrburstR = 21;
|
||||
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
|
||||
//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);
|
||||
@@ -471,8 +497,18 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
}
|
||||
if (opcode == 0x6 && err == 0)
|
||||
{
|
||||
if (state->currentslot == 0) state->dmrburstL = 22;
|
||||
else state->dmrburstR = 22;
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->dmrburstL = 22;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmrburstR = 22;
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
}
|
||||
fprintf (stderr, " MAC_HANGTIME ");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
process_MAC_VPDU(opts, state, 0, FMAC);
|
||||
|
||||
@@ -33,11 +33,11 @@ processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
#ifdef PROVOICE_DUMP
|
||||
fprintf (stderr," ");
|
||||
#endif
|
||||
//init Bits (64)...MI?
|
||||
//iNitial 64 bits
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
k = 0;
|
||||
//fprintf (stderr, "\nInit 64 ");
|
||||
fprintf (stderr, "\n N64: ");
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
initbyte[i] = 0;
|
||||
@@ -47,9 +47,10 @@ processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
initbyte[i] = initbyte[i] | init[k];
|
||||
k++;
|
||||
}
|
||||
//fprintf (stderr, "%02X", initbyte[i]);
|
||||
fprintf (stderr, "%02X", initbyte[i]);
|
||||
if (i == 3) fprintf (stderr, "-");
|
||||
}
|
||||
//fprintf (stderr, "\n");
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
// lid
|
||||
for (i = 0; i < 16; i++)
|
||||
@@ -79,7 +80,7 @@ processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
k = 0;
|
||||
//fprintf (stderr, "LID ");
|
||||
fprintf (stderr, " LID: ");
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
lidbyte[i] = 0;
|
||||
@@ -89,9 +90,10 @@ processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
lidbyte[i] = lidbyte[i] | lid[k];
|
||||
k++;
|
||||
}
|
||||
//fprintf (stderr, "%02X", lidbyte[i]);
|
||||
fprintf (stderr, "%02X", lidbyte[i]);
|
||||
if (i == 3 || i == 7) fprintf (stderr, "-");
|
||||
}
|
||||
//fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -337,7 +339,7 @@ processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
k = 0;
|
||||
//fprintf (stderr, "16 bits? ");
|
||||
fprintf (stderr, "\n 16B: ");
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
initbyte[i] = 0;
|
||||
@@ -347,9 +349,9 @@ if (opts->payload == 1)
|
||||
initbyte[i] = initbyte[i] | init[k];
|
||||
k++;
|
||||
}
|
||||
//fprintf (stderr, "%02X", initbyte[i]);
|
||||
fprintf (stderr, "%02X", initbyte[i]);
|
||||
}
|
||||
//fprintf (stderr, "\n");
|
||||
// fprintf (stderr, "\n");
|
||||
}
|
||||
// imbe frames 3,4 first half
|
||||
w = pW;
|
||||
|
||||
BIN
tone24.wav
BIN
tone24.wav
Binary file not shown.
BIN
tone48.wav
BIN
tone48.wav
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
pacmd load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||
pacmd load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user