mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57629cefe4 | ||
|
|
fe3a135a92 | ||
|
|
8d33c2b3d1 | ||
|
|
593ffbbd66 | ||
|
|
592d57ad87 | ||
|
|
9a31678d9a | ||
|
|
7b3a257df8 | ||
|
|
55e792a925 | ||
|
|
755f77f96c | ||
|
|
1c17757a4e | ||
|
|
abe2e61cf2 | ||
|
|
c404825451 | ||
|
|
769168da5b | ||
|
|
14284c3cf1 | ||
|
|
51f971b68d | ||
|
|
02fdb7cd90 | ||
|
|
64541a1958 | ||
|
|
0a675d3f0f | ||
|
|
e79b6fd231 | ||
|
|
d356ed0dbc | ||
|
|
495eb71090 | ||
|
|
6bf96f1df5 | ||
|
|
3a2db53c3b | ||
|
|
e038016c30 | ||
|
|
7d6269efad | ||
|
|
152f0ea7f6 | ||
|
|
13443a25f3 | ||
|
|
528f7294d9 | ||
|
|
83e3fa1061 | ||
|
|
9b3a2d96e3 | ||
|
|
0829cdbdb0 | ||
|
|
9541aef382 | ||
|
|
4caf6bb153 | ||
|
|
dd77273218 | ||
|
|
3bd3edb36f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ build
|
|||||||
examples
|
examples
|
||||||
*.bin
|
*.bin
|
||||||
*.ans
|
*.ans
|
||||||
|
*.patch
|
||||||
@@ -31,12 +31,6 @@ if (PVC)
|
|||||||
add_definitions(-DPVCONVENTIONAL)
|
add_definitions(-DPVCONVENTIONAL)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
#use cmake option -DNXDN=ON to enable the old NXDN Sync Pattern
|
|
||||||
option(NXDN
|
|
||||||
"Build with Old NXDN Sync Pattern Enabled" OFF)
|
|
||||||
if (NXDN)
|
|
||||||
add_definitions(-DNXDNOLDSYNC)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
|
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
|
||||||
option(LZ
|
option(LZ
|
||||||
@@ -52,13 +46,6 @@ if (TN)
|
|||||||
add_definitions(-DTONES)
|
add_definitions(-DTONES)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
#use cmake option -DZDEV to change designation of this build from MAIN to zDEV
|
|
||||||
option(ZDEV
|
|
||||||
"change designation of this build from MAIN to zDEV" OFF)
|
|
||||||
if (ZDEV)
|
|
||||||
add_definitions(-DZDEV_BUILD)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
include(git_revision)
|
include(git_revision)
|
||||||
git_describe(GIT_TAG)
|
git_describe(GIT_TAG)
|
||||||
|
|
||||||
|
|||||||
67
download-and-install-Arch.sh
Normal file
67
download-and-install-Arch.sh
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
clear
|
||||||
|
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer For Arch Linux
|
||||||
|
echo This will install the required packages, clone, build, and install DSD-FME only.
|
||||||
|
echo This has been tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal.
|
||||||
|
echo
|
||||||
|
echo MBELib is considered a requirement on this build.
|
||||||
|
echo You must view this notice prior to continuing.
|
||||||
|
echo The Patent Notice can be found at the site below.
|
||||||
|
echo https://github.com/lwvmobile/mbelib#readme
|
||||||
|
echo Please confirm that you have viewed the patent notice by entering y below.
|
||||||
|
echo
|
||||||
|
echo y/N
|
||||||
|
read ANSWER
|
||||||
|
Y='y'
|
||||||
|
if [[ $Y == $ANSWER ]]; then
|
||||||
|
|
||||||
|
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
|
||||||
|
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
|
||||||
|
|
||||||
|
echo Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal
|
||||||
|
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||||
|
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||||
|
sudo rm -R itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||||
|
|
||||||
|
git clone https://github.com/lwvmobile/mbelib
|
||||||
|
cd mbelib
|
||||||
|
git checkout ambe_tones
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j `nproc`
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
#sudo cp /usr/local/lib/libmbe.a /usr/lib/libmbe.a
|
||||||
|
sudo cp /usr/local/lib/libmbe.so /usr/lib/libmbe.so #this is the only one we need to copy
|
||||||
|
#sudo cp /usr/local/lib/libmbe.so.1 /usr/lib/libmbe.so.1
|
||||||
|
#sudo cp /usr/local/lib/libmbe.so.1.3 /usr/lib/libmbe.so.1.3
|
||||||
|
cd ..
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
git clone https://github.com/lwvmobile/dsd-fme
|
||||||
|
### For branch v2.1b - git clone --branch v2.1b https://github.com/lwvmobile/dsd-fme
|
||||||
|
cd dsd-fme
|
||||||
|
git checkout v2.1b
|
||||||
|
sudo cp tone8.wav /usr/share/
|
||||||
|
sudo cp tone24.wav /usr/share/
|
||||||
|
sudo cp tone48.wav /usr/share/
|
||||||
|
sudo chmod 777 /usr/share/tone8.wav
|
||||||
|
sudo chmod 777 /usr/share/tone24.wav
|
||||||
|
sudo chmod 777 /usr/share/tone48.wav
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j `nproc`
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
sudo rm -R dsd-fme
|
||||||
|
|
||||||
|
echo Any issues, Please report to either
|
||||||
|
echo https://github.com/lwvmobile/dsd-fme/issues
|
||||||
|
echo https://forums.radioreference.com/threads/dsd-fme.438137/
|
||||||
|
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
|
||||||
|
fi
|
||||||
@@ -100,7 +100,7 @@ and in a second terminal tab, same folder, run
|
|||||||
|
|
||||||
EDACS Trunking (w/ channel map import)
|
EDACS Trunking (w/ channel map import)
|
||||||
|
|
||||||
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (Tested and Working on EDACS/EDACS-EA with Provoice only, no analog voice monitoring)
|
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (Tested and Working on EDACS/EDACS-EA with Provoice, Analog Voice Monitoring and Per Call is Experimental)
|
||||||
|
|
||||||
`dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
|
`dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
|
||||||
|
|
||||||
@@ -192,3 +192,34 @@ e - Toggle Trunking Tuning to Encrypted Calls (P25)
|
|||||||
D - Reset DMR Site Parms/Call Strings, etc.
|
D - Reset DMR Site Parms/Call Strings, etc.
|
||||||
Z - Simulate NoCarrier/No VC/CC sync (capital Z)
|
Z - Simulate NoCarrier/No VC/CC sync (capital Z)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
|
||||||
|
|
||||||
|
Make sure to enable "Stereo Mix" from Volume Control Panel and then disable Windows Sounds.
|
||||||
|
|
||||||
|
`ffmpeg -f dshow -i audio="Stereo Mix (Realtek High Definition Audio)" -c:a aac -b:a 64k -content_type 'audio/aac' -vn -f adts icecast://source:password@192.168.5.251:8844/DSDFME`
|
||||||
|
|
||||||
|
## Sending Audio to a Icecast 2 Server via FFmpeg (Linux w/ Pulse Audio)
|
||||||
|
|
||||||
|
`pactl list short sources`
|
||||||
|
|
||||||
|
Choose Desired Device to Cast:
|
||||||
|
|
||||||
|
```
|
||||||
|
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
|
||||||
|
1 alsa_output.pci-0000_0d_00.3.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||||
|
2 alsa_input.pci-0000_0d_00.3.analog-stereo module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||||
|
3 virtual_sink.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
|
||||||
|
4 virtual_sink2.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
|
||||||
|
7 alsa_output.pci-0000_0b_00.1.hdmi-stereo-extra1.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
francis@12cores:~$ pactl list short sources
|
||||||
|
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
|
||||||
|
francis@12coresx:~$ ffmpeg -f pulse -i 0 -c:a libmp3lame -ab 64k -f mp3 icecast://source:password@XXXXXXXXX:8000
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|||||||
@@ -11,8 +11,18 @@ wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-insta
|
|||||||
chmod +x download-and-install.sh
|
chmod +x download-and-install.sh
|
||||||
./download-and-install.sh
|
./download-and-install.sh
|
||||||
```
|
```
|
||||||
f
|
|
||||||
If you have dependencies already installed (i.e. need a fresh clean install on a system with DSD-FME already or using system other than Debian/Ubuntu, etc), please run this instead:
|
### Arch Based Distros:
|
||||||
|
|
||||||
|
```
|
||||||
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/v2.1b/download-and-install-Arch.sh
|
||||||
|
chmod +x download-and-install-Arch.sh
|
||||||
|
./download-and-install-Arch.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Other:
|
||||||
|
|
||||||
|
If you have dependencies already installed, please run this instead:
|
||||||
|
|
||||||
```
|
```
|
||||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install-nodeps.sh
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-install-nodeps.sh
|
||||||
@@ -31,11 +41,22 @@ sudo apt update
|
|||||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Fedora (Recent Releases) -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||||
|
|
||||||
```
|
```
|
||||||
|
sudo dnf update
|
||||||
sudo dnf install libsndfile-devel fftw-devel lapack-devel rtl-sdr-devel pulseaudio-libs-devel libusb-devel cmake git ncurses ncurses-devel gcc wget pavucontrol gcc-c++ codec2-devel
|
sudo dnf install libsndfile-devel fftw-devel lapack-devel rtl-sdr-devel pulseaudio-libs-devel libusb-devel cmake git ncurses ncurses-devel gcc wget pavucontrol gcc-c++ codec2-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Arch -- https://github.com/lwvmobile/dsd-fme/issues/153 and https://github.com/lwvmobile/dsd-fme/issues/153
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo pacman -Syu
|
||||||
|
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr
|
||||||
|
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||||
|
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||||
|
```
|
||||||
|
|
||||||
## Headless Ubuntu Server/Pi
|
## Headless Ubuntu Server/Pi
|
||||||
|
|
||||||
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
|
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ typedef struct
|
|||||||
int rtl_udp_port;
|
int rtl_udp_port;
|
||||||
int rtl_bandwidth;
|
int rtl_bandwidth;
|
||||||
int rtl_started;
|
int rtl_started;
|
||||||
int rtl_rms;
|
long int rtl_rms;
|
||||||
int monitor_input_audio;
|
int monitor_input_audio;
|
||||||
int pulse_raw_rate_in;
|
int pulse_raw_rate_in;
|
||||||
int pulse_raw_rate_out;
|
int pulse_raw_rate_out;
|
||||||
@@ -414,6 +414,10 @@ typedef struct
|
|||||||
float *audio_out_temp_buf_p;
|
float *audio_out_temp_buf_p;
|
||||||
float audio_out_temp_bufR[160];
|
float audio_out_temp_bufR[160];
|
||||||
float *audio_out_temp_buf_pR;
|
float *audio_out_temp_buf_pR;
|
||||||
|
//analog/raw signal audio buffers
|
||||||
|
short analog_out[960];
|
||||||
|
int analog_sample_counter;
|
||||||
|
//
|
||||||
int audio_out_idx;
|
int audio_out_idx;
|
||||||
int audio_out_idx2;
|
int audio_out_idx2;
|
||||||
int audio_out_idxR;
|
int audio_out_idxR;
|
||||||
@@ -733,6 +737,7 @@ typedef struct
|
|||||||
|
|
||||||
unsigned long long int m17_dst;
|
unsigned long long int m17_dst;
|
||||||
unsigned long long int m17_src;
|
unsigned long long int m17_src;
|
||||||
|
uint8_t m17_can;
|
||||||
|
|
||||||
char m17_dst_csd[20];
|
char m17_dst_csd[20];
|
||||||
char m17_src_csd[20];
|
char m17_src_csd[20];
|
||||||
@@ -740,7 +745,7 @@ typedef struct
|
|||||||
char m17_src_str[50];
|
char m17_src_str[50];
|
||||||
char m17_dst_str[50];
|
char m17_dst_str[50];
|
||||||
|
|
||||||
uint8_t m17_meta[14]; //packed meta
|
uint8_t m17_meta[16]; //packed meta
|
||||||
uint8_t m17_enc; //enc type
|
uint8_t m17_enc; //enc type
|
||||||
uint8_t m17_enc_st; //scrambler or data subtye
|
uint8_t m17_enc_st; //scrambler or data subtye
|
||||||
|
|
||||||
@@ -944,7 +949,6 @@ short nxdn_filter(short sample);
|
|||||||
short dpmr_filter(short sample);
|
short dpmr_filter(short sample);
|
||||||
short m17_filter(short sample);
|
short m17_filter(short sample);
|
||||||
|
|
||||||
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr);
|
|
||||||
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
|
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
|
||||||
|
|
||||||
void ncursesOpen (dsd_opts * opts, dsd_state * state);
|
void ncursesOpen (dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1037,6 +1041,8 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||||
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]);
|
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]);
|
||||||
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]);
|
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]);
|
||||||
|
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18]); //simplier trellis decoder
|
||||||
|
void beeper (dsd_opts * opts, dsd_state * state, int type); //the tone beeper function
|
||||||
|
|
||||||
//Embedded Alias and GPS
|
//Embedded Alias and GPS
|
||||||
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||||
@@ -1074,6 +1080,7 @@ bool crc8_ok(uint8_t bits[], unsigned int len);
|
|||||||
//modified CRC functions for SB/RC
|
//modified CRC functions for SB/RC
|
||||||
uint8_t crc7(uint8_t bits[], unsigned int len);
|
uint8_t crc7(uint8_t bits[], unsigned int len);
|
||||||
uint8_t crc3(uint8_t bits[], unsigned int len);
|
uint8_t crc3(uint8_t bits[], unsigned int len);
|
||||||
|
uint8_t crc4(uint8_t bits[], unsigned int len);
|
||||||
|
|
||||||
//LFSR and LFSRP code courtesy of https://github.com/mattames/LFSR/
|
//LFSR and LFSRP code courtesy of https://github.com/mattames/LFSR/
|
||||||
void LFSR(dsd_state * state);
|
void LFSR(dsd_state * state);
|
||||||
@@ -1179,24 +1186,16 @@ void cleanup_rtlsdr_stream();
|
|||||||
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state);
|
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state);
|
||||||
void rtlsdr_sighandler();
|
void rtlsdr_sighandler();
|
||||||
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
void rtl_dev_tune(dsd_opts * opts, long int frequency);
|
||||||
int rtl_return_rms();
|
long int rtl_return_rms();
|
||||||
void rtl_clean_queue();
|
void rtl_clean_queue();
|
||||||
#endif
|
#endif
|
||||||
//DMR TRELLIS
|
|
||||||
void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload);
|
|
||||||
unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits);
|
|
||||||
bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload);
|
|
||||||
void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits);
|
|
||||||
void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points);
|
|
||||||
void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits);
|
|
||||||
void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits);
|
|
||||||
bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload);
|
|
||||||
|
|
||||||
//Phase 2 Helper Functions
|
//Phase 2 Helper Functions
|
||||||
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME
|
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME
|
||||||
int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
|
int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
|
||||||
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
|
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
|
||||||
int isch_lookup (unsigned long long int isch); //isch map lookup
|
int isch_lookup (uint64_t isch); //isch map lookup
|
||||||
int bd_bridge (int payload[196], uint8_t decoded[12]); //bridge to Michael Ossmann Block De-interleaver and 1/2 rate trellis decoder
|
int bd_bridge (int payload[196], uint8_t decoded[12]); //bridge to Michael Ossmann Block De-interleaver and 1/2 rate trellis decoder
|
||||||
int crc16_lb_bridge (int payload[190], int len);
|
int crc16_lb_bridge (int payload[190], int len);
|
||||||
int crc12_xb_bridge (int payload[190], int len);
|
int crc12_xb_bridge (int payload[190], int len);
|
||||||
|
|||||||
136
src/dmr_34.c
Normal file
136
src/dmr_34.c
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* dmr_34.c
|
||||||
|
* DMR 3/4 Rate Simple Trellis Decoder
|
||||||
|
*
|
||||||
|
* LWVMOBILE
|
||||||
|
* 2023-08 DSD-FME Florida Man Edition
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
uint8_t interleave[98] = {
|
||||||
|
0, 1, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 56, 57, 64, 65, 72, 73, 80, 81, 88, 89, 96, 97,
|
||||||
|
2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66, 67, 74, 75, 82, 83, 90, 91,
|
||||||
|
4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93,
|
||||||
|
6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 95};
|
||||||
|
|
||||||
|
//this is a convertion table for converting the dibit pairs into contellation points
|
||||||
|
uint8_t constellation_map[16] = {
|
||||||
|
11, 12, 0, 7, 14, 9, 5, 2, 10, 13, 1, 6, 15, 8, 4, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
//digitized dibit to OTA symbol conversion for reference
|
||||||
|
//0 = +1; 1 = +3;
|
||||||
|
//2 = -1; 3 = -3;
|
||||||
|
|
||||||
|
//finite state machine values
|
||||||
|
uint8_t fsm[64] = {
|
||||||
|
0, 8, 4, 12, 2, 10, 6, 14,
|
||||||
|
4, 12, 2, 10, 6, 14, 0, 8,
|
||||||
|
1, 9, 5, 13, 3, 11, 7, 15,
|
||||||
|
5, 13, 3, 11, 7, 15, 1, 9,
|
||||||
|
3, 11, 7, 15, 1, 9, 5, 13,
|
||||||
|
7, 15, 1, 9, 5, 13, 3, 11,
|
||||||
|
2, 10, 6, 14, 0, 8, 4, 12,
|
||||||
|
6, 14, 0, 8, 4, 12, 2, 10};
|
||||||
|
|
||||||
|
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18])
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
uint32_t irr_err = 0;
|
||||||
|
|
||||||
|
uint8_t deinterleaved_dibits[98];
|
||||||
|
memset (deinterleaved_dibits, 0, sizeof(deinterleaved_dibits));
|
||||||
|
|
||||||
|
//deinterleave our input dibits
|
||||||
|
for (i = 0; i < 98; i++)
|
||||||
|
deinterleaved_dibits[interleave[i]] = input[i];
|
||||||
|
|
||||||
|
//pack the input into nibbles (dibit pairs)
|
||||||
|
uint8_t nibs[49];
|
||||||
|
memset (nibs, 0, sizeof(nibs));
|
||||||
|
|
||||||
|
for (i = 0; i < 49; i++)
|
||||||
|
nibs[i] = (deinterleaved_dibits[i*2+0] << 2) | (deinterleaved_dibits[i*2+1] << 0);
|
||||||
|
|
||||||
|
//convert our dibit pairs into constellation point values
|
||||||
|
uint8_t point[49];
|
||||||
|
memset (point, 0xFF, sizeof(point));
|
||||||
|
|
||||||
|
for (i = 0; i < 49; i++)
|
||||||
|
point[i] = constellation_map[nibs[i]];
|
||||||
|
|
||||||
|
//debug view points -- point[0] should be zero
|
||||||
|
// fprintf (stderr, "\n P =");
|
||||||
|
// for (i = 0; i < 49; i++)
|
||||||
|
// fprintf (stderr, " %02d", point[i]);
|
||||||
|
|
||||||
|
//free-bee on err correction, point[0] should always be zero (flush bits)
|
||||||
|
point[0] = 0;
|
||||||
|
|
||||||
|
//convert constellation points into tribit values using the FSM
|
||||||
|
uint8_t state = 0;
|
||||||
|
uint32_t tribits[49];
|
||||||
|
memset (tribits, 0xF, sizeof(tribits));
|
||||||
|
|
||||||
|
for (i = 0; i < 49; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
if ( fsm[(state*8)+j] == point[i] )
|
||||||
|
{
|
||||||
|
//return our tribit value and state for the next point
|
||||||
|
tribits[i] = state = (uint8_t)j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if tribit value is greater than 7, then we have a decoding error
|
||||||
|
if (tribits[i] > 7)
|
||||||
|
{
|
||||||
|
irr_err++; //tally number of errors
|
||||||
|
|
||||||
|
//debug position of error and state value
|
||||||
|
// fprintf (stderr, " %d:%d;", i, state);
|
||||||
|
|
||||||
|
//Make a hard decision and flip point to fit in current state
|
||||||
|
point[i] ^= 7; //lucky number 7 (0111)
|
||||||
|
|
||||||
|
//NOTE: Ideally, a full path metric to find the surviving path
|
||||||
|
//is the best way to correct this, but it is also complex and no garauntee to fix errs
|
||||||
|
|
||||||
|
//decrement one and try again
|
||||||
|
if (i != 0) i--;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug view tribits/states
|
||||||
|
// fprintf (stderr, "\n T =");
|
||||||
|
// for (i = 0; i < 49; i++)
|
||||||
|
// fprintf (stderr, " %02d", tribits[i]);
|
||||||
|
|
||||||
|
//convert tribits into a return payload
|
||||||
|
uint32_t temp = 0;
|
||||||
|
if (1 == 1) //irr_err == 0
|
||||||
|
{
|
||||||
|
//break into chunks of 24 bit values and shuffle into 8-bit (byte) treturn values
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
temp = (tribits[(i*8)+0] << 21) + (tribits[(i*8)+1] << 18) + (tribits[(i*8)+2] << 15) + (tribits[(i*8)+3] << 12) + (tribits[(i*8)+4] << 9) + (tribits[(i*8)+5] << 6) + (tribits[(i*8)+6] << 3) + (tribits[(i*8)+7] << 0);
|
||||||
|
|
||||||
|
treturn[(i*3)+0] = (temp >> 16) & 0xFF;
|
||||||
|
treturn[(i*3)+1] = (temp >> 8) & 0xFF;
|
||||||
|
treturn[(i*3)+2] = (temp >> 0) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//trellis point/state err tally
|
||||||
|
if (irr_err != 0)
|
||||||
|
fprintf (stderr, " ERR = %d", irr_err);
|
||||||
|
|
||||||
|
return (irr_err);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -418,34 +418,29 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//the ugly one
|
//the sexy one
|
||||||
if (is_trellis)
|
if (is_trellis)
|
||||||
{
|
{
|
||||||
CRCExtracted = 0;
|
CRCExtracted = 0;
|
||||||
CRCComputed = 0;
|
CRCComputed = 0;
|
||||||
IrrecoverableErrors = 1;
|
IrrecoverableErrors = 1;
|
||||||
bool trellis_good = TRUE;
|
|
||||||
|
|
||||||
uint8_t tdibits[98];
|
uint8_t tdibits[98];
|
||||||
memset (tdibits, 0, sizeof(tdibits));
|
memset (tdibits, 0, sizeof(tdibits));
|
||||||
|
|
||||||
//reconstitute info bits into reverse ordered dibits for the trellis decoder
|
//reconstitute info bits into dibits for the trellis decoder
|
||||||
for (i = 0; i < 98; i++)
|
for (i = 0; i < 98; i++)
|
||||||
{
|
tdibits[i] = (info[i*2] << 1) | info[i*2+1];
|
||||||
tdibits[97-i] = (info[i*2] << 1) | info[i*2+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char TrellisReturn[18];
|
uint8_t TrellisReturn[18];
|
||||||
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
||||||
|
IrrecoverableErrors = dmr_34(tdibits, TrellisReturn);
|
||||||
|
|
||||||
trellis_good = CDMRTrellisDecode(tdibits, TrellisReturn);
|
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
|
||||||
if (trellis_good == TRUE) IrrecoverableErrors = 0;
|
//they may have been successfully corrected, the CRC will reveal as much
|
||||||
// else (fprintf (stderr, " Trellis Failure")); //debug print
|
|
||||||
|
|
||||||
for (i = 0; i < pdu_len; i++) //18
|
for (i = 0; i < pdu_len; i++)
|
||||||
{
|
DMR_PDU[i] = TrellisReturn[i+pdu_start];
|
||||||
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0, j = 0; i < 18; i++, j+=8)
|
for(i = 0, j = 0; i < 18; i++, j+=8)
|
||||||
{
|
{
|
||||||
@@ -471,7 +466,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
CRCExtracted = CRCExtracted ^ crcmask;
|
CRCExtracted = CRCExtracted ^ crcmask;
|
||||||
|
|
||||||
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
|
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
|
||||||
//confirmed working now!
|
|
||||||
for(i = 0; i < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
|
for(i = 0; i < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
|
||||||
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
|
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
|
||||||
|
|
||||||
@@ -482,10 +476,8 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
state->data_block_crc_valid[slot][blockcounter] = 1;
|
state->data_block_crc_valid[slot][blockcounter] = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix
|
|
||||||
state->data_block_crc_valid[slot][blockcounter] = 0;
|
state->data_block_crc_valid[slot][blockcounter] = 0;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +497,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_full) //Rate 1 Data
|
if (is_full) //Rate 1 Data -- todo: fix padding bits, the four padding bits are on bit 96,97,98,99
|
||||||
{
|
{
|
||||||
CRCExtracted = 0;
|
CRCExtracted = 0;
|
||||||
CRCComputed = 0;
|
CRCComputed = 0;
|
||||||
@@ -605,7 +597,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (IrrecoverableErrors != 0 && databurst != 0x09) //&& databurst != 0x05
|
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf(stderr, " (FEC ERR)");
|
fprintf(stderr, " (FEC ERR)");
|
||||||
|
|||||||
81
src/dmr_le.c
81
src/dmr_le.c
@@ -52,6 +52,12 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
uint64_t mi_corrected = 0;
|
uint64_t mi_corrected = 0;
|
||||||
uint64_t go_corrected = 0;
|
uint64_t go_corrected = 0;
|
||||||
|
|
||||||
|
uint8_t mi_bits[36];
|
||||||
|
memset (mi_bits, 0, sizeof(mi_bits));
|
||||||
|
uint8_t mi_crc_cmp = 0;
|
||||||
|
uint8_t mi_crc_ext = 1;
|
||||||
|
uint8_t mi_crc_ok = 0;
|
||||||
|
|
||||||
mi_test = (state->late_entry_mi_fragment[slot][1][0] << 32L) | (state->late_entry_mi_fragment[slot][2][0] << 28) | (state->late_entry_mi_fragment[slot][3][0] << 24) |
|
mi_test = (state->late_entry_mi_fragment[slot][1][0] << 32L) | (state->late_entry_mi_fragment[slot][2][0] << 28) | (state->late_entry_mi_fragment[slot][3][0] << 24) |
|
||||||
(state->late_entry_mi_fragment[slot][1][1] << 20) | (state->late_entry_mi_fragment[slot][2][1] << 16) | (state->late_entry_mi_fragment[slot][3][1] << 12) |
|
(state->late_entry_mi_fragment[slot][1][1] << 20) | (state->late_entry_mi_fragment[slot][2][1] << 16) | (state->late_entry_mi_fragment[slot][3][1] << 12) |
|
||||||
(state->late_entry_mi_fragment[slot][1][2] << 8) | (state->late_entry_mi_fragment[slot][2][2] << 4) | (state->late_entry_mi_fragment[slot][3][2] << 0);
|
(state->late_entry_mi_fragment[slot][1][2] << 8) | (state->late_entry_mi_fragment[slot][2][2] << 4) | (state->late_entry_mi_fragment[slot][3][2] << 0);
|
||||||
@@ -77,12 +83,22 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
mi_corrected |= mi_go_bits[i];
|
mi_corrected |= mi_go_bits[i];
|
||||||
go_corrected = go_corrected << 1;
|
go_corrected = go_corrected << 1;
|
||||||
go_corrected |= mi_go_bits[i+12];
|
go_corrected |= mi_go_bits[i+12];
|
||||||
|
//manipulate for crc check
|
||||||
|
mi_bits[i+(j*12)] = mi_go_bits[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int mi_final = 0;
|
int mi_final = 0;
|
||||||
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF;
|
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
mi_crc_ext = (uint8_t)ConvertBitIntoBytes(&mi_bits[32], 4);
|
||||||
|
mi_crc_cmp = crc4(mi_bits, 32);
|
||||||
|
if (mi_crc_ext == mi_crc_cmp)
|
||||||
|
mi_crc_ok = 1;
|
||||||
|
|
||||||
|
//debug -- working now
|
||||||
|
// fprintf (stderr, " LE MI: %09llX; CRC EXT: %X; CRC CMP: %X; \n", mi_corrected, mi_crc_ext, mi_crc_cmp);
|
||||||
|
|
||||||
if (g[0] && g[1] && g[2])
|
if (g[0] && g[1] && g[2])
|
||||||
{
|
{
|
||||||
if (slot == 0 && state->payload_algid != 0)
|
if (slot == 0 && state->payload_algid != 0)
|
||||||
@@ -90,8 +106,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->payload_mi != mi_final)
|
if (state->payload_mi != mi_final)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_mi, mi_final);
|
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_mi, mi_final);
|
||||||
state->payload_mi = mi_final;
|
state->payload_mi = mi_final;
|
||||||
|
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
||||||
|
else fprintf (stderr, "(CRC ERR)");
|
||||||
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
//run afterwards, or le verification won't match up properly
|
//run afterwards, or le verification won't match up properly
|
||||||
@@ -106,8 +125,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->payload_miR != mi_final)
|
if (state->payload_miR != mi_final)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_miR, mi_final);
|
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_miR, mi_final);
|
||||||
state->payload_miR = mi_final;
|
state->payload_miR = mi_final;
|
||||||
|
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
||||||
|
else fprintf (stderr, "(CRC ERR)");
|
||||||
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
//run afterwards, or le verification won't match up properly
|
//run afterwards, or le verification won't match up properly
|
||||||
@@ -268,7 +290,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sbrc_opcode = sbrc_hex & 0x7; //opcode and alg the same bits, but the alg is present when CRC is bad (I know they are limited on bits, but I hate that idea)
|
uint8_t sbrc_opcode = sbrc_hex & 0x7; //opcode and alg the same bits, but the alg is present when CRC is bad (I know they are limited on bits, but I hate that idea)
|
||||||
uint8_t alg = sbrc_hex & 0x7;
|
uint8_t alg = sbrc_hex & 0x7; //SEE: https://patents.google.com/patent/EP2347540B1/en
|
||||||
uint8_t key = (sbrc_hex >> 3) & 0xFF;
|
uint8_t key = (sbrc_hex >> 3) & 0xFF;
|
||||||
uint8_t txi_delay = (sbrc_hex >> 3) & 0x1F; //middle five are the 'delay' value on a TXI system
|
uint8_t txi_delay = (sbrc_hex >> 3) & 0x1F; //middle five are the 'delay' value on a TXI system
|
||||||
|
|
||||||
@@ -299,22 +321,30 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
else if (crc3_okay == 1 && (sbrc_opcode == 0 || sbrc_opcode == 3) )
|
else if (crc3_okay == 1 && (sbrc_opcode == 0 || sbrc_opcode == 3) )
|
||||||
{
|
{
|
||||||
//opcodes -- 0 (NULL), BR Delay (3)
|
//opcodes -- 0 (NULL), BR Delay (3)
|
||||||
fprintf (stderr, "\n");
|
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||||
fprintf (stderr, " TXI Op: %X - ", sbrc_opcode);
|
fprintf (stderr, "%s", KCYN);
|
||||||
|
fprintf (stderr, " TXI Op: %X -", sbrc_opcode);
|
||||||
if (sbrc_opcode == 0) fprintf (stderr, " Null; ");
|
if (sbrc_opcode == 0) fprintf (stderr, " Null; ");
|
||||||
else if (sbrc_opcode == 3)
|
else if (sbrc_opcode == 3)
|
||||||
{
|
{
|
||||||
if (txi_delay != 0)
|
if (txi_delay != 0)
|
||||||
fprintf (stderr, " BR Delay: %d - %d ms; ", txi_delay, txi_delay * 30); //could also indicate number of superframes until next VC6 pre-emption
|
fprintf (stderr, " BR Delay: %d - %d ms;", txi_delay, txi_delay * 30); //could also indicate number of superframes until next VC6 pre-emption
|
||||||
else fprintf (stderr, "BR Delay: Irrelevant / Send at any time;");
|
else fprintf (stderr, "BR Delay: Irrelevant / Send at any time;");
|
||||||
|
|
||||||
|
//alignment of inbound backwards channel and outbound burst
|
||||||
|
if (txi_delay == 2) fprintf (stderr, " SF3, Burst E;"); //E is inbound
|
||||||
|
if (txi_delay == 4) fprintf (stderr, " SF3, Burst D;"); //D is inbound
|
||||||
|
if (txi_delay == 6) fprintf (stderr, " SF3, Burst C;"); //C is inbound
|
||||||
|
if (txi_delay == 8) fprintf (stderr, " SF3, Burst B;"); //B is inbound
|
||||||
}
|
}
|
||||||
else fprintf (stderr, " Unk; ");
|
else fprintf (stderr, " Unk; ");
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n"); //only during payload
|
if (opts->payload == 1) fprintf (stderr, "\n"); //only during payload
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (sbrc_opcode != 0 || sbrc_opcode != 3) //all that should be left in this field is the potential ENC identifiers
|
else if (sbrc_opcode != 0 && sbrc_opcode != 3) //all that should be left in this field is the potential ENC identifiers
|
||||||
{
|
{
|
||||||
|
|
||||||
if (slot == 0) //may not need the state->errs anymore //&& state->errs < 3
|
if (slot == 0) //may not need the state->errs anymore //&& state->errs < 3
|
||||||
@@ -325,12 +355,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
if (state->M == 0)
|
if (state->M == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s ", KYEL);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 1");
|
fprintf (stderr, " Slot 1");
|
||||||
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||||
state->payload_keyid = key;
|
state->payload_keyid = key;
|
||||||
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||||
}
|
}
|
||||||
@@ -346,12 +375,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
if (state->M == 0)
|
if (state->M == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s ", KYEL);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 2");
|
fprintf (stderr, " Slot 2");
|
||||||
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
|
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
||||||
// fprintf (stderr, "\n");
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||||
state->payload_keyidR = key;
|
state->payload_keyidR = key;
|
||||||
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
|
||||||
}
|
}
|
||||||
@@ -408,3 +436,26 @@ uint8_t crc3(uint8_t bits[], unsigned int len)
|
|||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t crc4(uint8_t bits[], unsigned int len)
|
||||||
|
{
|
||||||
|
uint8_t crc=0;
|
||||||
|
unsigned int K = 4;
|
||||||
|
//x^4+x+1
|
||||||
|
uint8_t poly[5] = {1,0,0,1,1};
|
||||||
|
uint8_t buf[256];
|
||||||
|
if (len+K > sizeof(buf)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset (buf, 0, sizeof(buf));
|
||||||
|
for (unsigned int i=0; i<len; i++){
|
||||||
|
buf[i] = bits[i];
|
||||||
|
}
|
||||||
|
for (unsigned int i=0; i<len; i++)
|
||||||
|
if (buf[i])
|
||||||
|
for (unsigned int j=0; j<K+1; j++)
|
||||||
|
buf[i+j] ^= poly[j];
|
||||||
|
for (unsigned int i=0; i<K; i++){
|
||||||
|
crc = (crc << 1) + buf[len + i];
|
||||||
|
}
|
||||||
|
return crc ^ 0xF; //invert
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ void closePulseOutput (dsd_opts * opts)
|
|||||||
{
|
{
|
||||||
pa_simple_free (opts->pulse_digi_dev_out);
|
pa_simple_free (opts->pulse_digi_dev_out);
|
||||||
if (opts->dmr_stereo == 1)
|
if (opts->dmr_stereo == 1)
|
||||||
{
|
|
||||||
pa_simple_free (opts->pulse_digi_dev_outR);
|
pa_simple_free (opts->pulse_digi_dev_outR);
|
||||||
}
|
|
||||||
|
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) //EDACS analog calls and/or monitoring source analog audio
|
||||||
|
pa_simple_free (opts->pulse_raw_dev_out);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void closePulseInput (dsd_opts * opts)
|
void closePulseInput (dsd_opts * opts)
|
||||||
@@ -47,10 +49,9 @@ void openPulseOutput(dsd_opts * opts)
|
|||||||
tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
|
tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
|
||||||
tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
|
tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
|
||||||
|
|
||||||
if (opts->monitor_input_audio == 1)
|
//reconfigured to open when using edacs or raw analog monitor so we can have a analog audio out that runs at 48k1 and not 8k1 float/short
|
||||||
{
|
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
|
||||||
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL);
|
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Analog", &ss, 0, NULL, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
//tt
|
//tt
|
||||||
pa_channel_map* left = 0; //NULL and 0 are same in this context
|
pa_channel_map* left = 0; //NULL and 0 are same in this context
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
|
|||||||
}
|
}
|
||||||
|
|
||||||
char * getDateF(void) {
|
char * getDateF(void) {
|
||||||
char datename[80]; //32-bit needs this to be 80
|
#ifdef AERO_BUILD
|
||||||
|
char datename[80];
|
||||||
|
#else
|
||||||
|
char datename[99];
|
||||||
|
#endif
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
time_t t;
|
time_t t;
|
||||||
|
|||||||
@@ -177,19 +177,19 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
|
|
||||||
sprintf (state->fsubtype, " VOICE ");
|
sprintf (state->fsubtype, " VOICE ");
|
||||||
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
|
if (opts->dmr_stereo == 0 && state->synctype < 32)
|
||||||
{
|
{
|
||||||
sprintf (state->slot1light, " slot1 ");
|
sprintf (state->slot1light, " slot1 ");
|
||||||
sprintf (state->slot2light, " slot2 ");
|
sprintf (state->slot2light, " slot2 ");
|
||||||
//we can safely open MBE on any MS or mono handling
|
//we can safely open MBE on any MS or mono handling
|
||||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||||
dmrMSBootstrap (opts, state);
|
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
||||||
}
|
}
|
||||||
if (opts->dmr_mono == 1 && state->synctype == 32)
|
if (opts->dmr_mono == 1 && state->synctype == 32)
|
||||||
{
|
{
|
||||||
//we can safely open MBE on any MS or mono handling
|
//we can safely open MBE on any MS or mono handling
|
||||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||||
dmrMSBootstrap (opts, state);
|
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
||||||
}
|
}
|
||||||
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
||||||
{
|
{
|
||||||
@@ -198,7 +198,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
//we can safely open MBE on any MS or mono handling
|
//we can safely open MBE on any MS or mono handling
|
||||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||||
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
|
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
|
||||||
}
|
}
|
||||||
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
|
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||||
dmrMSData (opts, state);
|
if (opts->p25_trunk == 0) dmrMSData (opts, state);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -219,7 +219,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
state->err_str[0] = 0;
|
state->err_str[0] = 0;
|
||||||
sprintf (state->slot1light, " slot1 ");
|
sprintf (state->slot1light, " slot1 ");
|
||||||
sprintf (state->slot2light, " slot2 ");
|
sprintf (state->slot2light, " slot2 ");
|
||||||
state->payload_miP = 0; //zero out when switching back to data sync
|
|
||||||
dmr_data_sync (opts, state);
|
dmr_data_sync (opts, state);
|
||||||
}
|
}
|
||||||
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
|
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
|
||||||
@@ -231,7 +230,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
state->dmr_stereo = 0; //set the state to zero for handling pure data frames
|
state->dmr_stereo = 0; //set the state to zero for handling pure data frames
|
||||||
sprintf (state->slot1light, " slot1 ");
|
sprintf (state->slot1light, " slot1 ");
|
||||||
sprintf (state->slot2light, " slot2 ");
|
sprintf (state->slot2light, " slot2 ");
|
||||||
state->payload_miP = 0; //zero out when switching back to data sync
|
|
||||||
dmr_data_sync (opts, state);
|
dmr_data_sync (opts, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,7 +296,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) || (state->synctype == 99) || (state->synctype == 98))
|
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) || (state->synctype == 99) || (state->synctype == 98))
|
||||||
{
|
{
|
||||||
if (state->synctype == 98 || state->synctype == 99) //preamble only
|
if (state->synctype == 98 || state->synctype == 99) //preamble only
|
||||||
skipDibit(opts, state, 184); //skip dibits to prime the demodulator
|
skipDibit(opts, state, 8); //skip dibits to prime the demodulator
|
||||||
else if (state->synctype == 16 || state->synctype == 17)
|
else if (state->synctype == 16 || state->synctype == 17)
|
||||||
processM17STR(opts, state);
|
processM17STR(opts, state);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -18,39 +18,6 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
//borrowed from LEH/DSDcc for 'improved NXDN sync detection'
|
|
||||||
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr)
|
|
||||||
{
|
|
||||||
|
|
||||||
int Compare = -1;
|
|
||||||
size_t i = 0;
|
|
||||||
int err = 0;
|
|
||||||
int BreakBeforeEnd = 0;
|
|
||||||
|
|
||||||
if(s1 && s2)
|
|
||||||
{
|
|
||||||
for(i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
if(((s1[i] & 0xFF) != '\0') && ((s2[i] & 0xFF) != '\0'))
|
|
||||||
{
|
|
||||||
if((s1[i] & 0xFF) != (s2[i] & 0xFF)) err++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BreakBeforeEnd = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err <= MaxErr) && (BreakBeforeEnd == 0))
|
|
||||||
{
|
|
||||||
Compare = 0;
|
|
||||||
}
|
|
||||||
} /* End if(s1 && s2) */
|
|
||||||
|
|
||||||
return Compare;
|
|
||||||
} /* End strncmperr() */
|
|
||||||
|
|
||||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||||
{
|
{
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
@@ -67,7 +34,11 @@ char * getTime(void) //get pretty hh:mm:ss timestamp
|
|||||||
}
|
}
|
||||||
|
|
||||||
char * getDate(void) {
|
char * getDate(void) {
|
||||||
char datename[32];
|
#ifdef AERO_BUILD
|
||||||
|
char datename[80];
|
||||||
|
#else
|
||||||
|
char datename[99];
|
||||||
|
#endif
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
time_t t;
|
time_t t;
|
||||||
@@ -209,7 +180,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
char synctest[25];
|
char synctest[25];
|
||||||
char synctest12[13]; //dPMR
|
char synctest12[13]; //dPMR
|
||||||
char synctest10[11]; //NXDN FSW only
|
char synctest10[11]; //NXDN FSW only
|
||||||
char synctest19[20]; //NXDN Preamble + FSW
|
|
||||||
char synctest18[19];
|
char synctest18[19];
|
||||||
char synctest32[33];
|
char synctest32[33];
|
||||||
char synctest20[21]; //YSF
|
char synctest20[21]; //YSF
|
||||||
@@ -250,7 +220,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
else t_max = 24; //24 for everything else
|
else t_max = 24; //24 for everything else
|
||||||
|
|
||||||
int lbuf[t_max], lbuf2[t_max];
|
int lbuf[48], lbuf2[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max
|
||||||
int lsum;
|
int lsum;
|
||||||
char spectrum[64];
|
char spectrum[64];
|
||||||
//init the lbuf
|
//init the lbuf
|
||||||
@@ -740,10 +710,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, " P2 Missing Parameters ");
|
fprintf (stderr, " P2 Missing Parameters ");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (35); //35
|
return (35); //35
|
||||||
}
|
}
|
||||||
@@ -779,10 +745,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
state->lastsynctype = 36; //36
|
state->lastsynctype = 36; //36
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (36); //36
|
return (36); //36
|
||||||
}
|
}
|
||||||
@@ -814,10 +776,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
printFrameSync (opts, state, "+dPMR ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "+dPMR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 21;
|
state->lastsynctype = 21;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (21);
|
return (21);
|
||||||
}
|
}
|
||||||
if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
|
if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
|
||||||
@@ -850,10 +808,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
state->lastsynctype = 25;
|
state->lastsynctype = 25;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (25);
|
return (25);
|
||||||
}
|
}
|
||||||
if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
|
if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
|
||||||
@@ -892,20 +846,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
//state->firstframe = 1;
|
//state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 33; //33
|
state->lastsynctype = 33; //33
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (33); //33
|
return (33); //33
|
||||||
}
|
}
|
||||||
else //inverted MS voice frame
|
else //inverted MS voice frame
|
||||||
{
|
{
|
||||||
sprintf(state->ftype, "DMR MS");
|
sprintf(state->ftype, "DMR MS");
|
||||||
state->lastsynctype = 32;
|
state->lastsynctype = 32;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (32);
|
return (32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -932,10 +878,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
//state->firstframe = 1;
|
//state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 34;
|
state->lastsynctype = 34;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (34);
|
return (34);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -961,20 +903,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
//state->firstframe = 1;
|
//state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 32;
|
state->lastsynctype = 32;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (32);
|
return (32);
|
||||||
}
|
}
|
||||||
else //inverted MS data frame
|
else //inverted MS data frame
|
||||||
{
|
{
|
||||||
sprintf(state->ftype, "DMR MS");
|
sprintf(state->ftype, "DMR MS");
|
||||||
state->lastsynctype = 33;
|
state->lastsynctype = 33;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (33);
|
return (33);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -997,10 +931,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 10;
|
state->lastsynctype = 10;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (10);
|
return (10);
|
||||||
}
|
}
|
||||||
@@ -1017,10 +947,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->firstframe = 1;
|
state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 11;
|
state->lastsynctype = 11;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (11); //11
|
return (11); //11
|
||||||
}
|
}
|
||||||
@@ -1042,10 +968,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 33;
|
state->lastsynctype = 33;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (33);
|
return (33);
|
||||||
}
|
}
|
||||||
@@ -1062,10 +984,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->firstframe = 1;
|
state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 32;
|
state->lastsynctype = 32;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (32);
|
return (32);
|
||||||
}
|
}
|
||||||
@@ -1087,10 +1005,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 33;
|
state->lastsynctype = 33;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (33);
|
return (33);
|
||||||
}
|
}
|
||||||
@@ -1107,10 +1021,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->firstframe = 1;
|
state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 32;
|
state->lastsynctype = 32;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (32);
|
return (32);
|
||||||
}
|
}
|
||||||
@@ -1136,10 +1046,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->firstframe = 1;
|
state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 12;
|
state->lastsynctype = 12;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (12);
|
return (12);
|
||||||
}
|
}
|
||||||
@@ -1153,10 +1059,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 13;
|
state->lastsynctype = 13;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (13);
|
return (13);
|
||||||
}
|
}
|
||||||
@@ -1182,10 +1084,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->firstframe = 1;
|
state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 32;
|
state->lastsynctype = 32;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (32); //treat Direct Mode same as MS mode for now
|
return (32); //treat Direct Mode same as MS mode for now
|
||||||
}
|
}
|
||||||
@@ -1222,10 +1120,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->firstframe = 1;
|
state->firstframe = 1;
|
||||||
}
|
}
|
||||||
state->lastsynctype = 32;
|
state->lastsynctype = 32;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (32);
|
return (32);
|
||||||
}
|
}
|
||||||
@@ -1238,10 +1132,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 33;
|
state->lastsynctype = 33;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
return (33);
|
return (33);
|
||||||
}
|
}
|
||||||
@@ -1319,11 +1209,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
printFrameSync (opts, state, "+D-STAR ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "+D-STAR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 6;
|
state->lastsynctype = 6;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (6);
|
return (6);
|
||||||
}
|
}
|
||||||
if (strcmp (synctest, INV_DSTAR_SYNC) == 0)
|
if (strcmp (synctest, INV_DSTAR_SYNC) == 0)
|
||||||
@@ -1338,11 +1223,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
printFrameSync (opts, state, "-D-STAR ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "-D-STAR ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 7;
|
state->lastsynctype = 7;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (7);
|
return (7);
|
||||||
}
|
}
|
||||||
if (strcmp (synctest, DSTAR_HD) == 0)
|
if (strcmp (synctest, DSTAR_HD) == 0)
|
||||||
@@ -1357,11 +1237,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
printFrameSync (opts, state, "+D-STAR_HD ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "+D-STAR_HD ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 18;
|
state->lastsynctype = 18;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (18);
|
return (18);
|
||||||
}
|
}
|
||||||
if (strcmp (synctest, INV_DSTAR_HD) == 0)
|
if (strcmp (synctest, INV_DSTAR_HD) == 0)
|
||||||
@@ -1376,172 +1251,31 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
printFrameSync (opts, state, "-D-STAR_HD ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "-D-STAR_HD ", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 19;
|
state->lastsynctype = 19;
|
||||||
if ( opts->monitor_input_audio == 1)
|
|
||||||
{
|
|
||||||
|
|
||||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
|
||||||
}
|
|
||||||
return (19);
|
return (19);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NXDNOLDSYNC //Use FSW vs strncmperr method
|
//NXDN
|
||||||
|
|
||||||
//NXDN FSW sync and handling - moved to very bottom of sync stack for falsing sanity
|
|
||||||
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
||||||
{
|
{
|
||||||
strncpy (synctest10, (synctest_p - 9), 10); //FSW only
|
strncpy (synctest10, (synctest_p - 9), 10); //FSW only
|
||||||
strncpy (synctest19, (synctest_p - 18), 19); //Preamble + FSW
|
|
||||||
|
|
||||||
//Preamble plus FSW, proceed right away
|
|
||||||
if ( (strncmperr (synctest19, NXDN_PANDFSW, 19, 1) == 0) )
|
|
||||||
{
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
state->lastsynctype = 28;
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
// if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
|
||||||
// fprintf (stderr, " %s ", synctest19);
|
|
||||||
return (28);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (strncmperr (synctest19, INV_NXDN_PANDFSW, 19, 1) == 0) )
|
|
||||||
{
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
state->lastsynctype = 29;
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
// if (opts->payload == 1) fprintf (stderr, "PANDF ");
|
|
||||||
// fprintf (stderr, " %s ", synctest19);
|
|
||||||
return (29);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (strncmperr (synctest10, NXDN_FSW, 10, 1) == 0) )
|
|
||||||
{
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
|
|
||||||
if (state->lastsynctype == 28)
|
|
||||||
{
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
// if (opts->payload == 1) fprintf (stderr, "FSW ");
|
|
||||||
// fprintf (stderr, " %s ", synctest10);
|
|
||||||
return (28);
|
|
||||||
}
|
|
||||||
state->lastsynctype = 28; //need two consecutive patterns to continue
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( (strncmperr (synctest10, INV_NXDN_FSW, 10, 1) == 0) )
|
|
||||||
{
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
|
|
||||||
if (state->lastsynctype == 29)
|
|
||||||
{
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
// if (opts->payload == 1) fprintf (stderr, "FSW ");
|
|
||||||
// fprintf (stderr, " %s ", synctest10);
|
|
||||||
return (29);
|
|
||||||
}
|
|
||||||
state->lastsynctype = 29; //need two consecutive patterns to continue
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else //use Current FSW Pattern
|
|
||||||
|
|
||||||
//NXDN FSW sync and handling - using more exact frame sync values
|
|
||||||
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
|
||||||
{
|
|
||||||
strncpy (synctest10, (synctest_p - 9), 10); //FSW only
|
|
||||||
strncpy (synctest19, (synctest_p - 18), 19); //Preamble + FSW
|
|
||||||
|
|
||||||
//Using Hard Coded Sync Strings with variations for the areas where the symbol
|
|
||||||
//error will occur due to the demodulation issues internally
|
|
||||||
|
|
||||||
//Disabling the Preamble+FSW version for now
|
|
||||||
//its nearly impossible to catch it
|
|
||||||
|
|
||||||
//Preamble plus FSW, proceed right away
|
|
||||||
// if (
|
|
||||||
|
|
||||||
// (strcmp (synctest19, "3131133313131331131") == 0 )
|
|
||||||
// || (strcmp (synctest19, "3131133313331331131") == 0 )
|
|
||||||
// || (strcmp (synctest19, "3131133313131331111") == 0 )
|
|
||||||
// || (strcmp (synctest19, "3131133313331331111") == 0 )
|
|
||||||
|
|
||||||
// )
|
|
||||||
// {
|
|
||||||
// //state->carrier = 1;
|
|
||||||
// state->offset = synctest_pos;
|
|
||||||
// state->max = ((state->max) + lmax) / 2;
|
|
||||||
// state->min = ((state->min) + lmin) / 2;
|
|
||||||
// state->lastsynctype = 28;
|
|
||||||
// state->last_cc_sync_time = time(NULL);
|
|
||||||
|
|
||||||
// // if (opts->payload == 1)
|
|
||||||
// // fprintf (stderr, "\n +PANDF ");
|
|
||||||
// // if (opts->payload == 1)
|
|
||||||
// // fprintf (stderr, " %s \n", synctest19);
|
|
||||||
// return (28);
|
|
||||||
// }
|
|
||||||
// else if (
|
|
||||||
|
|
||||||
// (strcmp (synctest19, "1313311133131331131") == 0 )
|
|
||||||
// || (strcmp (synctest19, "1313311133331331131") == 0 )
|
|
||||||
// || (strcmp (synctest19, "1313311133131331111") == 0 )
|
|
||||||
// || (strcmp (synctest19, "1313311133331331111") == 0 )
|
|
||||||
|
|
||||||
// )
|
|
||||||
// {
|
|
||||||
// // state->carrier = 1;
|
|
||||||
// state->carrier = 1;
|
|
||||||
// state->offset = synctest_pos;
|
|
||||||
// state->max = ((state->max) + lmax) / 2;
|
|
||||||
// state->min = ((state->min) + lmin) / 2;
|
|
||||||
// state->lastsynctype = 29;
|
|
||||||
// state->last_cc_sync_time = time(NULL);
|
|
||||||
|
|
||||||
// // if (opts->payload == 1)
|
|
||||||
// // fprintf (stderr, "\n -PANDF ");
|
|
||||||
// // if (opts->payload == 1)
|
|
||||||
// // fprintf (stderr, " %s \n", synctest19);
|
|
||||||
// return (29);
|
|
||||||
// }
|
|
||||||
// else if (
|
|
||||||
if (
|
if (
|
||||||
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|
||||||
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|
||||||
|| (strcmp (synctest10, "3131331111") == 0 )
|
|| (strcmp (synctest10, "3131331111") == 0 )
|
||||||
|| (strcmp (synctest10, "3331331111") == 0 )
|
|| (strcmp (synctest10, "3331331111") == 0 )
|
||||||
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
|
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
// state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
state->offset = synctest_pos;
|
||||||
state->max = ((state->max) + lmax) / 2;
|
state->max = ((state->max) + lmax) / 2;
|
||||||
state->min = ((state->min) + lmin) / 2;
|
state->min = ((state->min) + lmin) / 2;
|
||||||
// state->last_cc_sync_time = time(NULL);
|
|
||||||
|
|
||||||
if (state->lastsynctype == 28)
|
if (state->lastsynctype == 28)
|
||||||
{
|
{
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
// if (opts->payload == 1)
|
|
||||||
// fprintf (stderr, "\n +FSW ");
|
|
||||||
// if (opts->payload == 1)
|
|
||||||
// fprintf (stderr, " %s \n", synctest10);
|
|
||||||
return (28);
|
return (28);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 28;
|
state->lastsynctype = 28;
|
||||||
@@ -1549,36 +1283,27 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
else if (
|
else if (
|
||||||
|
|
||||||
(strcmp (synctest10, "1313113313") == 0 )
|
(strcmp (synctest10, "1313113313") == 0 )
|
||||||
|| (strcmp (synctest10, "1113113313") == 0 )
|
|| (strcmp (synctest10, "1113113313") == 0 )
|
||||||
|| (strcmp (synctest10, "1313113333") == 0 )
|
|| (strcmp (synctest10, "1313113333") == 0 )
|
||||||
|| (strcmp (synctest10, "1113113333") == 0 )
|
|| (strcmp (synctest10, "1113113333") == 0 )
|
||||||
|| (strcmp (synctest10, "1313133313") == 0 ) //
|
|| (strcmp (synctest10, "1313133313") == 0 )
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
// state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
state->offset = synctest_pos;
|
||||||
state->max = ((state->max) + lmax) / 2;
|
state->max = ((state->max) + lmax) / 2;
|
||||||
state->min = ((state->min) + lmin) / 2;
|
state->min = ((state->min) + lmin) / 2;
|
||||||
// state->last_cc_sync_time = time(NULL);
|
|
||||||
|
|
||||||
if (state->lastsynctype == 29)
|
if (state->lastsynctype == 29)
|
||||||
{
|
{
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
// if (opts->payload == 1)
|
|
||||||
// fprintf (stderr, "\n -FSW ");
|
|
||||||
// if (opts->payload == 1)
|
|
||||||
// fprintf (stderr, " %s \n", synctest10);
|
|
||||||
return (29);
|
return (29);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 29;
|
state->lastsynctype = 29;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //NXDN Sync Type Selection
|
|
||||||
|
|
||||||
//Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible
|
//Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible
|
||||||
#ifdef PVCONVENTIONAL
|
#ifdef PVCONVENTIONAL
|
||||||
if (opts->frame_provoice == 1)
|
if (opts->frame_provoice == 1)
|
||||||
|
|||||||
@@ -467,6 +467,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
state->m17_dst = 0;
|
state->m17_dst = 0;
|
||||||
state->m17_src = 0;
|
state->m17_src = 0;
|
||||||
|
state->m17_can = 0;
|
||||||
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
|
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
|
||||||
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
|
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
|
||||||
sprintf (state->m17_dst_str, "%s", "");
|
sprintf (state->m17_dst_str, "%s", "");
|
||||||
@@ -621,7 +622,7 @@ initOpts (dsd_opts * opts)
|
|||||||
opts->dmr_mute_encL = 1;
|
opts->dmr_mute_encL = 1;
|
||||||
opts->dmr_mute_encR = 1;
|
opts->dmr_mute_encR = 1;
|
||||||
|
|
||||||
opts->monitor_input_audio = 0;
|
opts->monitor_input_audio = 0; //enable with -8
|
||||||
|
|
||||||
opts->inverted_p2 = 0;
|
opts->inverted_p2 = 0;
|
||||||
opts->p2counter = 0;
|
opts->p2counter = 0;
|
||||||
@@ -715,6 +716,11 @@ initState (dsd_state * state)
|
|||||||
//Upsampled Audio Smoothing
|
//Upsampled Audio Smoothing
|
||||||
state->audio_smoothing = 0;
|
state->audio_smoothing = 0;
|
||||||
|
|
||||||
|
//analog/raw signal audio buffers
|
||||||
|
state->analog_sample_counter = 0; //when it reaches 960, then dump the raw/analog audio signal and reset
|
||||||
|
memset (state->analog_out, 0, sizeof(state->analog_out) );
|
||||||
|
//
|
||||||
|
|
||||||
state->audio_out_buf = malloc (sizeof (short) * 1000000);
|
state->audio_out_buf = malloc (sizeof (short) * 1000000);
|
||||||
state->audio_out_bufR = malloc (sizeof (short) * 1000000);
|
state->audio_out_bufR = malloc (sizeof (short) * 1000000);
|
||||||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||||
@@ -1064,6 +1070,7 @@ initState (dsd_state * state)
|
|||||||
|
|
||||||
state->m17_dst = 0;
|
state->m17_dst = 0;
|
||||||
state->m17_src = 0;
|
state->m17_src = 0;
|
||||||
|
state->m17_can = 0;
|
||||||
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
|
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
|
||||||
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
|
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
|
||||||
sprintf (state->m17_dst_str, "%s", "");
|
sprintf (state->m17_dst_str, "%s", "");
|
||||||
@@ -1129,6 +1136,8 @@ usage ()
|
|||||||
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
|
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
|
||||||
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
|
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
|
||||||
printf (" -w <file> Output synthesized speech to a .wav file, legacy auto modes only.\n");
|
printf (" -w <file> Output synthesized speech to a .wav file, legacy auto modes only.\n");
|
||||||
|
printf (" -8 Enable Experimental Source Audio Monitor (OSS at 48k1 and Pulse Audio)\n");
|
||||||
|
printf (" (Its recommended to use Squelch in SDR++ or GQRX, etc, if monitoring mixed analog/digital)\n");
|
||||||
printf (" -P Enable Per Call WAV file saving in XDMA and NXDN decoding classes\n");
|
printf (" -P Enable Per Call WAV file saving in XDMA and NXDN decoding classes\n");
|
||||||
printf (" (Per Call can only be used in Ncurses Terminal!)\n");
|
printf (" (Per Call can only be used in Ncurses Terminal!)\n");
|
||||||
printf (" (Running in console will use static wav files)\n");
|
printf (" (Running in console will use static wav files)\n");
|
||||||
@@ -1201,8 +1210,6 @@ usage ()
|
|||||||
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
|
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
|
||||||
printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
|
printf (" -F Relax DMR RAS/CRC CSBK/DATA Pass/Fail\n");
|
||||||
printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n");
|
printf (" Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal\n");
|
||||||
printf (" -F Relax NXDN SACCH/FACCH/CAC/F2U CRC Pass/Fail\n");
|
|
||||||
printf (" Not recommended on NXDN, but can be bypassed if desired.\n");
|
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
|
printf (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
|
||||||
printf (" (NOTE: This used to be the 'K' option! \n");
|
printf (" (NOTE: This used to be the 'K' option! \n");
|
||||||
@@ -1230,9 +1237,6 @@ usage ()
|
|||||||
printf (" \n");
|
printf (" \n");
|
||||||
printf (" -3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n");
|
printf (" -3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n");
|
||||||
printf (" Note: Disable this if false positives on Voice ENC occur. \n");
|
printf (" Note: Disable this if false positives on Voice ENC occur. \n");
|
||||||
// printf (" -3 Enable DMR Late Entry Encryption Identifiers (VC6 Single Burst) \n");
|
|
||||||
// printf (" Note: This is experimental and may produce false positives depending on system type, notably TXI. \n");
|
|
||||||
// printf (" Use -0 or -4 options above instead if needed. \n");
|
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf (" Trunking Options:\n");
|
printf (" Trunking Options:\n");
|
||||||
printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n");
|
printf (" -C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C) \n");
|
||||||
@@ -1254,6 +1258,7 @@ usage ()
|
|||||||
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 7000; NXDN96: 9000; DMR - 7000; EDACS/PV - 12500;\n");
|
printf (" P25 - 7000-12000; P25 (QPSK) - 12000; NXDN48 - 7000; NXDN96: 9000; DMR - 7000; EDACS/PV - 12500;\n");
|
||||||
printf (" May vary based on system stregnth, etc.\n");
|
printf (" May vary based on system stregnth, etc.\n");
|
||||||
printf (" -t <secs> Set Trunking or Fast Scan VC/sync loss hangtime in seconds. (default = 1 second)\n");
|
printf (" -t <secs> Set Trunking or Fast Scan VC/sync loss hangtime in seconds. (default = 1 second)\n");
|
||||||
|
printf (" -9 Force Enable EDACS Standard or Networked Mode on Systems without a netcmd (temp fix) \n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf (" Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
|
printf (" Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans\n");
|
||||||
printf (" Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
printf (" Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans\n");
|
||||||
@@ -1300,6 +1305,12 @@ if (opts->audio_in_type == 1)
|
|||||||
|
|
||||||
open_rtlsdr_stream(opts);
|
open_rtlsdr_stream(opts);
|
||||||
opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again
|
opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again
|
||||||
|
#ifdef __arm__
|
||||||
|
fprintf (stderr, "WARNING: RMS Function is Disabled on ARM Devices (Raspberry Pi) due to High CPU use. \n");
|
||||||
|
fprintf (stderr, "RMS/Squelch Functionality for NXDN, dPMR, EDACS Analog, M17 and Raw Audio Monitor are unavailable and these modes will not function properly. \n");
|
||||||
|
if (opts->monitor_input_audio == 1) opts->monitor_input_audio = 0;
|
||||||
|
opts->rtl_squelch_level = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1319,6 +1330,13 @@ if (opts->audio_out_type == 0)
|
|||||||
openPulseOutput(opts);
|
openPulseOutput(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AERO_BUILD
|
||||||
|
//TODO: More Random Cygwin Related M17 Bugs to sort out
|
||||||
|
if(opts->frame_m17 == 1 && opts->audio_in_type != 0)
|
||||||
|
for (int i = 0; i < 960; i++) getSymbol(opts, state, 1); //I think this is actually just framesync being a pain
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1450,12 +1468,16 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AERO_BUILD
|
#ifdef AERO_BUILD
|
||||||
fprintf (stderr, "Build Version: v2.1b (20230714)\n");
|
fprintf (stderr, "Build Version: v2.1b (20230901)\n");
|
||||||
#else
|
#else
|
||||||
fprintf (stderr, "Build Version: %s \n", GIT_TAG);
|
fprintf (stderr, "Build Version: %s \n", GIT_TAG);
|
||||||
#endif
|
#endif
|
||||||
fprintf (stderr,"MBElib Version: %s\n", versionstr);
|
fprintf (stderr,"MBElib Version: %s\n", versionstr);
|
||||||
|
|
||||||
|
#ifdef USE_CODEC2
|
||||||
|
fprintf (stderr,"CODEC2 Support Enabled\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
initOpts (&opts);
|
initOpts (&opts);
|
||||||
initState (&state);
|
initState (&state);
|
||||||
|
|
||||||
@@ -1463,7 +1485,7 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
exitflag = 0;
|
exitflag = 0;
|
||||||
|
|
||||||
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1)
|
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK:b:H:X:NQ:WrlZTF01:2:345:6:7:89Ek:")) != -1)
|
||||||
{
|
{
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
switch (c)
|
switch (c)
|
||||||
@@ -1485,6 +1507,17 @@ main (int argc, char **argv)
|
|||||||
//NOTE: The 'K' option for single BP key has been swapped to 'b'
|
//NOTE: The 'K' option for single BP key has been swapped to 'b'
|
||||||
//'K' is now used for hexidecimal key.csv imports
|
//'K' is now used for hexidecimal key.csv imports
|
||||||
|
|
||||||
|
case '9': //This is a temporary fix for RR issue until a permanent fix can be found
|
||||||
|
state.ea_mode = 0;
|
||||||
|
fprintf (stderr,"Force Enabling EDACS Standard/Networked Mode Mode\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
//experimental audio monitoring
|
||||||
|
case '8':
|
||||||
|
opts.monitor_input_audio = 1;
|
||||||
|
fprintf (stderr,"Experimental Raw Analog Source Monitoring Enabled\n");
|
||||||
|
break;
|
||||||
|
|
||||||
//rc4 enforcement on DMR (due to missing the PI header)
|
//rc4 enforcement on DMR (due to missing the PI header)
|
||||||
case '0':
|
case '0':
|
||||||
state.M = 0x21;
|
state.M = 0x21;
|
||||||
@@ -1899,6 +1932,7 @@ main (int argc, char **argv)
|
|||||||
sprintf (opts.output_name, "EDACS/PV");
|
sprintf (opts.output_name, "EDACS/PV");
|
||||||
fprintf (stderr,"Setting symbol rate to 9600 / second\n");
|
fprintf (stderr,"Setting symbol rate to 9600 / second\n");
|
||||||
fprintf (stderr,"Decoding only ProVoice frames.\n");
|
fprintf (stderr,"Decoding only ProVoice frames.\n");
|
||||||
|
fprintf (stderr,"EDACS Analog Voice Channels are Experimental.\n");
|
||||||
//rtl specific tweaks
|
//rtl specific tweaks
|
||||||
opts.rtl_bandwidth = 24;
|
opts.rtl_bandwidth = 24;
|
||||||
// opts.rtl_gain_value = 36;
|
// opts.rtl_gain_value = 36;
|
||||||
@@ -2530,9 +2564,15 @@ main (int argc, char **argv)
|
|||||||
opts.audio_in_type = 5; //5 will become OSS input type
|
opts.audio_in_type = 5; //5 will become OSS input type
|
||||||
}
|
}
|
||||||
|
|
||||||
//Codec2 only running at 8k output currently, need to match for OSS
|
//OSS cannot open different rate/channel configs on /dev/dsp on real hardware and in Cygwin
|
||||||
|
//So, in Aero builds, we need to keep the rate the same but upscale Codec2
|
||||||
|
//padsp opens a virtual output, so mixing and matching rates/channels is possible there
|
||||||
|
#ifdef AERO_BUILD
|
||||||
|
// speed = 48000;
|
||||||
|
#else
|
||||||
if (opts.frame_m17 == 1)
|
if (opts.frame_m17 == 1)
|
||||||
speed = 8000;
|
speed = 8000;
|
||||||
|
#endif
|
||||||
|
|
||||||
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
|
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
state->dropL += 7;
|
state->dropL += 7;
|
||||||
|
|
||||||
short z = 0;
|
short z = 0;
|
||||||
for (short p = 0; p < 6; p++)
|
for (short p = 0; p <= 6; p++)
|
||||||
{
|
{
|
||||||
//convert bytes back to bits and load into ambe_d array.
|
//convert bytes back to bits and load into ambe_d array.
|
||||||
short b = 0; //reset b to use again
|
short b = 0; //reset b to use again
|
||||||
@@ -660,7 +660,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
state->dropL += 7;
|
state->dropL += 7;
|
||||||
|
|
||||||
short z = 0;
|
short z = 0;
|
||||||
for (short p = 0; p < 6; p++)
|
for (short p = 0; p <= 6; p++)
|
||||||
{
|
{
|
||||||
//convert bytes back to bits and load into ambe_d array.
|
//convert bytes back to bits and load into ambe_d array.
|
||||||
short b = 0; //reset b to use again
|
short b = 0; //reset b to use again
|
||||||
@@ -867,7 +867,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
state->dropR += 7;
|
state->dropR += 7;
|
||||||
|
|
||||||
short z = 0;
|
short z = 0;
|
||||||
for (short p = 0; p < 6; p++)
|
for (short p = 0; p <= 6; p++)
|
||||||
{
|
{
|
||||||
//convert bytes back to bits and load into ambe_d array.
|
//convert bytes back to bits and load into ambe_d array.
|
||||||
short b = 0; //reset b to use again
|
short b = 0; //reset b to use again
|
||||||
@@ -945,7 +945,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|||||||
state->dropR += 7;
|
state->dropR += 7;
|
||||||
|
|
||||||
short z = 0;
|
short z = 0;
|
||||||
for (short p = 0; p < 6; p++)
|
for (short p = 0; p <= 6; p++)
|
||||||
{
|
{
|
||||||
//convert bytes back to bits and load into ambe_d array.
|
//convert bytes back to bits and load into ambe_d array.
|
||||||
short b = 0; //reset b to use again
|
short b = 0; //reset b to use again
|
||||||
|
|||||||
@@ -248,7 +248,11 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
char * getDateN(void) {
|
char * getDateN(void) {
|
||||||
char datename[80]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
|
#ifdef AERO_BUILD
|
||||||
|
char datename[80];
|
||||||
|
#else
|
||||||
|
char datename[99];
|
||||||
|
#endif
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
time_t t;
|
time_t t;
|
||||||
@@ -274,9 +278,9 @@ char * getTimeN(void) //get pretty hh:mm:ss timestamp
|
|||||||
|
|
||||||
return curr;
|
return curr;
|
||||||
}
|
}
|
||||||
|
//this version is broken now in Cygwin with the 80 value, reverted back
|
||||||
char * getDateC(time_t t) {
|
char * getDateC(time_t t) {
|
||||||
char datename[99]; //Ubuntu 32-bit, use 80; everything else, use 99
|
char datename[99];
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
|
|
||||||
@@ -2225,7 +2229,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
if (opts->ncurses_compact == 1)
|
if (opts->ncurses_compact == 1)
|
||||||
{
|
{
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
printw ("------------------------------------------------------------------------------\n");
|
||||||
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.1b (20230714)");
|
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.1b (20230901)");
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
printw ("------------------------------------------------------------------------------\n");
|
||||||
}
|
}
|
||||||
#elif LIMAZULUTWEAKS
|
#elif LIMAZULUTWEAKS
|
||||||
@@ -2235,13 +2239,6 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
printw ("| Digital Speech Decoder: LimaZulu Edition VI: Return of the Zulu \n");
|
printw ("| Digital Speech Decoder: LimaZulu Edition VI: Return of the Zulu \n");
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
printw ("------------------------------------------------------------------------------\n");
|
||||||
}
|
}
|
||||||
#elif ZDEV_BUILD
|
|
||||||
if (opts->ncurses_compact == 1)
|
|
||||||
{
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
printw ("| Digital Speech Decoder: Florida Man Edition - zDEV %s \n", GIT_TAG);
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (opts->ncurses_compact == 1)
|
if (opts->ncurses_compact == 1)
|
||||||
{
|
{
|
||||||
@@ -2258,13 +2255,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
printw("%s", FM_bannerN[i]);
|
printw("%s", FM_bannerN[i]);
|
||||||
if (i == 1) printw (" ESC to Menu");
|
if (i == 1) printw (" ESC to Menu");
|
||||||
if (i == 2) printw (" 'q' to Quit ");
|
if (i == 2) printw (" 'q' to Quit ");
|
||||||
if (i == 4) printw (" MBElib %s", versionstr);
|
if (i == 4 && opts->frame_m17 == 0) printw (" MBElib %s", versionstr);
|
||||||
|
#ifdef USE_CODEC2
|
||||||
|
if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2");
|
||||||
|
#endif
|
||||||
#ifdef AERO_BUILD
|
#ifdef AERO_BUILD
|
||||||
if (i == 5) printw (" %s ", "Aero Build");
|
if (i == 5) printw (" %s ", "Aero Build");
|
||||||
if (i == 6) printw (" v2.1b (20230714) \n");
|
if (i == 6) printw (" v2.1b (20230901) \n");
|
||||||
#elif ZDEV_BUILD
|
|
||||||
if (i == 5) printw (" %s ", "zDEV Build");
|
|
||||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
|
||||||
#else
|
#else
|
||||||
if (i == 5) printw (" %s ", "Main Build");
|
if (i == 5) printw (" %s ", "Main Build");
|
||||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||||
@@ -2315,7 +2312,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
printw (" Gain: %idB;", opts->rtl_gain_value);
|
printw (" Gain: %idB;", opts->rtl_gain_value);
|
||||||
printw (" PPM: %i;", opts->rtlsdr_ppm_error);
|
printw (" PPM: %i;", opts->rtlsdr_ppm_error);
|
||||||
printw (" SQ: %i;", opts->rtl_squelch_level);
|
printw (" SQ: %i;", opts->rtl_squelch_level);
|
||||||
printw (" RMS: %04i;", opts->rtl_rms);
|
printw (" RMS: %04li;", opts->rtl_rms);
|
||||||
printw (" BW: %i kHz;", opts->rtl_bandwidth);
|
printw (" BW: %i kHz;", opts->rtl_bandwidth);
|
||||||
printw (" FRQ: %i;", opts->rtlsdr_center_freq);
|
printw (" FRQ: %i;", opts->rtlsdr_center_freq);
|
||||||
if (opts->rtl_udp_port != 0) printw ("\n| External Tuning on UDP Port: %i", opts->rtl_udp_port);
|
if (opts->rtl_udp_port != 0) printw ("\n| External Tuning on UDP Port: %i", opts->rtl_udp_port);
|
||||||
@@ -2327,15 +2324,22 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
||||||
printw (" \n");
|
printw (" \n");
|
||||||
}
|
}
|
||||||
|
if ( opts->audio_out_type == 0 && (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) )
|
||||||
|
{
|
||||||
|
printw ("| Pulse Audio Output: %i kHz; %i Ch; RMS: %04ld Analog", opts->pulse_raw_rate_out/1000, opts->pulse_raw_out_channels, opts->rtl_rms);
|
||||||
|
printw (" \n");
|
||||||
|
}
|
||||||
if (opts->audio_out_type == 5)
|
if (opts->audio_out_type == 5)
|
||||||
{
|
{
|
||||||
printw ("| OSS Audio Output: [%2i] kHz [1] Channel", SAMPLE_RATE_OUT/1000);
|
printw ("| OSS Audio Output: [%2i] kHz [1] Channel", SAMPLE_RATE_OUT/1000);
|
||||||
|
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
|
||||||
|
printw (" - Analog RMS: %04ld ", opts->rtl_rms);
|
||||||
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
if (state->audio_smoothing == 1) printw (" - Smoothing On");
|
||||||
printw (" \n");
|
printw (" \n");
|
||||||
}
|
}
|
||||||
if (opts->monitor_input_audio == 1)
|
if (opts->monitor_input_audio == 1)
|
||||||
{
|
{
|
||||||
printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected\n");
|
printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected (WIP)\n");
|
||||||
}
|
}
|
||||||
if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0)
|
if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0)
|
||||||
{
|
{
|
||||||
@@ -2481,14 +2485,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
|
|
||||||
printw ("| ");
|
printw ("| ");
|
||||||
printw ("M17 - ");
|
printw ("M17: ");
|
||||||
|
|
||||||
//insert data type and frame information
|
//insert data type and frame information
|
||||||
if (state->m17_str_dt == 0) printw("Reserved");
|
if (state->m17_str_dt == 0) printw("Reserved");
|
||||||
if (state->m17_str_dt == 1) printw("Data ");
|
if (state->m17_str_dt == 1) printw("Data ");
|
||||||
if (state->m17_str_dt == 2) printw("Voice (3200) ");
|
if (state->m17_str_dt == 2) printw("Voice (3200) ");
|
||||||
if (state->m17_str_dt == 3) printw("Voice (1600) + Data");
|
if (state->m17_str_dt == 3) printw("Voice (1600) + Data");
|
||||||
printw (" ");
|
|
||||||
|
|
||||||
printw ("\n");
|
printw ("\n");
|
||||||
printw ("| ");
|
printw ("| ");
|
||||||
@@ -2499,11 +2502,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
else if (state->m17_dst != 0 && state->m17_dst >= 0xEE6B28000000)
|
else if (state->m17_dst != 0 && state->m17_dst >= 0xEE6B28000000)
|
||||||
printw("RESERVED (%012llx) ", state->m17_dst);
|
printw("RESERVED (%012llx) ", state->m17_dst);
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// for (i = 0; i < 9; i++)
|
|
||||||
// printw ("%c", state->m17_dst_csd[i]);
|
|
||||||
printw("%s", state->m17_dst_str);
|
printw("%s", state->m17_dst_str);
|
||||||
}
|
|
||||||
|
|
||||||
printw ("\n");
|
printw ("\n");
|
||||||
printw ("| ");
|
printw ("| ");
|
||||||
@@ -2512,23 +2511,25 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->m17_src != 0 && state->m17_src >= 0xEE6B28000000)
|
if (state->m17_src != 0 && state->m17_src >= 0xEE6B28000000)
|
||||||
printw("RESERVED (%012llx)", state->m17_src);
|
printw("RESERVED (%012llx)", state->m17_src);
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// for (i = 0; i < 9; i++)
|
|
||||||
// printw ("%c", state->m17_src_csd[i]);
|
|
||||||
printw("%s", state->m17_src_str);
|
printw("%s", state->m17_src_str);
|
||||||
}
|
|
||||||
|
|
||||||
|
printw ("\n");
|
||||||
|
printw ("| ");
|
||||||
|
|
||||||
|
printw ("CAN: %02d ", state->m17_can);
|
||||||
|
|
||||||
printw ("\n");
|
printw ("\n");
|
||||||
printw ("| ");
|
printw ("| ");
|
||||||
|
|
||||||
|
|
||||||
//fill in any extra info, like Meta (IV, etc)
|
//fill in any extra info, like Meta (IV, etc)
|
||||||
if (state->m17_enc == 2)
|
if (state->m17_enc == 1)
|
||||||
{
|
{
|
||||||
printw (" Scrambler - Type: %d", state->m17_enc_st);
|
printw (" Scrambler - Type: %d", state->m17_enc_st);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->m17_enc == 1)
|
if (state->m17_enc == 2)
|
||||||
{
|
{
|
||||||
printw (" AES-CTR - IV: ");
|
printw (" AES-CTR - IV: ");
|
||||||
//display packed meta as IV
|
//display packed meta as IV
|
||||||
|
|||||||
@@ -17,6 +17,29 @@
|
|||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
|
long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as len
|
||||||
|
{
|
||||||
|
|
||||||
|
int i;
|
||||||
|
long int rms;
|
||||||
|
long p, t, s;
|
||||||
|
double dc, err;
|
||||||
|
|
||||||
|
p = t = 0L;
|
||||||
|
for (i=0; i<len; i+=step) {
|
||||||
|
s = (long)samples[i];
|
||||||
|
t += s;
|
||||||
|
p += s * s;
|
||||||
|
}
|
||||||
|
/* correct for dc offset in squares */
|
||||||
|
dc = (double)(t*step) / (double)len;
|
||||||
|
err = t * 2 * dc - dc * dc * len;
|
||||||
|
|
||||||
|
rms = (long int)sqrt((p-err) / len);
|
||||||
|
if (rms < 0) rms = 150;
|
||||||
|
return rms;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||||
{
|
{
|
||||||
@@ -129,14 +152,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
else if (opts->audio_in_type == 3)
|
else if (opts->audio_in_type == 3)
|
||||||
{
|
{
|
||||||
#ifdef USE_RTLSDR
|
#ifdef USE_RTLSDR
|
||||||
// TODO: need to read demodulated stream here
|
// Read demodulated stream here
|
||||||
// get_rtlsdr_sample(&sample);
|
|
||||||
get_rtlsdr_sample(&sample, opts, state);
|
get_rtlsdr_sample(&sample, opts, state);
|
||||||
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767)
|
|
||||||
{
|
|
||||||
state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here?
|
|
||||||
pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL);
|
|
||||||
}
|
|
||||||
opts->rtl_rms = rtl_return_rms();
|
opts->rtl_rms = rtl_return_rms();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -247,6 +264,56 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Source Audio Monitoring
|
||||||
|
if (have_sync == 0 && opts->monitor_input_audio == 1)
|
||||||
|
{
|
||||||
|
//sanity check to prevent an overflow
|
||||||
|
if (state->analog_sample_counter > 959)
|
||||||
|
state->analog_sample_counter = 959;
|
||||||
|
|
||||||
|
state->analog_out[state->analog_sample_counter++] = sample;
|
||||||
|
|
||||||
|
if (state->analog_sample_counter == 960)
|
||||||
|
{
|
||||||
|
//get an rms value if not using the rtl built in version
|
||||||
|
if (opts->audio_in_type != 3)
|
||||||
|
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// opts->rtl_rms = 101;
|
||||||
|
|
||||||
|
//make it a little quieter
|
||||||
|
for (int x = 0; x < 960; x++)
|
||||||
|
state->analog_out[x] /= 4;
|
||||||
|
|
||||||
|
//seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise
|
||||||
|
if ( opts->rtl_rms > opts->rtl_squelch_level )
|
||||||
|
{
|
||||||
|
if (opts->audio_out_type == 0)
|
||||||
|
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
|
||||||
|
|
||||||
|
//NOTE: Worked okay earlier in Cygwin, so should be fine
|
||||||
|
if (opts->audio_out_type == 5)
|
||||||
|
write (opts->audio_out_fd, state->analog_out, 960*2);
|
||||||
|
|
||||||
|
//test hold on scan/trunking
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
state->last_vc_sync_time = time(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||||
|
state->analog_sample_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_sync == 1 && opts->monitor_input_audio == 1)
|
||||||
|
{
|
||||||
|
//zero out and reset counter
|
||||||
|
memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||||
|
state->analog_sample_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (opts->use_cosine_filter)
|
if (opts->use_cosine_filter)
|
||||||
{
|
{
|
||||||
if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33
|
if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33
|
||||||
|
|||||||
305
src/edacs-fme.c
305
src/edacs-fme.c
@@ -14,12 +14,16 @@
|
|||||||
* 1994-7
|
* 1994-7
|
||||||
*
|
*
|
||||||
* LWVMOBILE
|
* LWVMOBILE
|
||||||
* 2022-10 Version EDACS-FM Florida Man Edition
|
* 2023-08 Version EDACS-FM Florida Man Edition
|
||||||
*-----------------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------------*/
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
char * getDateE(void) {
|
char * getDateE(void) {
|
||||||
char datename[99]; //might honestly just need a much smaller size, and not a larger one
|
#ifdef AERO_BUILD
|
||||||
|
char datename[80];
|
||||||
|
#else
|
||||||
|
char datename[99];
|
||||||
|
#endif
|
||||||
char * curr2;
|
char * curr2;
|
||||||
struct tm * to;
|
struct tm * to;
|
||||||
time_t t;
|
time_t t;
|
||||||
@@ -45,6 +49,191 @@ char * getTimeE(void) //get pretty hh:mm:ss timestamp
|
|||||||
return curr;
|
return curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void openWavOutFile48k (dsd_opts * opts, dsd_state * state)
|
||||||
|
{
|
||||||
|
|
||||||
|
SF_INFO info;
|
||||||
|
info.samplerate = 48000; //48k for analog output (has to match input)
|
||||||
|
info.channels = 1;
|
||||||
|
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||||
|
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info);
|
||||||
|
|
||||||
|
if (opts->wav_out_f == NULL)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//generic rms type function
|
||||||
|
long int gen_rms(short *samples, int len, int step)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i;
|
||||||
|
long int rms;
|
||||||
|
long p, t, s;
|
||||||
|
double dc, err;
|
||||||
|
|
||||||
|
p = t = 0L;
|
||||||
|
for (i=0; i<len; i+=step) {
|
||||||
|
s = (long)samples[i];
|
||||||
|
t += s;
|
||||||
|
p += s * s;
|
||||||
|
}
|
||||||
|
/* correct for dc offset in squares */
|
||||||
|
dc = (double)(t*step) / (double)len;
|
||||||
|
err = t * 2 * dc - dc * dc * len;
|
||||||
|
|
||||||
|
rms = (long int)sqrt((p-err) / len);
|
||||||
|
//make sure it doesnt' randomly feed us a large negative value (overflow?)
|
||||||
|
if (rms < 0) rms = 150; //could also consider returning 0 and making it return the last known good value instead
|
||||||
|
return rms;
|
||||||
|
}
|
||||||
|
|
||||||
|
//listening to and playing back analog audio
|
||||||
|
void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i;
|
||||||
|
short analog1[960];
|
||||||
|
short analog2[960];
|
||||||
|
short analog3[960];
|
||||||
|
short sample = 0;
|
||||||
|
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
state->last_vc_sync_time = time(NULL);
|
||||||
|
|
||||||
|
memset (analog1, 0, sizeof(analog1));
|
||||||
|
memset (analog2, 0, sizeof(analog2));
|
||||||
|
memset (analog3, 0, sizeof(analog3));
|
||||||
|
|
||||||
|
long int rms = opts->rtl_squelch_level + 1; //one more for the initial loop phase
|
||||||
|
long int sql = opts->rtl_squelch_level;
|
||||||
|
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
while (rms > sql) //!exitflag && -- no exitflag on this version
|
||||||
|
{
|
||||||
|
//this will only work on 48k/1 short output
|
||||||
|
if (opts->audio_in_type == 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||||
|
analog1[i] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||||
|
analog2[i] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||||
|
analog3[i] = sample;
|
||||||
|
}
|
||||||
|
//this rms will only work properly (for now) with squelch enabled in SDR++ or other
|
||||||
|
rms = gen_rms(analog3, 960, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TCP Input -- TODO: Error Handling if connection drops
|
||||||
|
if (opts->audio_in_type == 8)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
|
analog1[i] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
|
analog2[i] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
|
analog3[i] = sample;
|
||||||
|
}
|
||||||
|
//this rms will only work properly (for now) with squelch enabled in SDR++
|
||||||
|
rms = gen_rms(analog3, 960, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//RTL Input
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
if (opts->audio_in_type == 3)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
get_rtlsdr_sample(&sample, opts, state);
|
||||||
|
analog1[i] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
get_rtlsdr_sample(&sample, opts, state);
|
||||||
|
analog2[i] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 960; i++)
|
||||||
|
{
|
||||||
|
get_rtlsdr_sample(&sample, opts, state);
|
||||||
|
analog3[i] = sample;
|
||||||
|
}
|
||||||
|
//the rtl rms value works properly without needing a 'hard' squelch value
|
||||||
|
rms = rtl_return_rms();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (opts->audio_out_type == 0)
|
||||||
|
{
|
||||||
|
pa_simple_write(opts->pulse_raw_dev_out, analog1, 960*2, NULL);
|
||||||
|
pa_simple_write(opts->pulse_raw_dev_out, analog2, 960*2, NULL);
|
||||||
|
pa_simple_write(opts->pulse_raw_dev_out, analog3, 960*2, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->audio_out_type == 5)
|
||||||
|
{
|
||||||
|
write (opts->audio_out_fd, analog1, 960*2);
|
||||||
|
write (opts->audio_out_fd, analog2, 960*2);
|
||||||
|
write (opts->audio_out_fd, analog3, 960*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
opts->rtl_rms = rms;
|
||||||
|
|
||||||
|
|
||||||
|
printFrameSync (opts, state, " EDACS", 0, "A");
|
||||||
|
|
||||||
|
if (rms < sql) fprintf (stderr, "%s", KRED);
|
||||||
|
else fprintf (stderr, "%s", KGRN);
|
||||||
|
|
||||||
|
fprintf (stderr, " Analog RMS: %04ld SQL: %ld", rms, sql);
|
||||||
|
if (afs != 0)
|
||||||
|
fprintf (stderr, " AFS [0x%03X] [%02d-%03d] LCN [%02d]", afs, afs >> 7, afs & 0x7F, lcn);
|
||||||
|
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
if (rms > sql) fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
//Update Ncurses Terminal
|
||||||
|
if (opts->use_ncurses_terminal == 1)
|
||||||
|
ncursesPrinter(opts, state);
|
||||||
|
|
||||||
|
//WIP: Write Analog Samples to wav file, easy enough,
|
||||||
|
//but needs wav to be opened as 48k, or downsampled
|
||||||
|
//working on 48k version of openWavOutFile
|
||||||
|
if (opts->wav_out_f != NULL)
|
||||||
|
{
|
||||||
|
sf_write_short(opts->wav_out_f, analog1, 960);
|
||||||
|
sf_write_short(opts->wav_out_f, analog2, 960);
|
||||||
|
sf_write_short(opts->wav_out_f, analog3, 960);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void edacs(dsd_opts * opts, dsd_state * state)
|
void edacs(dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
//changed to ulli here for 32-bit cygwin (not sure if was an issue, but playing it safe)
|
//changed to ulli here for 32-bit cygwin (not sure if was an issue, but playing it safe)
|
||||||
@@ -64,7 +253,6 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
unsigned char command = 0xFF;
|
unsigned char command = 0xFF;
|
||||||
unsigned char mt1 = 0x1F;
|
unsigned char mt1 = 0x1F;
|
||||||
unsigned char mt2 = 0xF;
|
unsigned char mt2 = 0xF;
|
||||||
unsigned char mta = 0;
|
|
||||||
unsigned char lcn = 0;
|
unsigned char lcn = 0;
|
||||||
|
|
||||||
//commands; may not use these anymore
|
//commands; may not use these anymore
|
||||||
@@ -75,7 +263,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
state->edacs_vc_lcn = -1; //init on negative for ncurses and tuning
|
state->edacs_vc_lcn = -1; //init on negative for ncurses and tuning
|
||||||
|
|
||||||
int i, j;
|
int i;
|
||||||
int edacs_bit[241] = {0}; //zero out bit array and collect bits into it.
|
int edacs_bit[241] = {0}; //zero out bit array and collect bits into it.
|
||||||
|
|
||||||
for (i = 0; i < 240; i++) //288 bits every transmission minus 48 bit (24 dibit) sync pattern
|
for (i = 0; i < 240; i++) //288 bits every transmission minus 48 bit (24 dibit) sync pattern
|
||||||
@@ -124,32 +312,32 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
|
|
||||||
//ESK on/off detection, I honestly don't remember the logic for this anymore, but it works fine
|
//ESK on/off detection, I honestly don't remember the logic for this anymore, but it works fine
|
||||||
if ( (((fr_1t & 0xF000000000) >> 36) != 0xB) && (((fr_1t & 0xF000000000) >> 36) != 0x1) && (((fr_1t & 0xFF00000000) >> 32) != 0xF3) )
|
if ( (((fr_1t & 0xF000000000) >> 36) != 0xB) && (((fr_1t & 0xF000000000) >> 36) != 0x1) && (((fr_1t & 0xFF00000000) >> 32) != 0xF3) )
|
||||||
{
|
{
|
||||||
//experimenting with values here, not too high, and not too low
|
//experimenting with values here, not too high, and not too low
|
||||||
if ( (((fr_1t & 0xF000000000) >> 36) <= 0x8 ))
|
if ( (((fr_1t & 0xF000000000) >> 36) <= 0x8 ))
|
||||||
{
|
{
|
||||||
state->esk_mask = 0xA0;
|
state->esk_mask = 0xA0;
|
||||||
}
|
}
|
||||||
//ideal value would be 5, but some other values exist that don't allow it
|
//ideal value would be 5, but some other values exist that don't allow it
|
||||||
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
|
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
|
||||||
{
|
{
|
||||||
state->esk_mask = 0x0;
|
state->esk_mask = 0x0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Standard/Networked Auto Detection
|
//Standard/Networked Auto Detection
|
||||||
//if (command == netcmd) //netcmd is F3 Standard/Networked (I think)
|
//if (command == netcmd) //netcmd is F3 Standard/Networked (I think)
|
||||||
if ( (fr_1t >> 32 == netcmd) || (fr_1t >> 32 == (netcmd ^ 0xA0)) )
|
if ( (fr_1t >> 32 == netcmd) || (fr_1t >> 32 == (netcmd ^ 0xA0)) )
|
||||||
{
|
{
|
||||||
state->ea_mode = 0; //disable extended addressing mode
|
state->ea_mode = 0; //disable extended addressing mode
|
||||||
}
|
}
|
||||||
|
|
||||||
//EA Auto detection //peercmd is 0xF88 peer site relay 0xFF80000000 >> 28
|
//EA Auto detection //peercmd is 0xF88 peer site relay 0xFF80000000 >> 28
|
||||||
if (fr_1t >> 28 == peercmd || fr_1t >> 28 == (peercmd ^ 0xA00) )
|
if (fr_1t >> 28 == peercmd || fr_1t >> 28 == (peercmd ^ 0xA00) )
|
||||||
{
|
{
|
||||||
state->ea_mode = 1; //enable extended addressing mode
|
state->ea_mode = 1; //enable extended addressing mode
|
||||||
}
|
}
|
||||||
|
|
||||||
//Start Extended Addressing Mode
|
//Start Extended Addressing Mode
|
||||||
if (state->ea_mode == 1)
|
if (state->ea_mode == 1)
|
||||||
@@ -284,6 +472,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld TG %d SRC %d.wav", getDateE(), getTimeE(), state->edacs_site_id, group, source);
|
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld TG %d SRC %d.wav", getDateE(), getTimeE(), state->edacs_site_id, group, source);
|
||||||
openWavOutFile (opts, state);
|
openWavOutFile (opts, state);
|
||||||
|
// openWavOutFile48k (opts, state); //debug for testing analog wav only
|
||||||
}
|
}
|
||||||
|
|
||||||
//do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
|
//do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
|
||||||
@@ -293,7 +482,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
|
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
|
||||||
state->edacs_tuned_lcn = lcn;
|
state->edacs_tuned_lcn = lcn;
|
||||||
opts->p25_is_tuned = 1;
|
opts->p25_is_tuned = 1;
|
||||||
|
//debug testing (since I don't have EDACS standard w/ Analog nearby)
|
||||||
|
// edacs_analog(opts, state, group, lcn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->audio_in_type == 3) //rtl dongle
|
if (opts->audio_in_type == 3) //rtl dongle
|
||||||
@@ -302,6 +492,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||||
state->edacs_tuned_lcn = lcn;
|
state->edacs_tuned_lcn = lcn;
|
||||||
opts->p25_is_tuned = 1;
|
opts->p25_is_tuned = 1;
|
||||||
|
//debug testing (since I don't have EDACS standard w/ Analog nearby)
|
||||||
|
// edacs_analog(opts, state, group, lcn);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,46 +592,57 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NOTE: Restructured below so that analog and digital are handled the same, just that when
|
||||||
|
//its analog, it will now start edacs_analog which will while loop analog samples until
|
||||||
|
//signal level drops (RMS, or a dotting sequence is detected)
|
||||||
|
|
||||||
|
//analog working now with edacs_analog
|
||||||
if (command == 0xEE)
|
if (command == 0xEE)
|
||||||
{
|
|
||||||
//no handling for raw audio yet...that works properly atleast
|
|
||||||
fprintf (stderr, " Analog");
|
fprintf (stderr, " Analog");
|
||||||
}
|
|
||||||
else //Digital Call (ProVoice, hopefully not Aegis in 2022)
|
//Digital Call (ProVoice, hopefully, and not Aegis in 2022)
|
||||||
{
|
else
|
||||||
fprintf (stderr, " Digital");
|
fprintf (stderr, " Digital");
|
||||||
//this is working now with the new import setup
|
|
||||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
//skip analog calls on RTL Input on ARM devices due to High CPU usage from RTL RMS function
|
||||||
|
#ifdef __arm__
|
||||||
|
if (command == 0xEE && opts->audio_in_type == 3)
|
||||||
|
goto ENDPV;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//this is working now with the new import setup
|
||||||
|
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
|
||||||
|
{
|
||||||
|
if (lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
||||||
{
|
{
|
||||||
if (lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
|
//openwav file and do per call right here
|
||||||
|
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
||||||
{
|
{
|
||||||
//openwav file and do per call right here
|
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld AFS %02d-%03d - %X.wav", getDateE(), getTimeE(), state->edacs_site_id, a, fs, afs);
|
||||||
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
|
if (command == 0xEF) openWavOutFile (opts, state); //digital
|
||||||
{
|
if (command == 0xEE) openWavOutFile48k (opts, state); //analog at 48k
|
||||||
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld AFS %X.wav", getDateE(), getTimeE(), state->edacs_site_id, afs);
|
|
||||||
openWavOutFile (opts, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
|
|
||||||
state->edacs_tuned_lcn = lcn;
|
|
||||||
opts->p25_is_tuned = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->audio_in_type == 3) //rtl dongle
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
|
||||||
state->edacs_tuned_lcn = lcn;
|
|
||||||
opts->p25_is_tuned = 1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts->use_rigctl == 1)
|
||||||
|
{
|
||||||
|
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
|
||||||
|
state->edacs_tuned_lcn = lcn;
|
||||||
|
opts->p25_is_tuned = 1;
|
||||||
|
if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->audio_in_type == 3) //rtl dongle
|
||||||
|
{
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
|
||||||
|
state->edacs_tuned_lcn = lcn;
|
||||||
|
opts->p25_is_tuned = 1;
|
||||||
|
if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
@@ -462,6 +665,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENDPV:
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
294
src/ez.cpp
294
src/ez.cpp
@@ -178,146 +178,166 @@ int ez_rs28_sacch (int payload[180], int parity[132])
|
|||||||
return (ec);
|
return (ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
//I-ISCH Lookup section, borrowed from OP25
|
std::map <std::uint64_t, int> isch_map;
|
||||||
std::map <std::string, int> isch_map;
|
|
||||||
void map_isch()
|
void map_isch()
|
||||||
{
|
{
|
||||||
isch_map["184229d461"] = 0;
|
isch_map[0x184229d461ULL] = 0;
|
||||||
isch_map["18761451f6"] = 1;
|
isch_map[0x18761451f6ULL] = 1;
|
||||||
isch_map["181ae27e2f"] = 2;
|
isch_map[0x181ae27e2fULL] = 2;
|
||||||
isch_map["182edffbb8"] = 3;
|
isch_map[0x182edffbb8ULL] = 3;
|
||||||
isch_map["18df8a7510"] = 4;
|
isch_map[0x18df8a7510ULL] = 4;
|
||||||
isch_map["18ebb7f087"] = 5;
|
isch_map[0x18ebb7f087ULL] = 5;
|
||||||
isch_map["188741df5e"] = 6;
|
isch_map[0x188741df5eULL] = 6;
|
||||||
isch_map["18b37c5ac9"] = 7;
|
isch_map[0x18b37c5ac9ULL] = 7;
|
||||||
isch_map["1146a44f13"] = 8;
|
isch_map[0x1146a44f13ULL] = 8;
|
||||||
isch_map["117299ca84"] = 9;
|
isch_map[0x117299ca84ULL] = 9;
|
||||||
isch_map["111e6fe55d"] = 10;
|
isch_map[0x111e6fe55dULL] = 10;
|
||||||
isch_map["112a5260ca"] = 11;
|
isch_map[0x112a5260caULL] = 11;
|
||||||
isch_map["11db07ee62"] = 12;
|
isch_map[0x11db07ee62ULL] = 12;
|
||||||
isch_map["11ef3a6bf5"] = 13;
|
isch_map[0x11ef3a6bf5ULL] = 13;
|
||||||
isch_map["1183cc442c"] = 14;
|
isch_map[0x1183cc442cULL] = 14;
|
||||||
isch_map["11b7f1c1bb"] = 15;
|
isch_map[0x11b7f1c1bbULL] = 15;
|
||||||
isch_map["1a4a2e239e"] = 16;
|
isch_map[0x1a4a2e239eULL] = 16;
|
||||||
isch_map["1a7e13a609"] = 17;
|
isch_map[0x1a7e13a609ULL] = 17;
|
||||||
isch_map["1a12e589d0"] = 18;
|
isch_map[0x1a12e589d0ULL] = 18;
|
||||||
isch_map["1a26d80c47"] = 19;
|
isch_map[0x1a26d80c47ULL] = 19;
|
||||||
isch_map["1ad78d82ef"] = 20;
|
isch_map[0x1ad78d82efULL] = 20;
|
||||||
isch_map["1ae3b00778"] = 21;
|
isch_map[0x1ae3b00778ULL] = 21;
|
||||||
isch_map["1a8f4628a1"] = 22;
|
isch_map[0x1a8f4628a1ULL] = 22;
|
||||||
isch_map["1abb7bad36"] = 23;
|
isch_map[0x1abb7bad36ULL] = 23;
|
||||||
isch_map["134ea3b8ec"] = 24;
|
isch_map[0x134ea3b8ecULL] = 24;
|
||||||
isch_map["137a9e3d7b"] = 25;
|
isch_map[0x137a9e3d7bULL] = 25;
|
||||||
isch_map["13166812a2"] = 26;
|
isch_map[0x13166812a2ULL] = 26;
|
||||||
isch_map["1322559735"] = 27;
|
isch_map[0x1322559735ULL] = 27;
|
||||||
isch_map["13d300199d"] = 28;
|
isch_map[0x13d300199dULL] = 28;
|
||||||
isch_map["13e73d9c0a"] = 29;
|
isch_map[0x13e73d9c0aULL] = 29;
|
||||||
isch_map["138bcbb3d3"] = 30;
|
isch_map[0x138bcbb3d3ULL] = 30;
|
||||||
isch_map["13bff63644"] = 31;
|
isch_map[0x13bff63644ULL] = 31;
|
||||||
isch_map["1442f705ef"] = 32;
|
isch_map[0x1442f705efULL] = 32;
|
||||||
isch_map["1476ca8078"] = 33;
|
isch_map[0x1476ca8078ULL] = 33;
|
||||||
isch_map["141a3cafa1"] = 34;
|
isch_map[0x141a3cafa1ULL] = 34;
|
||||||
isch_map["142e012a36"] = 35;
|
isch_map[0x142e012a36ULL] = 35;
|
||||||
isch_map["14df54a49e"] = 36;
|
isch_map[0x14df54a49eULL] = 36;
|
||||||
isch_map["14eb692109"] = 37;
|
isch_map[0x14eb692109ULL] = 37;
|
||||||
isch_map["14879f0ed0"] = 38;
|
isch_map[0x14879f0ed0ULL] = 38;
|
||||||
isch_map["14b3a28b47"] = 39;
|
isch_map[0x14b3a28b47ULL] = 39;
|
||||||
isch_map["1d467a9e9d"] = 40;
|
isch_map[0x1d467a9e9dULL] = 40;
|
||||||
isch_map["1d72471b0a"] = 41;
|
isch_map[0x1d72471b0aULL] = 41;
|
||||||
isch_map["1d1eb134d3"] = 42;
|
isch_map[0x1d1eb134d3ULL] = 42;
|
||||||
isch_map["1d2a8cb144"] = 43;
|
isch_map[0x1d2a8cb144ULL] = 43;
|
||||||
isch_map["1ddbd93fec"] = 44;
|
isch_map[0x1ddbd93fecULL] = 44;
|
||||||
isch_map["1defe4ba7b"] = 45;
|
isch_map[0x1defe4ba7bULL] = 45;
|
||||||
isch_map["1d831295a2"] = 46;
|
isch_map[0x1d831295a2ULL] = 46;
|
||||||
isch_map["1db72f1035"] = 47;
|
isch_map[0x1db72f1035ULL] = 47;
|
||||||
isch_map["164af0f210"] = 48;
|
isch_map[0x164af0f210ULL] = 48;
|
||||||
isch_map["167ecd7787"] = 49;
|
isch_map[0x167ecd7787ULL] = 49;
|
||||||
isch_map["16123b585e"] = 50;
|
isch_map[0x16123b585eULL] = 50;
|
||||||
isch_map["162606ddc9"] = 51;
|
isch_map[0x162606ddc9ULL] = 51;
|
||||||
isch_map["16d7535361"] = 52;
|
isch_map[0x16d7535361ULL] = 52;
|
||||||
isch_map["16e36ed6f6"] = 53;
|
isch_map[0x16e36ed6f6ULL] = 53;
|
||||||
isch_map["168f98f92f"] = 54;
|
isch_map[0x168f98f92fULL] = 54;
|
||||||
isch_map["16bba57cb8"] = 55;
|
isch_map[0x16bba57cb8ULL] = 55;
|
||||||
isch_map["1f4e7d6962"] = 56;
|
isch_map[0x1f4e7d6962ULL] = 56;
|
||||||
isch_map["1f7a40ecf5"] = 57;
|
isch_map[0x1f7a40ecf5ULL] = 57;
|
||||||
isch_map["1f16b6c32c"] = 58;
|
isch_map[0x1f16b6c32cULL] = 58;
|
||||||
isch_map["1f228b46bb"] = 59;
|
isch_map[0x1f228b46bbULL] = 59;
|
||||||
isch_map["1fd3dec813"] = 60;
|
isch_map[0x1fd3dec813ULL] = 60;
|
||||||
isch_map["1fe7e34d84"] = 61;
|
isch_map[0x1fe7e34d84ULL] = 61;
|
||||||
isch_map["1f8b15625d"] = 62;
|
isch_map[0x1f8b15625dULL] = 62;
|
||||||
isch_map["1fbf28e7ca"] = 63;
|
isch_map[0x1fbf28e7caULL] = 63;
|
||||||
isch_map["84d62c339"] = 64;
|
isch_map[0x084d62c339ULL] = 64;
|
||||||
isch_map["8795f46ae"] = 65;
|
isch_map[0x08795f46aeULL] = 65;
|
||||||
isch_map["815a96977"] = 66;
|
isch_map[0x0815a96977ULL] = 66;
|
||||||
isch_map["82194ece0"] = 67;
|
isch_map[0x082194ece0ULL] = 67;
|
||||||
isch_map["8d0c16248"] = 68;
|
isch_map[0x08d0c16248ULL] = 68;
|
||||||
isch_map["8e4fce7df"] = 69;
|
isch_map[0x08e4fce7dfULL] = 69;
|
||||||
isch_map["8880ac806"] = 70;
|
isch_map[0x08880ac806ULL] = 70;
|
||||||
isch_map["8bc374d91"] = 71;
|
isch_map[0x08bc374d91ULL] = 71;
|
||||||
isch_map["149ef584b"] = 72;
|
isch_map[0x0149ef584bULL] = 72;
|
||||||
isch_map["17dd2dddc"] = 73;
|
isch_map[0x017dd2dddcULL] = 73;
|
||||||
isch_map["11124f205"] = 74;
|
isch_map[0x011124f205ULL] = 74;
|
||||||
isch_map["125197792"] = 75;
|
isch_map[0x0125197792ULL] = 75;
|
||||||
isch_map["1d44cf93a"] = 76;
|
isch_map[0x01d44cf93aULL] = 76;
|
||||||
isch_map["1e0717cad"] = 77;
|
isch_map[0x01e0717cadULL] = 77;
|
||||||
isch_map["18c875374"] = 78;
|
isch_map[0x018c875374ULL] = 78;
|
||||||
isch_map["1b8bad6e3"] = 79;
|
isch_map[0x01b8bad6e3ULL] = 79;
|
||||||
isch_map["a456534c6"] = 80;
|
isch_map[0x0a456534c6ULL] = 80;
|
||||||
isch_map["a7158b151"] = 81;
|
isch_map[0x0a7158b151ULL] = 81;
|
||||||
isch_map["a1dae9e88"] = 82;
|
isch_map[0x0a1dae9e88ULL] = 82;
|
||||||
isch_map["a29931b1f"] = 83;
|
isch_map[0x0a29931b1fULL] = 83;
|
||||||
isch_map["ad8c695b7"] = 84;
|
isch_map[0x0ad8c695b7ULL] = 84;
|
||||||
isch_map["aecfb1020"] = 85;
|
isch_map[0x0aecfb1020ULL] = 85;
|
||||||
isch_map["a800d3ff9"] = 86;
|
isch_map[0x0a800d3ff9ULL] = 86;
|
||||||
isch_map["ab430ba6e"] = 87;
|
isch_map[0x0ab430ba6eULL] = 87;
|
||||||
isch_map["341e8afb4"] = 88;
|
isch_map[0x0341e8afb4ULL] = 88;
|
||||||
isch_map["375d52a23"] = 89;
|
isch_map[0x0375d52a23ULL] = 89;
|
||||||
isch_map["3192305fa"] = 90;
|
isch_map[0x03192305faULL] = 90;
|
||||||
isch_map["32d1e806d"] = 91;
|
isch_map[0x032d1e806dULL] = 91;
|
||||||
isch_map["3dc4b0ec5"] = 92;
|
isch_map[0x03dc4b0ec5ULL] = 92;
|
||||||
isch_map["3e8768b52"] = 93;
|
isch_map[0x03e8768b52ULL] = 93;
|
||||||
isch_map["38480a48b"] = 94;
|
isch_map[0x038480a48bULL] = 94;
|
||||||
isch_map["3b0bd211c"] = 95;
|
isch_map[0x03b0bd211cULL] = 95;
|
||||||
isch_map["44dbc12b7"] = 96;
|
isch_map[0x044dbc12b7ULL] = 96;
|
||||||
isch_map["479819720"] = 97;
|
isch_map[0x0479819720ULL] = 97;
|
||||||
isch_map["41577b8f9"] = 98;
|
isch_map[0x041577b8f9ULL] = 98;
|
||||||
isch_map["4214a3d6e"] = 99;
|
isch_map[0x04214a3d6eULL] = 99;
|
||||||
isch_map["4d01fb3c6"] = 100;
|
isch_map[0x04d01fb3c6ULL] = 100;
|
||||||
isch_map["4e4223651"] = 101;
|
isch_map[0x04e4223651ULL] = 101;
|
||||||
isch_map["488d41988"] = 102;
|
isch_map[0x0488d41988ULL] = 102;
|
||||||
isch_map["4bce99c1f"] = 103;
|
isch_map[0x04bce99c1fULL] = 103;
|
||||||
isch_map["d493189c5"] = 104;
|
isch_map[0x0d493189c5ULL] = 104;
|
||||||
isch_map["d7d0c0c52"] = 105;
|
isch_map[0x0d7d0c0c52ULL] = 105;
|
||||||
isch_map["d11fa238b"] = 106;
|
isch_map[0x0d11fa238bULL] = 106;
|
||||||
isch_map["d25c7a61c"] = 107;
|
isch_map[0x0d25c7a61cULL] = 107;
|
||||||
isch_map["dd49228b4"] = 108;
|
isch_map[0x0dd49228b4ULL] = 108;
|
||||||
isch_map["de0afad23"] = 109;
|
isch_map[0x0de0afad23ULL] = 109;
|
||||||
isch_map["d8c5982fa"] = 110;
|
isch_map[0x0d8c5982faULL] = 110;
|
||||||
isch_map["db864076d"] = 111;
|
isch_map[0x0db864076dULL] = 111;
|
||||||
isch_map["645bbe548"] = 112;
|
isch_map[0x0645bbe548ULL] = 112;
|
||||||
isch_map["6718660df"] = 113;
|
isch_map[0x06718660dfULL] = 113;
|
||||||
isch_map["61d704f06"] = 114;
|
isch_map[0x061d704f06ULL] = 114;
|
||||||
isch_map["6294dca91"] = 115;
|
isch_map[0x06294dca91ULL] = 115;
|
||||||
isch_map["6d8184439"] = 116;
|
isch_map[0x06d8184439ULL] = 116;
|
||||||
isch_map["6ec25c1ae"] = 117;
|
isch_map[0x06ec25c1aeULL] = 117;
|
||||||
isch_map["680d3ee77"] = 118;
|
isch_map[0x0680d3ee77ULL] = 118;
|
||||||
isch_map["6b4ee6be0"] = 119;
|
isch_map[0x06b4ee6be0ULL] = 119;
|
||||||
isch_map["f41367e3a"] = 120;
|
isch_map[0x0f41367e3aULL] = 120;
|
||||||
isch_map["f750bfbad"] = 121;
|
isch_map[0x0f750bfbadULL] = 121;
|
||||||
isch_map["f19fdd474"] = 122;
|
isch_map[0x0f19fdd474ULL] = 122;
|
||||||
isch_map["f2dc051e3"] = 123;
|
isch_map[0x0f2dc051e3ULL] = 123;
|
||||||
isch_map["fdc95df4b"] = 124;
|
isch_map[0x0fdc95df4bULL] = 124;
|
||||||
isch_map["fe8a85adc"] = 125;
|
isch_map[0x0fe8a85adcULL] = 125;
|
||||||
isch_map["f845e7505"] = 126;
|
isch_map[0x0f845e7505ULL] = 126;
|
||||||
isch_map["fb063f092"] = 127;
|
isch_map[0x0fb063f092ULL] = 127;
|
||||||
|
isch_map[0x575d57f7ffULL] = -2; // S-ISCH
|
||||||
}
|
}
|
||||||
|
|
||||||
int isch_lookup (unsigned long long int isch)
|
//I-ISCH Lookup, borrowed from OP25 (now w/ error correction)
|
||||||
|
int isch_lookup (uint64_t isch)
|
||||||
{
|
{
|
||||||
map_isch(); //initialize the lookup map
|
map_isch(); //initialize the lookup map
|
||||||
char s[64];
|
int decoded = -2;
|
||||||
int decoded = -2; //initialize lookup to an invalid number
|
|
||||||
sprintf(s, "%llx", isch);
|
// Must contain bit errors if no exact match, so
|
||||||
decoded = isch_map[s];
|
// look for codeword with smallest hamming distance
|
||||||
return(decoded);
|
if (isch_map.find(isch) == isch_map.end())
|
||||||
|
{
|
||||||
|
int popct, popmin = 40;
|
||||||
|
for (auto it = isch_map.begin(); it != isch_map.end(); ++it)
|
||||||
|
{
|
||||||
|
popct = __builtin_popcountll(isch ^ it->first);
|
||||||
|
// Encoding is (40, 9, 16) which can correct at most 7 bit-errors
|
||||||
|
if ((popct <= 7) && (popct < popmin))
|
||||||
|
{
|
||||||
|
decoded = it->second;
|
||||||
|
popmin = popct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
else // No errors, so simply return the matching value
|
||||||
|
decoded = isch_map[isch];
|
||||||
|
|
||||||
|
return decoded;
|
||||||
|
|
||||||
}
|
}
|
||||||
193
src/m17.c
193
src/m17.c
@@ -40,11 +40,32 @@ uint8_t m17_scramble[369] = {
|
|||||||
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
|
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
|
||||||
|
|
||||||
uint8_t p1[62] = {
|
uint8_t p1[62] = {
|
||||||
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1,
|
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
||||||
1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
|
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
||||||
0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
|
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
|
||||||
|
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//produce 6 short samples (48k) for every 1 short sample (8k)
|
||||||
|
void upsampleM17 (short invalue, short prev, short outbuf[6])
|
||||||
|
{
|
||||||
|
|
||||||
|
float c, d;
|
||||||
|
|
||||||
|
c = prev;
|
||||||
|
d = invalue;
|
||||||
|
|
||||||
|
// basic triangle interpolation
|
||||||
|
outbuf[0] = c = ((invalue * (float) 0.166) + (c * (float) 0.834));
|
||||||
|
outbuf[1] = c = ((invalue * (float) 0.332) + (c * (float) 0.668));
|
||||||
|
outbuf[2] = c = ((invalue * (float) 0.500) + (c * (float) 0.5));
|
||||||
|
outbuf[3] = c = ((invalue * (float) 0.668) + (c * (float) 0.332));
|
||||||
|
outbuf[4] = c = ((invalue * (float) 0.834) + (c * (float) 0.166));
|
||||||
|
outbuf[5] = c = d;
|
||||||
|
prev = d; //shift prev to the last d value for the next repitition
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//from M17_Implementations -- sp5wwp -- should have just looked here to begin with
|
//from M17_Implementations -- sp5wwp -- should have just looked here to begin with
|
||||||
//this setup looks very similar to the OP25 variant of crc16, but with a few differences (uses packed bytes)
|
//this setup looks very similar to the OP25 variant of crc16, but with a few differences (uses packed bytes)
|
||||||
uint16_t crc16m17(const uint8_t *in, const uint16_t len)
|
uint16_t crc16m17(const uint8_t *in, const uint16_t len)
|
||||||
@@ -136,7 +157,7 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
uint16_t lsf_type = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[96], 16);
|
uint16_t lsf_type = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[96], 16);
|
||||||
|
|
||||||
//this is the way the manual/code expects you to read these bits
|
//this is the way the manual/code expects you to read these bits
|
||||||
uint8_t lsf_ps = (lsf_type >> 0) & 0x1;
|
// uint8_t lsf_ps = (lsf_type >> 0) & 0x1;
|
||||||
uint8_t lsf_dt = (lsf_type >> 1) & 0x3;
|
uint8_t lsf_dt = (lsf_type >> 1) & 0x3;
|
||||||
uint8_t lsf_et = (lsf_type >> 3) & 0x3;
|
uint8_t lsf_et = (lsf_type >> 3) & 0x3;
|
||||||
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
|
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
|
||||||
@@ -147,18 +168,17 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
state->m17_str_dt = lsf_dt;
|
state->m17_str_dt = lsf_dt;
|
||||||
state->m17_dst = lsf_dst;
|
state->m17_dst = lsf_dst;
|
||||||
state->m17_src = lsf_src;
|
state->m17_src = lsf_src;
|
||||||
|
state->m17_can = lsf_cn;
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
//packet or stream
|
//packet or stream
|
||||||
if (lsf_ps == 0) fprintf (stderr, " P-");
|
// if (lsf_ps == 0) fprintf (stderr, " P-");
|
||||||
if (lsf_ps == 1) fprintf (stderr, " S-");
|
// if (lsf_ps == 1) fprintf (stderr, " S-");
|
||||||
|
|
||||||
fprintf (stderr, " CAN: %d", lsf_cn);
|
fprintf (stderr, " CAN: %d", lsf_cn);
|
||||||
M17decodeCSD(state, lsf_dst, lsf_src);
|
M17decodeCSD(state, lsf_dst, lsf_src);
|
||||||
|
|
||||||
if (lsf_et != 0) fprintf (stderr, " ENC");
|
|
||||||
|
|
||||||
if (lsf_dt == 0) fprintf (stderr, " Reserved");
|
if (lsf_dt == 0) fprintf (stderr, " Reserved");
|
||||||
if (lsf_dt == 1) fprintf (stderr, " Data");
|
if (lsf_dt == 1) fprintf (stderr, " Data");
|
||||||
if (lsf_dt == 2) fprintf (stderr, " Voice (3200bps)");
|
if (lsf_dt == 2) fprintf (stderr, " Voice (3200bps)");
|
||||||
@@ -166,8 +186,9 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
|
|
||||||
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
|
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
|
||||||
|
|
||||||
if (lsf_et == 1) fprintf (stderr, " AES-CTR");
|
if (lsf_et != 0) fprintf (stderr, " ENC:");
|
||||||
if (lsf_et == 2) fprintf (stderr, " Scrambler - %d", lsf_es);
|
if (lsf_et == 2) fprintf (stderr, " AES-CTR");
|
||||||
|
if (lsf_et == 1) fprintf (stderr, " Scrambler - %d", lsf_es);
|
||||||
|
|
||||||
state->m17_enc = lsf_et;
|
state->m17_enc = lsf_et;
|
||||||
state->m17_enc_st = lsf_es;
|
state->m17_enc_st = lsf_es;
|
||||||
@@ -186,16 +207,16 @@ void M17decodeLSF(dsd_state * state)
|
|||||||
if (lsf_es == 3) fprintf (stderr, " Reserved");
|
if (lsf_es == 3) fprintf (stderr, " Reserved");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lsf_et == 1)
|
if (lsf_et == 2)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " IV: ");
|
fprintf (stderr, " IV: ");
|
||||||
for (i = 0; i < 14; i++)
|
for (i = 0; i < 16; i++)
|
||||||
fprintf (stderr, "%02X", state->m17_meta[i]);
|
fprintf (stderr, "%02X", state->m17_meta[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t lich_bits[96])
|
int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits)
|
||||||
{
|
{
|
||||||
int i, j, err;
|
int i, j, err;
|
||||||
err = 0;
|
err = 0;
|
||||||
@@ -292,14 +313,10 @@ int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t lich_bits[96])
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[128])
|
void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload)
|
||||||
{
|
{
|
||||||
|
|
||||||
//If payload is the same from the stream in this mode, I suppose we could use this area to parse
|
|
||||||
//or send off the remaining data to be handled or decoded , or just print out the raw data bytes
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
unsigned char voice1[8]; //codec2_bytes_per_frame
|
unsigned char voice1[8];
|
||||||
unsigned char voice2[8];
|
unsigned char voice2[8];
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
@@ -329,35 +346,47 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[1
|
|||||||
|
|
||||||
#ifdef USE_CODEC2
|
#ifdef USE_CODEC2
|
||||||
size_t nsam;
|
size_t nsam;
|
||||||
nsam = 320; //codec2_samples_per_frame(state->codec2_1600);
|
nsam = 160;
|
||||||
|
|
||||||
short samp1[nsam];
|
|
||||||
// short samp2[nsam];
|
|
||||||
memset (samp1, 0, sizeof(samp1));
|
|
||||||
// memset (samp2, 0, sizeof(samp2));
|
|
||||||
|
|
||||||
|
//converted to using allocated memory pointers to prevent the overflow issues
|
||||||
|
short * samp1 = malloc (sizeof(short) * nsam);
|
||||||
|
short * upsamp = malloc (sizeof(short) * nsam * 6);
|
||||||
|
short * out = malloc (sizeof(short) * 6);
|
||||||
|
short prev;
|
||||||
|
int j;
|
||||||
|
|
||||||
codec2_decode(state->codec2_1600, samp1, voice1);
|
codec2_decode(state->codec2_1600, samp1, voice1);
|
||||||
// codec2_decode(state->codec2_1600, samp2, voice2);
|
|
||||||
|
|
||||||
|
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
|
||||||
if (opts->audio_out_type == 0 && state->m17_enc == 0)
|
|
||||||
{
|
{
|
||||||
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
||||||
// pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->audio_out_type == 5 && state->m17_enc == 0)
|
#ifdef AERO_BUILD
|
||||||
|
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS w/ required upsample to 48k
|
||||||
|
{
|
||||||
|
//upsample to 48k and then play
|
||||||
|
prev = samp1[0];
|
||||||
|
for (i = 0; i < 160; i++)
|
||||||
|
{
|
||||||
|
upsampleM17 (samp1[i], prev, out);
|
||||||
|
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
|
||||||
|
}
|
||||||
|
write (opts->audio_out_fd, upsamp, nsam*2*6);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS via PADSP at 8k
|
||||||
{
|
{
|
||||||
write (opts->audio_out_fd, samp1, nsam*2);
|
write (opts->audio_out_fd, samp1, nsam*2);
|
||||||
// write (opts->audio_out_fd, samp2, nsam*2);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
||||||
if(opts->wav_out_f != NULL && state->m17_enc == 0)
|
if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV
|
||||||
{
|
{
|
||||||
sf_write_short(opts->wav_out_f, samp1, nsam);
|
sf_write_short(opts->wav_out_f, samp1, nsam);
|
||||||
// sf_write_short(opts->wav_out_f, samp2, nsam);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Codec2 Raw file saving
|
//TODO: Codec2 Raw file saving
|
||||||
@@ -366,14 +395,18 @@ void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t payload[1
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
free (samp1);
|
||||||
|
free (upsamp);
|
||||||
|
free (out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[128])
|
void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned char voice1[8]; //codec2_bytes_per_frame
|
unsigned char voice1[8];
|
||||||
unsigned char voice2[8];
|
unsigned char voice2[8];
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
@@ -404,32 +437,62 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[1
|
|||||||
|
|
||||||
#ifdef USE_CODEC2
|
#ifdef USE_CODEC2
|
||||||
size_t nsam;
|
size_t nsam;
|
||||||
nsam = 160; //codec2_samples_per_frame(state->codec2_3200);
|
nsam = 160;
|
||||||
|
|
||||||
short samp1[nsam];
|
|
||||||
short samp2[nsam];
|
|
||||||
memset (samp1, 0, sizeof(samp1));
|
|
||||||
memset (samp2, 0, sizeof(samp2));
|
|
||||||
|
|
||||||
|
//converted to using allocated memory pointers to prevent the overflow issues
|
||||||
|
short * samp1 = malloc (sizeof(short) * nsam);
|
||||||
|
short * samp2 = malloc (sizeof(short) * nsam);
|
||||||
|
short * upsamp = malloc (sizeof(short) * nsam * 6);
|
||||||
|
short * out = malloc (sizeof(short) * 6);
|
||||||
|
short prev;
|
||||||
|
int j;
|
||||||
|
|
||||||
codec2_decode(state->codec2_3200, samp1, voice1);
|
codec2_decode(state->codec2_3200, samp1, voice1);
|
||||||
codec2_decode(state->codec2_3200, samp2, voice2);
|
codec2_decode(state->codec2_3200, samp2, voice2);
|
||||||
|
|
||||||
|
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
|
||||||
if (opts->audio_out_type == 0 && state->m17_enc == 0)
|
|
||||||
{
|
{
|
||||||
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
|
||||||
pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->audio_out_type == 5 && state->m17_enc == 0)
|
#ifdef AERO_BUILD
|
||||||
|
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS w/ required upsample to 48k
|
||||||
|
{
|
||||||
|
//upsample to 48k and then play
|
||||||
|
// prev = samp1[0];
|
||||||
|
prev = 0;
|
||||||
|
for (i = 0; i < 160; i++)
|
||||||
|
{
|
||||||
|
upsampleM17 (samp1[i], prev, out);
|
||||||
|
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
|
||||||
|
}
|
||||||
|
write (opts->audio_out_fd, upsamp, nsam*2*6);
|
||||||
|
prev = samp2[0];
|
||||||
|
for (i = 0; i < 160; i++)
|
||||||
|
{
|
||||||
|
upsampleM17 (samp2[i], prev, out);
|
||||||
|
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
|
||||||
|
}
|
||||||
|
write (opts->audio_out_fd, upsamp, nsam*2*6);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS via PADSP at 8k
|
||||||
|
{
|
||||||
|
write (opts->audio_out_fd, samp1, nsam*2);
|
||||||
|
write (opts->audio_out_fd, samp2, nsam*2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT
|
||||||
{
|
{
|
||||||
write (opts->audio_out_fd, samp1, nsam*2);
|
write (opts->audio_out_fd, samp1, nsam*2);
|
||||||
write (opts->audio_out_fd, samp2, nsam*2);
|
write (opts->audio_out_fd, samp2, nsam*2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
|
||||||
if(opts->wav_out_f != NULL && state->m17_enc == 0)
|
if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV
|
||||||
{
|
{
|
||||||
sf_write_short(opts->wav_out_f, samp1, nsam);
|
sf_write_short(opts->wav_out_f, samp1, nsam);
|
||||||
sf_write_short(opts->wav_out_f, samp2, nsam);
|
sf_write_short(opts->wav_out_f, samp2, nsam);
|
||||||
@@ -441,21 +504,26 @@ void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t payload[1
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
free (samp1);
|
||||||
|
free (samp2);
|
||||||
|
free (upsamp);
|
||||||
|
free (out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t m17_bits[368])
|
void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t * m17_bits)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i, j, k, x;
|
int i, k, x;
|
||||||
uint8_t m17_punc[310]; //25 * 11 = 275
|
uint8_t m17_punc[275]; //25 * 11 = 275
|
||||||
memset (m17_punc, 0, sizeof(m17_punc));
|
memset (m17_punc, 0, sizeof(m17_punc));
|
||||||
for (i = 0; i < 272; i++)
|
for (i = 0; i < 272; i++)
|
||||||
m17_punc[i] = m17_bits[i+96];
|
m17_punc[i] = m17_bits[i+96];
|
||||||
|
|
||||||
//depuncture the bits
|
//depuncture the bits
|
||||||
uint8_t m17_depunc[310]; //25 * 12 = 300
|
uint8_t m17_depunc[300]; //25 * 12 = 300
|
||||||
memset (m17_depunc, 0, sizeof(m17_depunc));
|
memset (m17_depunc, 0, sizeof(m17_depunc));
|
||||||
k = 0; x = 0;
|
k = 0; x = 0;
|
||||||
for (i = 0; i < 25; i++)
|
for (i = 0; i < 25; i++)
|
||||||
@@ -479,7 +547,7 @@ void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t m17_bits[368])
|
|||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[28];
|
uint8_t m_data[28];
|
||||||
uint8_t trellis_buf[400];
|
uint8_t trellis_buf[144];
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
memset (temp, 0, sizeof (temp));
|
memset (temp, 0, sizeof (temp));
|
||||||
memset (m_data, 0, sizeof (m_data));
|
memset (m_data, 0, sizeof (m_data));
|
||||||
@@ -520,6 +588,10 @@ void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t m17_bits[368])
|
|||||||
end = trellis_buf[0];
|
end = trellis_buf[0];
|
||||||
fn = (uint16_t)ConvertBitIntoBytes(&trellis_buf[1], 15);
|
fn = (uint16_t)ConvertBitIntoBytes(&trellis_buf[1], 15);
|
||||||
|
|
||||||
|
//insert fn bits into meta 14 and meta 15 for Initialization Vector
|
||||||
|
state->m17_meta[14] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[1], 7);
|
||||||
|
state->m17_meta[15] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[8], 8);
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
fprintf (stderr, " FSN: %05d", fn);
|
fprintf (stderr, " FSN: %05d", fn);
|
||||||
|
|
||||||
@@ -550,13 +622,7 @@ void processM17STR(dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
|
|
||||||
int i, x;
|
int i, x;
|
||||||
|
//overflow/memory issue returns in Cygwin for...reasons...
|
||||||
//NOTE: adding more space for dbuf seems to fix the memory issue, but I don't think this is
|
|
||||||
//the culprit, not entirely sure what is going on here, but the issue with Cygwin (32-bit)
|
|
||||||
//not working at all with this also is fixed by this and I can't seem to figure out why
|
|
||||||
//its probably something really dumb that I am completely blind on seeing here for some reason
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
||||||
uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized)
|
uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized)
|
||||||
uint8_t m17_int_bits[368]; //368 bits that are still interleaved
|
uint8_t m17_int_bits[368]; //368 bits that are still interleaved
|
||||||
@@ -612,12 +678,9 @@ void processM17STR(dsd_opts * opts, dsd_state * state)
|
|||||||
void processM17LSF(dsd_opts * opts, dsd_state * state)
|
void processM17LSF(dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
//NOTE1: Pretty sure the flow here is all correct, but the initial (and only)
|
//NOTE: Have not been able to get this to work successfully, but considering
|
||||||
//LSF frame is demodulated incorrectly, so more than likely, this frame will
|
//there is only one LSF frame at the beginning of TX, its probably just as easy to
|
||||||
//always be bad since there is only one sent before STR
|
//use and rely on the STR frame and embedded LSF chunk, which does work properly
|
||||||
|
|
||||||
//NOTE2: Even with the preamble detection and LSF sync, we still get bad decode on this
|
|
||||||
|
|
||||||
int i, j, k, x;
|
int i, j, k, x;
|
||||||
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
|
||||||
uint8_t m17_rnd_bits[500]; //368 bits that are still scrambled (randomized)
|
uint8_t m17_rnd_bits[500]; //368 bits that are still scrambled (randomized)
|
||||||
@@ -673,8 +736,8 @@ void processM17LSF(dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t temp[500];
|
uint8_t temp[500];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[32];
|
uint8_t m_data[30];
|
||||||
uint8_t trellis_buf[400];
|
uint8_t trellis_buf[240]; //30*8 = 240
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
memset (temp, 0, sizeof (temp));
|
memset (temp, 0, sizeof (temp));
|
||||||
memset (m_data, 0, sizeof (m_data));
|
memset (m_data, 0, sizeof (m_data));
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ void nxdn_descramble(uint8_t dibits[], int len)
|
|||||||
|
|
||||||
void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
||||||
{
|
{
|
||||||
uint8_t deperm[200]; //144
|
uint8_t deperm[144]; //144
|
||||||
uint8_t depunc[200]; //192
|
uint8_t depunc[192]; //192
|
||||||
uint8_t trellis_buf[400]; //96
|
uint8_t trellis_buf[96]; //96
|
||||||
uint16_t crc = 0; //crc calculated by function
|
uint16_t crc = 0; //crc calculated by function
|
||||||
uint16_t check = 0; //crc from payload for comparison
|
uint16_t check = 0; //crc from payload for comparison
|
||||||
int out;
|
int out;
|
||||||
@@ -70,7 +70,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
|||||||
}
|
}
|
||||||
|
|
||||||
//switch to the convolutional decoder
|
//switch to the convolutional decoder
|
||||||
uint8_t temp[210];
|
uint8_t temp[200];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[20]; //13
|
uint8_t m_data[20]; //13
|
||||||
@@ -79,17 +79,10 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
|||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
|
|
||||||
for (int i = 0; i < 192; i++)
|
for (int i = 0; i < 192; i++)
|
||||||
{
|
|
||||||
temp[i] = depunc[i] << 1;
|
temp[i] = depunc[i] << 1;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
temp[i+192] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CNXDNConvolution_start();
|
CNXDNConvolution_start();
|
||||||
for (int i = 0U; i < 100U; i++)
|
for (int i = 0; i < 96; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -97,7 +90,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
|||||||
CNXDNConvolution_decode(s0, s1);
|
CNXDNConvolution_decode(s0, s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CNXDNConvolution_chainback(m_data, 96U);
|
CNXDNConvolution_chainback(m_data, 92);
|
||||||
|
|
||||||
for(int i = 0; i < 12; i++)
|
for(int i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
@@ -119,7 +112,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
||||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
@@ -143,9 +136,9 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
|
|||||||
void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||||
{
|
{
|
||||||
//see about initializing these variables
|
//see about initializing these variables
|
||||||
uint8_t deperm[200]; //60
|
uint8_t deperm[60]; //60
|
||||||
uint8_t depunc[200]; //72
|
uint8_t depunc[72]; //72
|
||||||
uint8_t trellis_buf[400]; //32
|
uint8_t trellis_buf[32]; //32
|
||||||
|
|
||||||
memset (deperm, 0, sizeof(deperm));
|
memset (deperm, 0, sizeof(deperm));
|
||||||
memset (depunc, 0, sizeof(depunc));
|
memset (depunc, 0, sizeof(depunc));
|
||||||
@@ -176,27 +169,20 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
|||||||
}
|
}
|
||||||
|
|
||||||
//switch to the convolutional decoder
|
//switch to the convolutional decoder
|
||||||
uint8_t temp[90];
|
uint8_t temp[80];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[10]; //5
|
uint8_t m_data[5]; //5
|
||||||
|
|
||||||
memset (temp, 0, sizeof (temp));
|
memset (temp, 0, sizeof (temp));
|
||||||
memset (m_data, 0, sizeof (m_data));
|
memset (m_data, 0, sizeof (m_data));
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
|
|
||||||
for (int i = 0; i < 72; i++)
|
for (int i = 0; i < 72; i++)
|
||||||
{
|
|
||||||
temp[i] = depunc[i] << 1;
|
temp[i] = depunc[i] << 1;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
temp[i+72] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CNXDNConvolution_start();
|
CNXDNConvolution_start();
|
||||||
for (int i = 0U; i < 36U; i++) //40
|
for (int i = 0; i < 36; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -205,7 +191,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
|||||||
}
|
}
|
||||||
|
|
||||||
//stored as 5 bytes, will need to convert to trellis_buf after running
|
//stored as 5 bytes, will need to convert to trellis_buf after running
|
||||||
CNXDNConvolution_chainback(m_data, 32U); //36
|
CNXDNConvolution_chainback(m_data, 32);
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++)
|
for(int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
@@ -232,7 +218,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
|||||||
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
|
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
|
||||||
else fprintf (stderr, " ");
|
else fprintf (stderr, " ");
|
||||||
|
|
||||||
uint8_t nsf_sacch[400];
|
uint8_t nsf_sacch[26];
|
||||||
memset (nsf_sacch, 0, sizeof(nsf_sacch));
|
memset (nsf_sacch, 0, sizeof(nsf_sacch));
|
||||||
for (int i = 0; i < 26; i++)
|
for (int i = 0; i < 26; i++)
|
||||||
{
|
{
|
||||||
@@ -350,9 +336,9 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
|||||||
|
|
||||||
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type)
|
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type)
|
||||||
{
|
{
|
||||||
uint8_t deperm[500]; //348
|
uint8_t deperm[348]; //348
|
||||||
uint8_t depunc[500]; //406
|
uint8_t depunc[406]; //406
|
||||||
uint8_t trellis_buf[400]; //199
|
uint8_t trellis_buf[208]; //199
|
||||||
int id = 0;
|
int id = 0;
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
uint16_t check = 0;
|
uint16_t check = 0;
|
||||||
@@ -381,26 +367,19 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
}
|
}
|
||||||
|
|
||||||
//switch to the convolutional decoder
|
//switch to the convolutional decoder
|
||||||
uint8_t temp[500]; //220, this one was way too small
|
uint8_t temp[406];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[52]; //26
|
uint8_t m_data[26]; //26
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
memset (temp, 0, sizeof (temp));
|
memset (temp, 0, sizeof (temp));
|
||||||
memset (m_data, 0, sizeof (m_data));
|
memset (m_data, 0, sizeof (m_data));
|
||||||
|
|
||||||
for (int i = 0; i < 406; i++)
|
for (int i = 0; i < 406; i++)
|
||||||
{
|
|
||||||
temp[i] = depunc[i] << 1;
|
temp[i] = depunc[i] << 1;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
temp[i+203] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CNXDNConvolution_start();
|
CNXDNConvolution_start();
|
||||||
for (int i = 0U; i < 207U; i++)
|
for (int i = 0; i < 203; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -409,7 +388,7 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
}
|
}
|
||||||
|
|
||||||
//numerals seem okay now
|
//numerals seem okay now
|
||||||
CNXDNConvolution_chainback(m_data, 203U);
|
CNXDNConvolution_chainback(m_data, 199);
|
||||||
|
|
||||||
for(int i = 0; i < 26; i++)
|
for(int i = 0; i < 26; i++)
|
||||||
{
|
{
|
||||||
@@ -440,7 +419,7 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
|
|
||||||
//just going to leave this all here in case its needed, like in cac,
|
//just going to leave this all here in case its needed, like in cac,
|
||||||
//don't have any samples with f2 or udch data in it
|
//don't have any samples with f2 or udch data in it
|
||||||
for (int i = 0; i < 199-8; i++)
|
for (int i = 0; i < 199-8-15; i++)
|
||||||
{
|
{
|
||||||
f2u_message_buffer[i] = trellis_buf[i+8];
|
f2u_message_buffer[i] = trellis_buf[i+8];
|
||||||
}
|
}
|
||||||
@@ -450,11 +429,11 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
|
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
|
||||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||||
}
|
}
|
||||||
else if (opts->aggressive_framesync == 0)
|
// else if (opts->aggressive_framesync == 0)
|
||||||
{
|
// {
|
||||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
|
// if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
|
||||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
// if (type == 0) {} //need handling for user data (text messages and AVL)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
@@ -495,9 +474,9 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
|||||||
|
|
||||||
void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||||
{
|
{
|
||||||
uint8_t deperm[500]; //300
|
uint8_t deperm[300]; //300
|
||||||
uint8_t depunc[500]; //350
|
uint8_t depunc[350]; //350
|
||||||
uint8_t trellis_buf[400]; //171
|
uint8_t trellis_buf[176]; //176
|
||||||
int id = 0;
|
int id = 0;
|
||||||
int ran = 0;
|
int ran = 0;
|
||||||
uint16_t crc = 0;
|
uint16_t crc = 0;
|
||||||
@@ -526,21 +505,19 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
|||||||
}
|
}
|
||||||
|
|
||||||
//switch to the convolutional decoder
|
//switch to the convolutional decoder
|
||||||
uint8_t temp[360];
|
uint8_t temp[179];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[52]; //26
|
uint8_t m_data[22]; //26
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
memset (temp, 0, sizeof (temp));
|
memset (temp, 0, sizeof (temp));
|
||||||
memset (m_data, 0, sizeof (m_data));
|
memset (m_data, 0, sizeof (m_data));
|
||||||
|
|
||||||
for (int i = 0; i < 350; i++)
|
for (int i = 0; i < 350; i++)
|
||||||
{
|
|
||||||
temp[i] = depunc[i] << 1;
|
temp[i] = depunc[i] << 1;
|
||||||
}
|
|
||||||
|
|
||||||
CNXDNConvolution_start();
|
CNXDNConvolution_start();
|
||||||
for (int i = 0U; i < 179U; i++)
|
for (int i = 0; i < 175; i++) //179
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -548,7 +525,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
|||||||
CNXDNConvolution_decode(s0, s1);
|
CNXDNConvolution_decode(s0, s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CNXDNConvolution_chainback(m_data, 175U);
|
CNXDNConvolution_chainback(m_data, 171); //175
|
||||||
|
|
||||||
for(int i = 0; i < 22; i++)
|
for(int i = 0; i < 22; i++)
|
||||||
{
|
{
|
||||||
@@ -564,11 +541,11 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
|||||||
|
|
||||||
crc = crc16cac(trellis_buf, 171);
|
crc = crc16cac(trellis_buf, 171);
|
||||||
|
|
||||||
uint8_t cac_message_buffer[400]; //171
|
uint8_t cac_message_buffer[147]; //171
|
||||||
memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
|
memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
|
||||||
|
|
||||||
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field
|
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field and ending crc
|
||||||
for (int i = 0; i < 160; i++)
|
for (int i = 0; i < 147; i++)
|
||||||
{
|
{
|
||||||
cac_message_buffer[i] = trellis_buf[i+8];
|
cac_message_buffer[i] = trellis_buf[i+8];
|
||||||
}
|
}
|
||||||
@@ -594,7 +571,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
|
if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
|
||||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, cac_message_buffer);
|
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, cac_message_buffer);
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
@@ -618,9 +595,9 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
|||||||
fprintf (stderr, " SCCH");
|
fprintf (stderr, " SCCH");
|
||||||
|
|
||||||
//see about initializing these variables
|
//see about initializing these variables
|
||||||
uint8_t deperm[200]; //60
|
uint8_t deperm[60]; //60
|
||||||
uint8_t depunc[200]; //72
|
uint8_t depunc[72]; //72
|
||||||
uint8_t trellis_buf[400]; //32
|
uint8_t trellis_buf[32]; //32
|
||||||
|
|
||||||
memset (deperm, 0, sizeof(deperm));
|
memset (deperm, 0, sizeof(deperm));
|
||||||
memset (depunc, 0, sizeof(depunc));
|
memset (depunc, 0, sizeof(depunc));
|
||||||
@@ -650,27 +627,20 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
//switch to the convolutional decoder
|
//switch to the convolutional decoder
|
||||||
uint8_t temp[90];
|
uint8_t temp[72];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[10]; //5
|
uint8_t m_data[5]; //5
|
||||||
|
|
||||||
memset (temp, 0, sizeof (temp));
|
memset (temp, 0, sizeof (temp));
|
||||||
memset (m_data, 0, sizeof (m_data));
|
memset (m_data, 0, sizeof (m_data));
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
|
|
||||||
for (int i = 0; i < 72; i++)
|
for (int i = 0; i < 72; i++)
|
||||||
{
|
|
||||||
temp[i] = depunc[i] << 1;
|
temp[i] = depunc[i] << 1;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
temp[i+72] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CNXDNConvolution_start();
|
CNXDNConvolution_start();
|
||||||
for (int i = 0U; i < 36U; i++)
|
for (int i = 0; i < 36; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -678,7 +648,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
|||||||
CNXDNConvolution_decode(s0, s1);
|
CNXDNConvolution_decode(s0, s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CNXDNConvolution_chainback(m_data, 32U);
|
CNXDNConvolution_chainback(m_data, 32);
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++)
|
for(int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
@@ -731,7 +701,7 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
|||||||
//like everything else does
|
//like everything else does
|
||||||
|
|
||||||
if (crc == check) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
if (crc == check) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
||||||
else if (opts->aggressive_framesync == 0) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
// else if (opts->aggressive_framesync == 0) NXDN_decode_scch (opts, state, trellis_buf, direction);
|
||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
@@ -757,9 +727,9 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
|||||||
|
|
||||||
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type)
|
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type)
|
||||||
{
|
{
|
||||||
uint8_t deperm[300]; //144
|
uint8_t deperm[144]; //144
|
||||||
uint8_t depunc[300]; //192
|
uint8_t depunc[192]; //192
|
||||||
uint8_t trellis_buf[600]; //96
|
uint8_t trellis_buf[96]; //96
|
||||||
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached
|
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached
|
||||||
uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
|
uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
|
||||||
uint16_t crc[2]; //crc calculated by function
|
uint16_t crc[2]; //crc calculated by function
|
||||||
@@ -767,10 +737,10 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
int out;
|
int out;
|
||||||
|
|
||||||
//switch to the convolutional decoder
|
//switch to the convolutional decoder
|
||||||
uint8_t temp[500];
|
uint8_t temp[192];
|
||||||
uint8_t s0;
|
uint8_t s0;
|
||||||
uint8_t s1;
|
uint8_t s1;
|
||||||
uint8_t m_data[40]; //13
|
uint8_t m_data[12]; //13
|
||||||
memset (temp, 0, sizeof(temp));
|
memset (temp, 0, sizeof(temp));
|
||||||
memset (m_data, 0, sizeof(m_data));
|
memset (m_data, 0, sizeof(m_data));
|
||||||
memset (trellis_buf, 0, sizeof(trellis_buf));
|
memset (trellis_buf, 0, sizeof(trellis_buf));
|
||||||
@@ -794,17 +764,10 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 192; i++)
|
for (int i = 0; i < 192; i++)
|
||||||
{
|
|
||||||
temp[i] = depunc[i] << 1;
|
temp[i] = depunc[i] << 1;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
temp[i+192] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CNXDNConvolution_start();
|
CNXDNConvolution_start();
|
||||||
for (int i = 0U; i < 100U; i++)
|
for (int i = 0; i < 96; i++)
|
||||||
{
|
{
|
||||||
s0 = temp[(2*i)];
|
s0 = temp[(2*i)];
|
||||||
s1 = temp[(2*i)+1];
|
s1 = temp[(2*i)+1];
|
||||||
@@ -812,7 +775,7 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
CNXDNConvolution_decode(s0, s1);
|
CNXDNConvolution_decode(s0, s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CNXDNConvolution_chainback(m_data, 96U);
|
CNXDNConvolution_chainback(m_data, 92);
|
||||||
|
|
||||||
for(int i = 0; i < 12; i++)
|
for(int i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
@@ -849,11 +812,11 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
|
|||||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
|
||||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
if (type == 0) ; //need handling for user data (text messages and AVL)
|
||||||
}
|
}
|
||||||
else if (opts->aggressive_framesync == 0)
|
// else if (opts->aggressive_framesync == 0)
|
||||||
{
|
// {
|
||||||
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
// if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
|
||||||
if (type == 0) ; //need handling for user data (text messages and AVL)
|
// if (type == 0) {} //need handling for user data (text messages and AVL)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (opts->payload == 1)
|
if (opts->payload == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
|
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
uint8_t SACCH[400]; //72
|
uint8_t SACCH[72]; //72
|
||||||
uint8_t sacch_bytes[10];
|
uint8_t sacch_bytes[9];
|
||||||
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t CrcCorrect = 1;
|
uint8_t CrcCorrect = 1;
|
||||||
@@ -38,7 +38,7 @@ void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
|
|||||||
/* Decodes the element content */
|
/* Decodes the element content */
|
||||||
// currently only going to run this if all four CRCs are good
|
// currently only going to run this if all four CRCs are good
|
||||||
if (CrcCorrect == 1) NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH);
|
if (CrcCorrect == 1) NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH);
|
||||||
else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, SACCH);
|
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, SACCH);
|
||||||
|
|
||||||
//reset the sacch field -- Github Issue #118
|
//reset the sacch field -- Github Issue #118
|
||||||
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||||
|
|||||||
@@ -37,4 +37,9 @@ processTDU (dsd_opts* opts, dsd_state* state)
|
|||||||
//reset some strings -- since its a tdu, blank out any call strings, only want during actual call
|
//reset some strings -- since its a tdu, blank out any call strings, only want during actual call
|
||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||||
|
|
||||||
|
//zero out on termination
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_miP = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -446,4 +446,9 @@ processTDULC (dsd_opts* opts, dsd_state* state)
|
|||||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||||
|
|
||||||
|
//zero out on termination
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_miP = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ int dibit = 0;
|
|||||||
int vc_counter = 0;
|
int vc_counter = 0;
|
||||||
int framing_counter = 0;
|
int framing_counter = 0;
|
||||||
|
|
||||||
unsigned long long int isch = 0;
|
uint64_t isch = 0;
|
||||||
int isch_decoded = -1;
|
int isch_decoded = -1;
|
||||||
int p2_duid[8] = {0};
|
int p2_duid[8] = {0};
|
||||||
int16_t duid_decoded = 0;
|
int16_t duid_decoded = 0;
|
||||||
|
|||||||
@@ -463,11 +463,14 @@ void dc_block_filter(struct demod_state *fm)
|
|||||||
}
|
}
|
||||||
fm->dc_avg = avg;
|
fm->dc_avg = avg;
|
||||||
}
|
}
|
||||||
|
//TODO: Fix This so we don't get random negative values in Cygwin (or 32-bit builds?)
|
||||||
int rms(int16_t *samples, int len, int step)
|
//Fixed -- I honestly think the issue is Cygwin can't keep up and if it can't run enough samples in the other thread,
|
||||||
|
//then it reports some jank values, really unsure, I've never seen the issue in Linux side though
|
||||||
|
long int rms(int16_t *samples, int len, int step)
|
||||||
/* largely lifted from rtl_power */
|
/* largely lifted from rtl_power */
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
long int rms;
|
||||||
long p, t, s;
|
long p, t, s;
|
||||||
double dc, err;
|
double dc, err;
|
||||||
|
|
||||||
@@ -481,7 +484,10 @@ int rms(int16_t *samples, int len, int step)
|
|||||||
dc = (double)(t*step) / (double)len;
|
dc = (double)(t*step) / (double)len;
|
||||||
err = t * 2 * dc - dc * dc * len;
|
err = t * 2 * dc - dc * dc * len;
|
||||||
|
|
||||||
return (int)sqrt((p-err) / len);
|
rms = (long int)sqrt((p-err) / len);
|
||||||
|
//going with a value that's easy to figure out when its done the thing
|
||||||
|
if (rms < 0){ rms = 999; } //need to text nxdn with this setup to make sure it isn't broken in Windows Cygwin now
|
||||||
|
return rms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void full_demod(struct demod_state *d)
|
void full_demod(struct demod_state *d)
|
||||||
@@ -1108,13 +1114,14 @@ void rtl_dev_tune(dsd_opts * opts, long int frequency)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//return RMS value (root means square) power level -- used as soft squelch inside of framesync
|
//return RMS value (root means square) power level -- used as soft squelch inside of framesync
|
||||||
int rtl_return_rms()
|
long int rtl_return_rms()
|
||||||
{
|
{
|
||||||
int sr = 0;
|
long int sr = 0;
|
||||||
|
#ifdef __arm__
|
||||||
|
sr = 100;
|
||||||
|
#else
|
||||||
sr = rms(demod.lowpassed, demod.lp_len, 1);
|
sr = rms(demod.lowpassed, demod.lp_len, 1);
|
||||||
// 'Fix' potential negative value overflow from the rms function -- Observed in Windows builds
|
#endif
|
||||||
sr = abs(sr);
|
|
||||||
if (sr > 9999) sr = 9999;
|
|
||||||
return (sr);
|
return (sr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
538
src/trellis.cpp
538
src/trellis.cpp
@@ -1,538 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 by Jonathan Naylor, G4KLX
|
|
||||||
*
|
|
||||||
* Heavy Modificatins of Original Code to work for DSD-FME
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; version 2 of the License.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
#include "dsd.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
const unsigned int INTERLEAVE_TABLE[] = {
|
|
||||||
0U, 1U, 8U, 9U, 16U, 17U, 24U, 25U, 32U, 33U, 40U, 41U, 48U, 49U, 56U, 57U, 64U, 65U, 72U, 73U, 80U, 81U, 88U, 89U, 96U, 97U,
|
|
||||||
2U, 3U, 10U, 11U, 18U, 19U, 26U, 27U, 34U, 35U, 42U, 43U, 50U, 51U, 58U, 59U, 66U, 67U, 74U, 75U, 82U, 83U, 90U, 91U,
|
|
||||||
4U, 5U, 12U, 13U, 20U, 21U, 28U, 29U, 36U, 37U, 44U, 45U, 52U, 53U, 60U, 61U, 68U, 69U, 76U, 77U, 84U, 85U, 92U, 93U,
|
|
||||||
6U, 7U, 14U, 15U, 22U, 23U, 30U, 31U, 38U, 39U, 46U, 47U, 54U, 55U, 62U, 63U, 70U, 71U, 78U, 79U, 86U, 87U, 94U, 95U};
|
|
||||||
|
|
||||||
const unsigned char ENCODE_TABLE[] = {
|
|
||||||
0U, 8U, 4U, 12U, 2U, 10U, 6U, 14U,
|
|
||||||
4U, 12U, 2U, 10U, 6U, 14U, 0U, 8U,
|
|
||||||
1U, 9U, 5U, 13U, 3U, 11U, 7U, 15U,
|
|
||||||
5U, 13U, 3U, 11U, 7U, 15U, 1U, 9U,
|
|
||||||
3U, 11U, 7U, 15U, 1U, 9U, 5U, 13U,
|
|
||||||
7U, 15U, 1U, 9U, 5U, 13U, 3U, 11U,
|
|
||||||
2U, 10U, 6U, 14U, 0U, 8U, 4U, 12U,
|
|
||||||
6U, 14U, 0U, 8U, 4U, 12U, 2U, 10U};
|
|
||||||
|
|
||||||
const unsigned char DECODE_TABLE[] = { //flip the rows and columns, right?
|
|
||||||
0,4,1,5,3,7,2,6,
|
|
||||||
8,12,9,13,11,15,10,14,
|
|
||||||
4,2,5,3,7,1,6,0,
|
|
||||||
12,10,13,11,15,9,14,8,
|
|
||||||
2,6,3,7,1,5,0,4,
|
|
||||||
10,14,11,15,9,13,8,12,
|
|
||||||
6,0,7,1,5,3,4,2,
|
|
||||||
14,8,15,9,13,11,12,10
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
|
||||||
|
|
||||||
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
|
||||||
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
|
||||||
|
|
||||||
unsigned char state = 0U;
|
|
||||||
//rework quickHamming to accept unsigned intergers instead and go bit by bit
|
|
||||||
int quickHamming(unsigned int butt, unsigned int farts)
|
|
||||||
{
|
|
||||||
unsigned int i = 0, count = 0, shit = 0, shart = 0;
|
|
||||||
//fprintf (stderr, "Distance Compare %X - %X \n", butt, farts );
|
|
||||||
for (i; i < 3; i++) //shift three places tops;
|
|
||||||
{
|
|
||||||
shit = (butt >> i) & 0b1;
|
|
||||||
shart = (farts >> i) & 0b1;
|
|
||||||
if (shit != shart)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload)
|
|
||||||
{
|
|
||||||
//unsigned int bestPos = 0U;
|
|
||||||
//unsigned int bestVal = 0U;
|
|
||||||
|
|
||||||
for (unsigned j = 0U; j < 20U; j++) {
|
|
||||||
unsigned int bestPos = 0U;
|
|
||||||
unsigned int bestVal = 0U;
|
|
||||||
//fprintf (stderr, " fail%d-", failPos);
|
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < 16U; i++) {
|
|
||||||
points[failPos] = i;
|
|
||||||
|
|
||||||
//fprintf (stderr, "i%d", i);
|
|
||||||
|
|
||||||
unsigned char tribits[49U];
|
|
||||||
unsigned int pos = CDMRTrellisCheckCode(points, tribits);
|
|
||||||
if (pos == 999U) {
|
|
||||||
CDMRTrellisTribitsToBits(tribits, payload);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos > bestPos) {
|
|
||||||
bestPos = pos;
|
|
||||||
bestVal = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
points[failPos] = bestVal;
|
|
||||||
failPos = bestPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char bits[144];
|
|
||||||
for (int i = 0; i < 48; i++) {
|
|
||||||
bits[(i * 3) + 0] = (tribits[i] >> 2) & 1;
|
|
||||||
bits[(i * 3) + 1] = (tribits[i] >> 1) & 1;
|
|
||||||
bits[(i * 3) + 2] = tribits[i] & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// convert bits to bytes
|
|
||||||
//fprintf (stderr, "\n Tribit Binary Sequence\n ");
|
|
||||||
for (short i = 0; i < 144; i++)
|
|
||||||
{
|
|
||||||
//fprintf (stderr, "%b", bits[i]);
|
|
||||||
}
|
|
||||||
for(short int i = 0; i < 18; i++)
|
|
||||||
{
|
|
||||||
payload[i] = (bits[i * 8 + 0] << 7) | (bits[i * 8 + 1] << 6) | (bits[i * 8 + 2] << 5) | (bits[i * 8 + 3] << 4) |
|
|
||||||
(bits[i * 8 + 4] << 3) | (bits[i * 8 + 5] << 2) | (bits[i * 8 + 6] << 1) | (bits[i * 8 + 7] << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//for (int i = 0; i < 144; i++)
|
|
||||||
//payload[i/8] = (payload[i/8] << 1) | bits[i];
|
|
||||||
//DmrDataBit[j + 0] = (TrellisReturn[17-i] >> 0) & 0x01; //example
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits)
|
|
||||||
{
|
|
||||||
|
|
||||||
//unsigned char state = 0U; //move outside of function to preserve state for every iteration
|
|
||||||
//let's try reversing the points to pass through the decode table instead of flipping them here,
|
|
||||||
//it may mess up the fixcode and failpos POS
|
|
||||||
state = 0U;
|
|
||||||
for (unsigned int i = 0U; i < 49U;) //total number of points to process
|
|
||||||
{
|
|
||||||
tribits[i] = 9U;
|
|
||||||
for (unsigned int j = 0U; j < 8U; j++)
|
|
||||||
{
|
|
||||||
//if (points[i] == DECODE_TABLE[state * 8U + j])
|
|
||||||
//if (points[48-i] == DECODE_TABLE[state * 8U + j])
|
|
||||||
if (points[i] == ENCODE_TABLE[state * 8U + j])
|
|
||||||
{
|
|
||||||
tribits[i] = j;
|
|
||||||
state = tribits[i]; //carry over if found right away
|
|
||||||
i++; //increment i by one value
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//try to find shortest distance for surviving paths and decide on one
|
|
||||||
//seems to be that two paths will have distance value 1, and two will have distance value 2
|
|
||||||
//need to keep totaling up a few rounds before we can eliminate a path and resume?
|
|
||||||
if (tribits[i] == 9U)
|
|
||||||
{
|
|
||||||
int distance = 0;
|
|
||||||
int maxdistance = 99; //random metric for two position distance
|
|
||||||
int pathdistance = 0;
|
|
||||||
unsigned int match = 0;
|
|
||||||
unsigned int nextmatch = 0;
|
|
||||||
unsigned int q = 0;
|
|
||||||
//only 4 possible states for each point, but in 8 (0-7) FSM states
|
|
||||||
char path[99][99] = {0}; //[i][pathcount] = distance
|
|
||||||
int pathcount = 0;
|
|
||||||
for (unsigned int o = 0; o < 64; o++) //check entire state transition table for matches
|
|
||||||
{
|
|
||||||
if (points[i] == ENCODE_TABLE[o]) //ENCODE TABLE
|
|
||||||
{
|
|
||||||
match = o / (unsigned int)8; //get dividend no remainder/decimal I hope, get fsm state 0-7
|
|
||||||
//fprintf (stderr, "\n Point #%d [%d] Match State %d Position %d Tribit Value %d \n", i, points[i], match, o, o % (unsigned int)8);
|
|
||||||
distance = quickHamming(match, state);
|
|
||||||
//fprintf (stderr, "Raw Distance Current %d\n", distance);
|
|
||||||
path[i][pathcount] = distance ; //save which table values (paths) match as possible values and distance
|
|
||||||
for (q; q < 64; q++) //check entire state transition table for next point match
|
|
||||||
{
|
|
||||||
if (points[i+1] == ENCODE_TABLE[q]) //ENCODE TABLE
|
|
||||||
{
|
|
||||||
nextmatch = q / (unsigned int)8;
|
|
||||||
path[i+1][pathcount] = quickHamming(nextmatch, q % (unsigned int)8);
|
|
||||||
//fprintf (stderr, "Raw Distance Next %d\n", path[i+1][pathcount]);
|
|
||||||
pathcount++;
|
|
||||||
//fprintf (stderr, "State 0 Match %d Distance %d \n", o, distance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (short int z = 0; z <= pathcount; z++) //add metrics on paths to find shortest distance
|
|
||||||
{
|
|
||||||
pathdistance = path[i][0] + path[i+1][z];
|
|
||||||
//fprintf (stderr, "Total Path Distance %d\n", pathdistance);
|
|
||||||
if (pathdistance <= maxdistance) //equal too in case of tie?
|
|
||||||
{
|
|
||||||
maxdistance = pathdistance;
|
|
||||||
tribits[i] = o % (unsigned int)8; //remainder value will be tribit value on table
|
|
||||||
if (i < 49) //just in case we are on 49 already, don't want to crash or something.
|
|
||||||
{
|
|
||||||
tribits[i+1] = q % (unsigned int)8; //remainder value will be tribit value on table
|
|
||||||
}
|
|
||||||
|
|
||||||
//fprintf (stderr, "Point #%d [%d] - Tribit Candidate %d\n", i, points[i], tribits[i] );
|
|
||||||
//fprintf (stderr, "Point #%d [%d]- Tribit Candidate %d\n", i+1, points[i+1], tribits[i+1] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//fprintf (stderr, "Selected Point #%d [%d] - Tribit Selection %d\n", i, points[i], tribits[i] );
|
|
||||||
//fprintf (stderr, "Selected Point #%d [%d]- Tribit Selection %d\n", i+1, points[i+1], tribits[i+1] );
|
|
||||||
}
|
|
||||||
state = tribits[i+1]; //not quite sure if this will be needed or not, if so, set state to last found value
|
|
||||||
i += 2; //increment i by two since we already got the next tribit value as well;
|
|
||||||
//state = tribits[i]; //not quite sure if this will be needed or not, if so, set state to last found value
|
|
||||||
//i++; //increment i by two since we already got the next tribit value as well;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return 999U;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
//can only assume this is giving the correct dibits out, and not inverse or something.
|
|
||||||
/*
|
|
||||||
for (int i = 0; i < 98; i++) {
|
|
||||||
n = i * 2;
|
|
||||||
if (n >= 98) n += 68;
|
|
||||||
bool b1 = data[n] != 0x0;
|
|
||||||
|
|
||||||
n = i * 2 + 1;
|
|
||||||
if (n >= 98) n += 68;
|
|
||||||
bool b2 = data[n] != 0x0;
|
|
||||||
|
|
||||||
if (!b1 && b2)
|
|
||||||
dibit = +3; // 1 - 01
|
|
||||||
else if (!b1 && !b2)
|
|
||||||
dibit = +1; // 0 - 00
|
|
||||||
else if (b1 && !b2)
|
|
||||||
dibit = -1; // 2 - 10
|
|
||||||
else
|
|
||||||
dibit = -3; // 3 - 11
|
|
||||||
|
|
||||||
*/
|
|
||||||
//Keep it simple!
|
|
||||||
for (int i = 0; i < 98; i++)
|
|
||||||
{
|
|
||||||
n = INTERLEAVE_TABLE[97-i];
|
|
||||||
//n = i;
|
|
||||||
if (data[i] == 0)
|
|
||||||
{
|
|
||||||
dibits[n] = 1; //1
|
|
||||||
}
|
|
||||||
if (data[i] == 1)
|
|
||||||
{
|
|
||||||
dibits[n] = 3; //3
|
|
||||||
}
|
|
||||||
if (data[i] == 2)
|
|
||||||
{
|
|
||||||
dibits[n] = -1; //-1
|
|
||||||
}
|
|
||||||
if (data[i] == 3)
|
|
||||||
{
|
|
||||||
dibits[n] = -3; //-3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//n = INTERLEAVE_TABLE[i]; //should this go in reverse?
|
|
||||||
//n = INTERLEAVE_TABLE[97-i]; //should this go in reverse?
|
|
||||||
//dibits[n] = dibit; //should this go in reverse too? not sure on this one, but definitely the INTERLEAVE_TABLE
|
|
||||||
//n = INTERLEAVE_TABLE[97-i]; //should this go in reverse?
|
|
||||||
//dibits[97-n] = dibit;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0U; i < 49U; i++) {
|
|
||||||
if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -1)
|
|
||||||
points[i] = 0U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -1)
|
|
||||||
points[i] = 1U;
|
|
||||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -3)
|
|
||||||
points[i] = 2U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -3)
|
|
||||||
points[i] = 3U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -1)
|
|
||||||
points[i] = 4U;
|
|
||||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -1)
|
|
||||||
points[i] = 5U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -3)
|
|
||||||
points[i] = 6U;
|
|
||||||
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -3)
|
|
||||||
points[i] = 7U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +3)
|
|
||||||
points[i] = 8U;
|
|
||||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +3)
|
|
||||||
points[i] = 9U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +1)
|
|
||||||
points[i] = 10U;
|
|
||||||
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +1)
|
|
||||||
points[i] = 11U;
|
|
||||||
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +3)
|
|
||||||
points[i] = 12U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +3)
|
|
||||||
points[i] = 13U;
|
|
||||||
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +1)
|
|
||||||
points[i] = 14U;
|
|
||||||
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +1)
|
|
||||||
points[i] = 15U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0U; i < 49U; i++) {
|
|
||||||
switch (points[i]) {
|
|
||||||
case 0U:
|
|
||||||
dibits[i * 2U + 0U] = +1;
|
|
||||||
dibits[i * 2U + 1U] = -1;
|
|
||||||
break;
|
|
||||||
case 1U:
|
|
||||||
dibits[i * 2U + 0U] = -1;
|
|
||||||
dibits[i * 2U + 1U] = -1;
|
|
||||||
break;
|
|
||||||
case 2U:
|
|
||||||
dibits[i * 2U + 0U] = +3;
|
|
||||||
dibits[i * 2U + 1U] = -3;
|
|
||||||
break;
|
|
||||||
case 3U:
|
|
||||||
dibits[i * 2U + 0U] = -3;
|
|
||||||
dibits[i * 2U + 1U] = -3;
|
|
||||||
break;
|
|
||||||
case 4U:
|
|
||||||
dibits[i * 2U + 0U] = -3;
|
|
||||||
dibits[i * 2U + 1U] = -1;
|
|
||||||
break;
|
|
||||||
case 5U:
|
|
||||||
dibits[i * 2U + 0U] = +3;
|
|
||||||
dibits[i * 2U + 1U] = -1;
|
|
||||||
break;
|
|
||||||
case 6U:
|
|
||||||
dibits[i * 2U + 0U] = -1;
|
|
||||||
dibits[i * 2U + 1U] = -3;
|
|
||||||
break;
|
|
||||||
case 7U:
|
|
||||||
dibits[i * 2U + 0U] = +1;
|
|
||||||
dibits[i * 2U + 1U] = -3;
|
|
||||||
break;
|
|
||||||
case 8U:
|
|
||||||
dibits[i * 2U + 0U] = -3;
|
|
||||||
dibits[i * 2U + 1U] = +3;
|
|
||||||
break;
|
|
||||||
case 9U:
|
|
||||||
dibits[i * 2U + 0U] = +3;
|
|
||||||
dibits[i * 2U + 1U] = +3;
|
|
||||||
break;
|
|
||||||
case 10U:
|
|
||||||
dibits[i * 2U + 0U] = -1;
|
|
||||||
dibits[i * 2U + 1U] = +1;
|
|
||||||
break;
|
|
||||||
case 11U:
|
|
||||||
dibits[i * 2U + 0U] = +1;
|
|
||||||
dibits[i * 2U + 1U] = +1;
|
|
||||||
break;
|
|
||||||
case 12U:
|
|
||||||
dibits[i * 2U + 0U] = +1;
|
|
||||||
dibits[i * 2U + 1U] = +3;
|
|
||||||
break;
|
|
||||||
case 13U:
|
|
||||||
dibits[i * 2U + 0U] = -1;
|
|
||||||
dibits[i * 2U + 1U] = +3;
|
|
||||||
break;
|
|
||||||
case 14U:
|
|
||||||
dibits[i * 2U + 0U] = +3;
|
|
||||||
dibits[i * 2U + 1U] = +1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dibits[i * 2U + 0U] = -3;
|
|
||||||
dibits[i * 2U + 1U] = +1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0U; i < 48U; i++) {
|
|
||||||
unsigned int n = 143U - i * 3U;
|
|
||||||
|
|
||||||
bool b1 = READ_BIT(payload, n) != 0x00U;
|
|
||||||
n--;
|
|
||||||
bool b2 = READ_BIT(payload, n) != 0x00U;
|
|
||||||
n--;
|
|
||||||
bool b3 = READ_BIT(payload, n) != 0x00U;
|
|
||||||
|
|
||||||
unsigned char tribit = 0U;
|
|
||||||
tribit |= b1 ? 4U : 0U;
|
|
||||||
tribit |= b2 ? 2U : 0U;
|
|
||||||
tribit |= b3 ? 1U : 0U;
|
|
||||||
|
|
||||||
//tribits[i] = tribit;
|
|
||||||
}
|
|
||||||
|
|
||||||
tribits[48U] = 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload)
|
|
||||||
{
|
|
||||||
assert(data != NULL);
|
|
||||||
assert(payload != NULL);
|
|
||||||
unsigned char tribits[49U];
|
|
||||||
for (short i = 0; i < 49; i++)
|
|
||||||
{
|
|
||||||
tribits[i] = 0; //initialize with 0 values so we know later on if these values are actually being assigned or not
|
|
||||||
}
|
|
||||||
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n Raw Trellis Dibits inside Decoder\n ");
|
|
||||||
for (short i = 0; i < 98; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "#%d [%0d] ", i, data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signed char dibits[98U];
|
|
||||||
CDMRTrellisDeinterleave(data, dibits);
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n Trellis Deinterleaved Dibits inside Decoder (converted to signed)\n ");
|
|
||||||
for (short i = 0; i < 98; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "#%d [%d] ", i, dibits[i]); //signed char, values should be -3, -1, 1, 3 only
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsigned char points[49U];
|
|
||||||
// unsigned char reverse_points[49U];
|
|
||||||
CDMRTrellisDibitsToPoints(dibits, points);
|
|
||||||
//maybe keep point 49 at 49, since its the flush?
|
|
||||||
//fprintf (stderr, "\n Trellis Reverse Points inside Decoder\n ");
|
|
||||||
// for (short i = 0; i < 49; i++)
|
|
||||||
// {
|
|
||||||
// reverse_points[i] = points[48-i];
|
|
||||||
// //fprintf (stderr, "#%d [%02u] ", i, reverse_points[i]);
|
|
||||||
// }
|
|
||||||
//reverse_points[48] = points[48];
|
|
||||||
//fprintf (stderr, "#%d [%02u] ", 48, reverse_points[48]);
|
|
||||||
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n Trellis Points inside Decoder\n ");
|
|
||||||
for (short i = 0; i < 49; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "#%d [%02u] ", i, points[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check the original code
|
|
||||||
|
|
||||||
unsigned int failPos = CDMRTrellisCheckCode(points, tribits);
|
|
||||||
//unsigned int failPos = CDMRTrellisCheckCode(reverse_points, tribits); //stack smashing detected terminated
|
|
||||||
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n Check Code Trellis Tribits inside Decoder\n ");
|
|
||||||
for (short i = 0; i < 49; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failPos == 999U)
|
|
||||||
{
|
|
||||||
CDMRTrellisTribitsToBits(tribits, payload);
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\nTrellis Payload Tribits\n %s ", KCYN);
|
|
||||||
for (short i = 0; i < 49; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\nTrellis Payload Tribits to Bytes inside Decoder\n %s ", KCYN);
|
|
||||||
for (short i = 0; i < 18; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "[%02X]", payload[i]);
|
|
||||||
}
|
|
||||||
fprintf (stderr,"%s", KNRM); //change back to normal
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char savePoints[49U];
|
|
||||||
for (unsigned int i = 0U; i < 49U; i++)
|
|
||||||
savePoints[i] = points[i];
|
|
||||||
//savePoints[i] = reverse_points[i];
|
|
||||||
|
|
||||||
bool ret = CDMRTrellisFixCode(points, failPos, payload);
|
|
||||||
//bool ret = CDMRTrellisFixCode(reverse_points, failPos, payload);
|
|
||||||
if (ret){
|
|
||||||
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n if return Trellis Tribits inside Decoder\n ");
|
|
||||||
for (short i = 0; i < 49; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\nTrellis Payload Tribits to Bits fix return true\n "); //this one seems to be happening
|
|
||||||
for (short i = 0; i < 18; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "[%02X]", payload[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true; }
|
|
||||||
|
|
||||||
if (failPos == 0U)
|
|
||||||
{
|
|
||||||
if (1 == 2)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\nTrellis Payload Tribits to Bytes failPos == 0U\n ");
|
|
||||||
for (short i = 0; i < 18; i++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "[%02X]", payload[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false; }
|
|
||||||
|
|
||||||
// Backtrack one place for a last go
|
|
||||||
return CDMRTrellisFixCode(savePoints, failPos - 1U, payload);
|
|
||||||
}
|
|
||||||
@@ -812,7 +812,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
//print some useful decoded stuff
|
//print some useful decoded stuff
|
||||||
if (dt == 0 && err == 0) fprintf (stderr, "V/D1 "); //Voice/Data Type 1
|
if (dt == 0 && err == 0) fprintf (stderr, "V/D1 "); //Voice/Data Type 1
|
||||||
if (dt == 1 && err == 0) fprintf (stderr, "DATA "); //Full Rate Voice
|
if (dt == 1 && err == 0) fprintf (stderr, "DATA "); //Full Rate Data
|
||||||
if (dt == 2 && err == 0) fprintf (stderr, "V/D2 "); //Voice/Data Type 2
|
if (dt == 2 && err == 0) fprintf (stderr, "V/D2 "); //Voice/Data Type 2
|
||||||
if (dt == 3 && err == 0) fprintf (stderr, "VWFR "); //Full Rate Voice
|
if (dt == 3 && err == 0) fprintf (stderr, "VWFR "); //Full Rate Voice
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user