35 Commits

Author SHA1 Message Date
lwvmobile
57629cefe4 Version/Date Update; 2023-08-27 15:06:32 -04:00
lwvmobile
fe3a135a92 Disable DMR MS/Simplex When Trunking Enabled; 2023-08-26 21:23:56 -04:00
lwvmobile
8d33c2b3d1 DMR SB TXI Tweaks; Add CRC4 Check to LE MI; 2023-08-26 17:28:06 -04:00
lwvmobile
593ffbbd66 DMR LE Minor Code Fix; Print Tweaks; 2023-08-26 09:32:40 -04:00
lwvmobile
592d57ad87 Fix M17 IV; 2023-08-25 09:16:34 -04:00
lwvmobile
9a31678d9a Fix M17 Enc Type Values; 2023-08-25 09:12:51 -04:00
lwvmobile
7b3a257df8 Fix EDACS Analog Call Preemption Conditions; 2023-08-22 09:21:03 -04:00
lwvmobile
55e792a925 Disable RTL RMS Function on ARM Devices (RPi); 2023-08-19 20:58:30 -04:00
lwvmobile
755f77f96c Temp Fix for EDACS Standard/Networked; 2023-08-19 12:45:22 -04:00
lwvmobile
1c17757a4e DMR 3/4 Simple Error Correction; 2023-08-19 07:43:30 -04:00
lwvmobile
abe2e61cf2 P25p2 I-ISCH/DUID Error Correction; 2023-08-17 13:44:22 -04:00
lwvmobile
c404825451 Analog Monitor Hold on SQL Break; Misc; 2023-08-13 11:43:04 -04:00
lwvmobile
769168da5b Prevent Possible Overflow in lbuf and lbuf2; 2023-08-11 14:59:50 -04:00
lwvmobile
14284c3cf1 More Cygwin M17 Related Bandaids; 2023-08-11 14:59:14 -04:00
lwvmobile
51f971b68d Update Install Notes and Include Arch Installer; 2023-08-11 12:52:28 -04:00
lwvmobile
02fdb7cd90 Fix Some NXDN Array Sizes and Chainbacks; 2023-08-11 12:21:22 -04:00
lwvmobile
64541a1958 M17 Misc Cleanup; 2023-08-11 12:20:47 -04:00
lwvmobile
0a675d3f0f Misc Code Cleanup; 2023-08-10 14:44:16 -04:00
lwvmobile
e79b6fd231 Simplify DMR Trellis Decoder; 2023-08-10 03:47:08 -04:00
lwvmobile
d356ed0dbc Add M17 CAN Value to Ncurses; Misc; 2023-08-09 20:54:07 -04:00
lwvmobile
495eb71090 Fixed Wrong Line; Fix the Correct Line This Time; 2023-08-09 04:10:03 -04:00
lwvmobile
6bf96f1df5 Forgot something; 2023-08-09 04:08:11 -04:00
lwvmobile
3a2db53c3b Fix RTL Source Audio Monitoring Bug; 2023-08-09 04:05:43 -04:00
lwvmobile
e038016c30 Fix Pulse Audio Output Source Monitor; 2023-08-09 02:16:12 -04:00
lwvmobile
7d6269efad WIP: Source Audio Monitoring on V2.1b; 2023-08-09 01:14:00 -04:00
lwvmobile
152f0ea7f6 EDACS Tweaks to Analog Call Handling; 2023-08-08 01:06:48 -04:00
lwvmobile
13443a25f3 Fix Annoying Alignment Issues; 2023-08-07 04:14:33 -04:00
lwvmobile
528f7294d9 Experimental EDACS Analog Voice Monitoring; 2023-08-07 03:48:39 -04:00
lwvmobile
83e3fa1061 Fix RTL RMS so it does't return Jank Values; 2023-08-07 03:43:39 -04:00
lwvmobile
9b3a2d96e3 Fix Some DateName Issues for dates in Aero; 2023-08-07 03:42:11 -04:00
lwvmobile
0829cdbdb0 Update Example_Usage for Icecast; #159 2023-08-07 03:38:15 -04:00
lwvmobile
9541aef382 Merge pull request #159 from francisuk1989/v2.1b-1
Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
2023-08-05 16:38:35 -04:00
lwvmobile
4caf6bb153 Update Example_Usage.md 2023-08-05 16:37:00 -04:00
Francis
dd77273218 Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
For them who wont to send audio to a icecast 2 server via WIndows.
2023-08-05 20:38:15 +01:00
lwvmobile
3bd3edb36f Fix Cygwin/Aero/OSS/M17 Junk; 2023-07-26 18:43:52 -04:00
28 changed files with 1186 additions and 1335 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ build
examples
*.bin
*.ans
*.patch

View File

@@ -31,12 +31,6 @@ if (PVC)
add_definitions(-DPVCONVENTIONAL)
endif ()
#use cmake option -DNXDN=ON to enable the old NXDN Sync Pattern
option(NXDN
"Build with Old NXDN Sync Pattern Enabled" OFF)
if (NXDN)
add_definitions(-DNXDNOLDSYNC)
endif ()
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
option(LZ
@@ -52,13 +46,6 @@ if (TN)
add_definitions(-DTONES)
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)
git_describe(GIT_TAG)

View 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

View File

@@ -100,7 +100,7 @@ and in a second terminal tab, same folder, run
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`
@@ -191,4 +191,35 @@ e - Toggle Trunking Tuning to Encrypted Calls (P25)
9 - Connect to SDR++ RIGCTL Server with Defaults/Retry RIGCTL Connection
D - Reset DMR Site Parms/Call Strings, etc.
Z - Simulate NoCarrier/No VC/CC sync (capital Z)
```
```
## 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
```

View File

@@ -11,8 +11,18 @@ wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/main/download-and-insta
chmod +x download-and-install.sh
./download-and-install.sh
```
f
If you have dependencies already installed (i.e. need a fresh clean install on a system with DSD-FME already or using system other than Debian/Ubuntu, etc), please run this instead:
### 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
@@ -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
```
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
```
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
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.

View File

@@ -274,7 +274,7 @@ typedef struct
int rtl_udp_port;
int rtl_bandwidth;
int rtl_started;
int rtl_rms;
long int rtl_rms;
int monitor_input_audio;
int pulse_raw_rate_in;
int pulse_raw_rate_out;
@@ -414,6 +414,10 @@ typedef struct
float *audio_out_temp_buf_p;
float audio_out_temp_bufR[160];
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_idx2;
int audio_out_idxR;
@@ -733,6 +737,7 @@ typedef struct
unsigned long long int m17_dst;
unsigned long long int m17_src;
uint8_t m17_can;
char m17_dst_csd[20];
char m17_src_csd[20];
@@ -740,7 +745,7 @@ typedef struct
char m17_src_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_st; //scrambler or data subtye
@@ -944,7 +949,6 @@ short nxdn_filter(short sample);
short dpmr_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);
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_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]);
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
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
@@ -1073,7 +1079,8 @@ uint8_t crc8(uint8_t bits[], unsigned int len);
bool crc8_ok(uint8_t bits[], unsigned int len);
//modified CRC functions for SB/RC
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/
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 rtlsdr_sighandler();
void rtl_dev_tune(dsd_opts * opts, long int frequency);
int rtl_return_rms();
long int rtl_return_rms();
void rtl_clean_queue();
#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
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME
int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
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 crc16_lb_bridge (int payload[190], int len);
int crc12_xb_bridge (int payload[190], int len);

136
src/dmr_34.c Normal file
View 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);
}

View File

@@ -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)
{
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 1;
bool trellis_good = TRUE;
uint8_t tdibits[98];
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++)
{
tdibits[97-i] = (info[i*2] << 1) | info[i*2+1];
}
tdibits[i] = (info[i*2] << 1) | info[i*2+1];
unsigned char TrellisReturn[18];
uint8_t TrellisReturn[18];
memset (TrellisReturn, 0, sizeof(TrellisReturn));
IrrecoverableErrors = dmr_34(tdibits, TrellisReturn);
trellis_good = CDMRTrellisDecode(tdibits, TrellisReturn);
if (trellis_good == TRUE) IrrecoverableErrors = 0;
// else (fprintf (stderr, " Trellis Failure")); //debug print
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
//they may have been successfully corrected, the CRC will reveal as much
for (i = 0; i < pdu_len; i++) //18
{
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
}
for (i = 0; i < pdu_len; i++)
DMR_PDU[i] = TrellisReturn[i+pdu_start];
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;
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
//confirmed working now!
for(i = 0; i < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
@@ -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;
}
else
{
// IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix
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;
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, " (FEC ERR)");

View File

@@ -51,6 +51,12 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
uint64_t go_test = 0;
uint64_t mi_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) |
(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) |
@@ -77,12 +83,22 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
mi_corrected |= mi_go_bits[i];
go_corrected = go_corrected << 1;
go_corrected |= mi_go_bits[i+12];
//manipulate for crc check
mi_bits[i+(j*12)] = mi_go_bits[i];
}
}
int mi_final = 0;
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 (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)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_mi, mi_final);
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;
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
else fprintf (stderr, "(CRC ERR)");
fprintf (stderr, "\n");
fprintf (stderr, "%s", KNRM);
}
//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)
{
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;
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
else fprintf (stderr, "(CRC ERR)");
fprintf (stderr, "\n");
fprintf (stderr, "%s", KNRM);
}
//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 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 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) )
{
//opcodes -- 0 (NULL), BR Delay (3)
fprintf (stderr, "\n");
fprintf (stderr, " TXI Op: %X - ", sbrc_opcode);
if (opts->payload == 0) fprintf (stderr, "\n");
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " TXI Op: %X -", sbrc_opcode);
if (sbrc_opcode == 0) fprintf (stderr, " Null; ");
else if (sbrc_opcode == 3)
{
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;");
//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; ");
fprintf (stderr, "%s", KNRM);
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
@@ -325,12 +355,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
if (state->M == 0)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
// fprintf (stderr, "\n");
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
fprintf (stderr, "%s ", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
state->payload_keyid = key;
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)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
// fprintf (stderr, "\n");
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
fprintf (stderr, "%s ", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
state->payload_keyidR = key;
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;
}
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
}

View File

@@ -26,9 +26,11 @@ void closePulseOutput (dsd_opts * opts)
{
pa_simple_free (opts->pulse_digi_dev_out);
if (opts->dmr_stereo == 1)
{
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)
@@ -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.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
if (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);
}
//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, "Analog", &ss, 0, NULL, NULL);
//tt
pa_channel_map* left = 0; //NULL and 0 are same in this context

View File

@@ -34,7 +34,11 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
}
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;
struct tm * to;
time_t t;

View File

@@ -177,19 +177,19 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
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->slot2light, " slot2 ");
//we can safely open MBE on any MS or mono handling
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
dmrMSBootstrap (opts, state);
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
}
if (opts->dmr_mono == 1 && state->synctype == 32)
{
//we can safely open MBE on any MS or mono handling
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
dmrMSBootstrap (opts, state);
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
}
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
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
}
@@ -207,7 +207,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
dmrMSData (opts, state);
if (opts->p25_trunk == 0) dmrMSData (opts, state);
}
else
{
@@ -219,7 +219,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->err_str[0] = 0;
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync
dmr_data_sync (opts, state);
}
//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
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync
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))
{
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)
processM17STR(opts, state);
else

View File

@@ -18,39 +18,6 @@
#include "dsd.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
{
time_t t = time(NULL);
@@ -67,7 +34,11 @@ char * getTime(void) //get pretty hh:mm:ss timestamp
}
char * getDate(void) {
char datename[32];
#ifdef AERO_BUILD
char datename[80];
#else
char datename[99];
#endif
char * curr2;
struct tm * to;
time_t t;
@@ -209,7 +180,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
char synctest[25];
char synctest12[13]; //dPMR
char synctest10[11]; //NXDN FSW only
char synctest19[20]; //NXDN Preamble + FSW
char synctest18[19];
char synctest32[33];
char synctest20[21]; //YSF
@@ -250,7 +220,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
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;
char spectrum[64];
//init the lbuf
@@ -740,10 +710,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
fprintf (stderr, " P2 Missing Parameters ");
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);
return (35); //35
}
@@ -779,10 +745,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
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);
return (36); //36
}
@@ -814,10 +776,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 21;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (21);
}
if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
@@ -850,10 +808,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
state->lastsynctype = 25;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (25);
}
if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
@@ -892,20 +846,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1;
}
state->lastsynctype = 33; //33
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (33); //33
}
else //inverted MS voice frame
{
sprintf(state->ftype, "DMR MS");
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (32);
}
}
@@ -932,10 +878,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1;
}
state->lastsynctype = 34;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (34);
}
}
@@ -961,20 +903,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1;
}
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (32);
}
else //inverted MS data frame
{
sprintf(state->ftype, "DMR MS");
state->lastsynctype = 33;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (33);
}
@@ -997,10 +931,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
}
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);
return (10);
}
@@ -1017,10 +947,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
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);
return (11); //11
}
@@ -1042,10 +968,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
}
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);
return (33);
}
@@ -1062,10 +984,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
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);
return (32);
}
@@ -1087,10 +1005,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
}
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);
return (33);
}
@@ -1107,10 +1021,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
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);
return (32);
}
@@ -1136,10 +1046,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
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);
return (12);
}
@@ -1153,10 +1059,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
}
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);
return (13);
}
@@ -1182,10 +1084,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
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);
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->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (32);
}
@@ -1238,10 +1132,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
}
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);
return (33);
}
@@ -1319,11 +1209,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+D-STAR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 6;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (6);
}
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);
}
state->lastsynctype = 7;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (7);
}
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);
}
state->lastsynctype = 18;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (18);
}
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);
}
state->lastsynctype = 19;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (19);
}
}
#ifdef NXDNOLDSYNC //Use FSW vs strncmperr method
//NXDN FSW sync and handling - moved to very bottom of sync stack for falsing sanity
//NXDN
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
//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 (
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|| (strcmp (synctest10, "3131331111") == 0 )
|| (strcmp (synctest10, "3331331111") == 0 )
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|| (strcmp (synctest10, "3131331111") == 0 )
|| (strcmp (synctest10, "3331331111") == 0 )
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
)
)
{
// state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
// state->last_cc_sync_time = time(NULL);
if (state->lastsynctype == 28)
{
state->last_cc_sync_time = time(NULL);
// if (opts->payload == 1)
// fprintf (stderr, "\n +FSW ");
// if (opts->payload == 1)
// fprintf (stderr, " %s \n", synctest10);
return (28);
}
state->lastsynctype = 28;
@@ -1549,36 +1283,27 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
else if (
(strcmp (synctest10, "1313113313") == 0 )
|| (strcmp (synctest10, "1113113313") == 0 )
|| (strcmp (synctest10, "1313113333") == 0 )
|| (strcmp (synctest10, "1113113333") == 0 )
|| (strcmp (synctest10, "1313133313") == 0 ) //
(strcmp (synctest10, "1313113313") == 0 )
|| (strcmp (synctest10, "1113113313") == 0 )
|| (strcmp (synctest10, "1313113333") == 0 )
|| (strcmp (synctest10, "1113113333") == 0 )
|| (strcmp (synctest10, "1313133313") == 0 )
)
{
// state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
// state->last_cc_sync_time = time(NULL);
if (state->lastsynctype == 29)
{
state->last_cc_sync_time = time(NULL);
// if (opts->payload == 1)
// fprintf (stderr, "\n -FSW ");
// if (opts->payload == 1)
// fprintf (stderr, " %s \n", synctest10);
return (29);
}
state->lastsynctype = 29;
}
}
#endif //NXDN Sync Type Selection
//Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible
#ifdef PVCONVENTIONAL
if (opts->frame_provoice == 1)

View File

@@ -467,6 +467,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
state->m17_dst = 0;
state->m17_src = 0;
state->m17_can = 0;
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
sprintf (state->m17_dst_str, "%s", "");
@@ -621,7 +622,7 @@ initOpts (dsd_opts * opts)
opts->dmr_mute_encL = 1;
opts->dmr_mute_encR = 1;
opts->monitor_input_audio = 0;
opts->monitor_input_audio = 0; //enable with -8
opts->inverted_p2 = 0;
opts->p2counter = 0;
@@ -715,6 +716,11 @@ initState (dsd_state * state)
//Upsampled Audio Smoothing
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_bufR = malloc (sizeof (short) * 1000000);
memset (state->audio_out_buf, 0, 100 * sizeof (short));
@@ -1064,6 +1070,7 @@ initState (dsd_state * state)
state->m17_dst = 0;
state->m17_src = 0;
state->m17_can = 0;
memset(state->m17_dst_csd, 0, sizeof(state->m17_dst_csd));
memset(state->m17_src_csd, 0, sizeof(state->m17_src_csd));
sprintf (state->m17_dst_str, "%s", "");
@@ -1129,6 +1136,8 @@ usage ()
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
printf (" -w <file> Output synthesized speech to a .wav file, legacy auto modes only.\n");
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 (" (Per Call can only be used in Ncurses Terminal!)\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 (" -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 (" -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 (" -b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
printf (" (NOTE: This used to be the 'K' option! \n");
@@ -1230,9 +1237,6 @@ usage ()
printf (" \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 (" -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 (" Trunking Options:\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 (" 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 (" -9 Force Enable EDACS Standard or Networked Mode on Systems without a netcmd (temp fix) \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 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);
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
@@ -1319,6 +1330,13 @@ if (opts->audio_out_type == 0)
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)
{
@@ -1450,12 +1468,16 @@ main (int argc, char **argv)
}
#ifdef AERO_BUILD
fprintf (stderr, "Build Version: v2.1b (20230714)\n");
fprintf (stderr, "Build Version: v2.1b (20230901)\n");
#else
fprintf (stderr, "Build Version: %s \n", GIT_TAG);
#endif
fprintf (stderr,"MBElib Version: %s\n", versionstr);
#ifdef USE_CODEC2
fprintf (stderr,"CODEC2 Support Enabled\n");
#endif
initOpts (&opts);
initState (&state);
@@ -1463,7 +1485,7 @@ main (int argc, char **argv)
exitflag = 0;
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:YK: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;
switch (c)
@@ -1485,6 +1507,17 @@ main (int argc, char **argv)
//NOTE: The 'K' option for single BP key has been swapped to 'b'
//'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)
case '0':
state.M = 0x21;
@@ -1899,6 +1932,7 @@ main (int argc, char **argv)
sprintf (opts.output_name, "EDACS/PV");
fprintf (stderr,"Setting symbol rate to 9600 / second\n");
fprintf (stderr,"Decoding only ProVoice frames.\n");
fprintf (stderr,"EDACS Analog Voice Channels are Experimental.\n");
//rtl specific tweaks
opts.rtl_bandwidth = 24;
// 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
}
//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)
speed = 8000;
#endif
if((strncmp(opts.audio_out_dev, "/dev/audio", 10) == 0))
{

View File

@@ -582,7 +582,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
state->dropL += 7;
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.
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;
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.
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;
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.
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;
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.
short b = 0; //reset b to use again

View File

@@ -248,7 +248,11 @@ void beeper (dsd_opts * opts, dsd_state * state, int type)
#endif
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;
struct tm * to;
time_t t;
@@ -274,9 +278,9 @@ char * getTimeN(void) //get pretty hh:mm:ss timestamp
return curr;
}
//this version is broken now in Cygwin with the 80 value, reverted back
char * getDateC(time_t t) {
char datename[99]; //Ubuntu 32-bit, use 80; everything else, use 99
char datename[99];
char * curr2;
struct tm * to;
@@ -2225,7 +2229,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->ncurses_compact == 1)
{
printw ("------------------------------------------------------------------------------\n");
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.1b (20230714)");
printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "v2.1b (20230901)");
printw ("------------------------------------------------------------------------------\n");
}
#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 ("------------------------------------------------------------------------------\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
if (opts->ncurses_compact == 1)
{
@@ -2258,13 +2255,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw("%s", FM_bannerN[i]);
if (i == 1) printw (" ESC to Menu");
if (i == 2) printw (" 'q' to Quit ");
if (i == 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
if (i == 5) printw (" %s ", "Aero Build");
if (i == 6) printw (" v2.1b (20230714) \n");
#elif ZDEV_BUILD
if (i == 5) printw (" %s ", "zDEV Build");
if (i == 6) printw (" %s \n", GIT_TAG);
if (i == 6) printw (" v2.1b (20230901) \n");
#else
if (i == 5) printw (" %s ", "Main Build");
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 (" PPM: %i;", opts->rtlsdr_ppm_error);
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 (" FRQ: %i;", opts->rtlsdr_center_freq);
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");
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)
{
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");
printw (" \n");
}
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)
{
@@ -2481,14 +2485,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
{
printw ("| ");
printw ("M17 - ");
printw ("M17: ");
//insert data type and frame information
if (state->m17_str_dt == 0) printw("Reserved");
if (state->m17_str_dt == 1) printw("Data ");
if (state->m17_str_dt == 2) printw("Voice (3200) ");
if (state->m17_str_dt == 3) printw("Voice (1600) + Data");
printw (" ");
printw ("\n");
printw ("| ");
@@ -2499,11 +2502,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
else if (state->m17_dst != 0 && state->m17_dst >= 0xEE6B28000000)
printw("RESERVED (%012llx) ", state->m17_dst);
else
{
// for (i = 0; i < 9; i++)
// printw ("%c", state->m17_dst_csd[i]);
printw("%s", state->m17_dst_str);
}
printw ("\n");
printw ("| ");
@@ -2512,23 +2511,25 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (state->m17_src != 0 && state->m17_src >= 0xEE6B28000000)
printw("RESERVED (%012llx)", state->m17_src);
else
{
// for (i = 0; i < 9; i++)
// printw ("%c", state->m17_src_csd[i]);
printw("%s", state->m17_src_str);
}
printw ("\n");
printw ("| ");
printw ("CAN: %02d ", state->m17_can);
printw ("\n");
printw ("| ");
//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);
}
if (state->m17_enc == 1)
if (state->m17_enc == 2)
{
printw (" AES-CTR - IV: ");
//display packed meta as IV

View File

@@ -17,6 +17,29 @@
#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
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)
{
#ifdef USE_RTLSDR
// TODO: need to read demodulated stream here
// get_rtlsdr_sample(&sample);
// Read demodulated stream here
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();
#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 ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33

View File

@@ -14,12 +14,16 @@
* 1994-7
*
* LWVMOBILE
* 2022-10 Version EDACS-FM Florida Man Edition
* 2023-08 Version EDACS-FM Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
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;
struct tm * to;
time_t t;
@@ -45,6 +49,191 @@ char * getTimeE(void) //get pretty hh:mm:ss timestamp
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)
{
//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 mt1 = 0x1F;
unsigned char mt2 = 0xF;
unsigned char mta = 0;
unsigned char lcn = 0;
//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
int i, j;
int i;
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
@@ -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
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
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
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
{
state->esk_mask = 0x0;
state->esk_mask = 0x0;
}
}
}
//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)) )
{
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
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
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);
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
@@ -292,8 +481,9 @@ void edacs(dsd_opts * opts, dsd_state * state)
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
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
@@ -302,6 +492,8 @@ void edacs(dsd_opts * opts, dsd_state * state)
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
//debug testing (since I don't have EDACS standard w/ Analog nearby)
// edacs_analog(opts, state, group, lcn);
#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)
{
//no handling for raw audio yet...that works properly atleast
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");
//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
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
{
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
}
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 (command == 0xEF) openWavOutFile (opts, state); //digital
if (command == 0xEE) openWavOutFile48k (opts, state); //analog at 48k
}
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);
}
@@ -460,7 +663,9 @@ void edacs(dsd_opts * opts, dsd_state * state)
} //end Standard or Networked
}
}
ENDPV:
fprintf (stderr, "\n");

View File

@@ -178,146 +178,166 @@ int ez_rs28_sacch (int payload[180], int parity[132])
return (ec);
}
//I-ISCH Lookup section, borrowed from OP25
std::map <std::string, int> isch_map;
std::map <std::uint64_t, int> isch_map;
void map_isch()
{
isch_map["184229d461"] = 0;
isch_map["18761451f6"] = 1;
isch_map["181ae27e2f"] = 2;
isch_map["182edffbb8"] = 3;
isch_map["18df8a7510"] = 4;
isch_map["18ebb7f087"] = 5;
isch_map["188741df5e"] = 6;
isch_map["18b37c5ac9"] = 7;
isch_map["1146a44f13"] = 8;
isch_map["117299ca84"] = 9;
isch_map["111e6fe55d"] = 10;
isch_map["112a5260ca"] = 11;
isch_map["11db07ee62"] = 12;
isch_map["11ef3a6bf5"] = 13;
isch_map["1183cc442c"] = 14;
isch_map["11b7f1c1bb"] = 15;
isch_map["1a4a2e239e"] = 16;
isch_map["1a7e13a609"] = 17;
isch_map["1a12e589d0"] = 18;
isch_map["1a26d80c47"] = 19;
isch_map["1ad78d82ef"] = 20;
isch_map["1ae3b00778"] = 21;
isch_map["1a8f4628a1"] = 22;
isch_map["1abb7bad36"] = 23;
isch_map["134ea3b8ec"] = 24;
isch_map["137a9e3d7b"] = 25;
isch_map["13166812a2"] = 26;
isch_map["1322559735"] = 27;
isch_map["13d300199d"] = 28;
isch_map["13e73d9c0a"] = 29;
isch_map["138bcbb3d3"] = 30;
isch_map["13bff63644"] = 31;
isch_map["1442f705ef"] = 32;
isch_map["1476ca8078"] = 33;
isch_map["141a3cafa1"] = 34;
isch_map["142e012a36"] = 35;
isch_map["14df54a49e"] = 36;
isch_map["14eb692109"] = 37;
isch_map["14879f0ed0"] = 38;
isch_map["14b3a28b47"] = 39;
isch_map["1d467a9e9d"] = 40;
isch_map["1d72471b0a"] = 41;
isch_map["1d1eb134d3"] = 42;
isch_map["1d2a8cb144"] = 43;
isch_map["1ddbd93fec"] = 44;
isch_map["1defe4ba7b"] = 45;
isch_map["1d831295a2"] = 46;
isch_map["1db72f1035"] = 47;
isch_map["164af0f210"] = 48;
isch_map["167ecd7787"] = 49;
isch_map["16123b585e"] = 50;
isch_map["162606ddc9"] = 51;
isch_map["16d7535361"] = 52;
isch_map["16e36ed6f6"] = 53;
isch_map["168f98f92f"] = 54;
isch_map["16bba57cb8"] = 55;
isch_map["1f4e7d6962"] = 56;
isch_map["1f7a40ecf5"] = 57;
isch_map["1f16b6c32c"] = 58;
isch_map["1f228b46bb"] = 59;
isch_map["1fd3dec813"] = 60;
isch_map["1fe7e34d84"] = 61;
isch_map["1f8b15625d"] = 62;
isch_map["1fbf28e7ca"] = 63;
isch_map["84d62c339"] = 64;
isch_map["8795f46ae"] = 65;
isch_map["815a96977"] = 66;
isch_map["82194ece0"] = 67;
isch_map["8d0c16248"] = 68;
isch_map["8e4fce7df"] = 69;
isch_map["8880ac806"] = 70;
isch_map["8bc374d91"] = 71;
isch_map["149ef584b"] = 72;
isch_map["17dd2dddc"] = 73;
isch_map["11124f205"] = 74;
isch_map["125197792"] = 75;
isch_map["1d44cf93a"] = 76;
isch_map["1e0717cad"] = 77;
isch_map["18c875374"] = 78;
isch_map["1b8bad6e3"] = 79;
isch_map["a456534c6"] = 80;
isch_map["a7158b151"] = 81;
isch_map["a1dae9e88"] = 82;
isch_map["a29931b1f"] = 83;
isch_map["ad8c695b7"] = 84;
isch_map["aecfb1020"] = 85;
isch_map["a800d3ff9"] = 86;
isch_map["ab430ba6e"] = 87;
isch_map["341e8afb4"] = 88;
isch_map["375d52a23"] = 89;
isch_map["3192305fa"] = 90;
isch_map["32d1e806d"] = 91;
isch_map["3dc4b0ec5"] = 92;
isch_map["3e8768b52"] = 93;
isch_map["38480a48b"] = 94;
isch_map["3b0bd211c"] = 95;
isch_map["44dbc12b7"] = 96;
isch_map["479819720"] = 97;
isch_map["41577b8f9"] = 98;
isch_map["4214a3d6e"] = 99;
isch_map["4d01fb3c6"] = 100;
isch_map["4e4223651"] = 101;
isch_map["488d41988"] = 102;
isch_map["4bce99c1f"] = 103;
isch_map["d493189c5"] = 104;
isch_map["d7d0c0c52"] = 105;
isch_map["d11fa238b"] = 106;
isch_map["d25c7a61c"] = 107;
isch_map["dd49228b4"] = 108;
isch_map["de0afad23"] = 109;
isch_map["d8c5982fa"] = 110;
isch_map["db864076d"] = 111;
isch_map["645bbe548"] = 112;
isch_map["6718660df"] = 113;
isch_map["61d704f06"] = 114;
isch_map["6294dca91"] = 115;
isch_map["6d8184439"] = 116;
isch_map["6ec25c1ae"] = 117;
isch_map["680d3ee77"] = 118;
isch_map["6b4ee6be0"] = 119;
isch_map["f41367e3a"] = 120;
isch_map["f750bfbad"] = 121;
isch_map["f19fdd474"] = 122;
isch_map["f2dc051e3"] = 123;
isch_map["fdc95df4b"] = 124;
isch_map["fe8a85adc"] = 125;
isch_map["f845e7505"] = 126;
isch_map["fb063f092"] = 127;
isch_map[0x184229d461ULL] = 0;
isch_map[0x18761451f6ULL] = 1;
isch_map[0x181ae27e2fULL] = 2;
isch_map[0x182edffbb8ULL] = 3;
isch_map[0x18df8a7510ULL] = 4;
isch_map[0x18ebb7f087ULL] = 5;
isch_map[0x188741df5eULL] = 6;
isch_map[0x18b37c5ac9ULL] = 7;
isch_map[0x1146a44f13ULL] = 8;
isch_map[0x117299ca84ULL] = 9;
isch_map[0x111e6fe55dULL] = 10;
isch_map[0x112a5260caULL] = 11;
isch_map[0x11db07ee62ULL] = 12;
isch_map[0x11ef3a6bf5ULL] = 13;
isch_map[0x1183cc442cULL] = 14;
isch_map[0x11b7f1c1bbULL] = 15;
isch_map[0x1a4a2e239eULL] = 16;
isch_map[0x1a7e13a609ULL] = 17;
isch_map[0x1a12e589d0ULL] = 18;
isch_map[0x1a26d80c47ULL] = 19;
isch_map[0x1ad78d82efULL] = 20;
isch_map[0x1ae3b00778ULL] = 21;
isch_map[0x1a8f4628a1ULL] = 22;
isch_map[0x1abb7bad36ULL] = 23;
isch_map[0x134ea3b8ecULL] = 24;
isch_map[0x137a9e3d7bULL] = 25;
isch_map[0x13166812a2ULL] = 26;
isch_map[0x1322559735ULL] = 27;
isch_map[0x13d300199dULL] = 28;
isch_map[0x13e73d9c0aULL] = 29;
isch_map[0x138bcbb3d3ULL] = 30;
isch_map[0x13bff63644ULL] = 31;
isch_map[0x1442f705efULL] = 32;
isch_map[0x1476ca8078ULL] = 33;
isch_map[0x141a3cafa1ULL] = 34;
isch_map[0x142e012a36ULL] = 35;
isch_map[0x14df54a49eULL] = 36;
isch_map[0x14eb692109ULL] = 37;
isch_map[0x14879f0ed0ULL] = 38;
isch_map[0x14b3a28b47ULL] = 39;
isch_map[0x1d467a9e9dULL] = 40;
isch_map[0x1d72471b0aULL] = 41;
isch_map[0x1d1eb134d3ULL] = 42;
isch_map[0x1d2a8cb144ULL] = 43;
isch_map[0x1ddbd93fecULL] = 44;
isch_map[0x1defe4ba7bULL] = 45;
isch_map[0x1d831295a2ULL] = 46;
isch_map[0x1db72f1035ULL] = 47;
isch_map[0x164af0f210ULL] = 48;
isch_map[0x167ecd7787ULL] = 49;
isch_map[0x16123b585eULL] = 50;
isch_map[0x162606ddc9ULL] = 51;
isch_map[0x16d7535361ULL] = 52;
isch_map[0x16e36ed6f6ULL] = 53;
isch_map[0x168f98f92fULL] = 54;
isch_map[0x16bba57cb8ULL] = 55;
isch_map[0x1f4e7d6962ULL] = 56;
isch_map[0x1f7a40ecf5ULL] = 57;
isch_map[0x1f16b6c32cULL] = 58;
isch_map[0x1f228b46bbULL] = 59;
isch_map[0x1fd3dec813ULL] = 60;
isch_map[0x1fe7e34d84ULL] = 61;
isch_map[0x1f8b15625dULL] = 62;
isch_map[0x1fbf28e7caULL] = 63;
isch_map[0x084d62c339ULL] = 64;
isch_map[0x08795f46aeULL] = 65;
isch_map[0x0815a96977ULL] = 66;
isch_map[0x082194ece0ULL] = 67;
isch_map[0x08d0c16248ULL] = 68;
isch_map[0x08e4fce7dfULL] = 69;
isch_map[0x08880ac806ULL] = 70;
isch_map[0x08bc374d91ULL] = 71;
isch_map[0x0149ef584bULL] = 72;
isch_map[0x017dd2dddcULL] = 73;
isch_map[0x011124f205ULL] = 74;
isch_map[0x0125197792ULL] = 75;
isch_map[0x01d44cf93aULL] = 76;
isch_map[0x01e0717cadULL] = 77;
isch_map[0x018c875374ULL] = 78;
isch_map[0x01b8bad6e3ULL] = 79;
isch_map[0x0a456534c6ULL] = 80;
isch_map[0x0a7158b151ULL] = 81;
isch_map[0x0a1dae9e88ULL] = 82;
isch_map[0x0a29931b1fULL] = 83;
isch_map[0x0ad8c695b7ULL] = 84;
isch_map[0x0aecfb1020ULL] = 85;
isch_map[0x0a800d3ff9ULL] = 86;
isch_map[0x0ab430ba6eULL] = 87;
isch_map[0x0341e8afb4ULL] = 88;
isch_map[0x0375d52a23ULL] = 89;
isch_map[0x03192305faULL] = 90;
isch_map[0x032d1e806dULL] = 91;
isch_map[0x03dc4b0ec5ULL] = 92;
isch_map[0x03e8768b52ULL] = 93;
isch_map[0x038480a48bULL] = 94;
isch_map[0x03b0bd211cULL] = 95;
isch_map[0x044dbc12b7ULL] = 96;
isch_map[0x0479819720ULL] = 97;
isch_map[0x041577b8f9ULL] = 98;
isch_map[0x04214a3d6eULL] = 99;
isch_map[0x04d01fb3c6ULL] = 100;
isch_map[0x04e4223651ULL] = 101;
isch_map[0x0488d41988ULL] = 102;
isch_map[0x04bce99c1fULL] = 103;
isch_map[0x0d493189c5ULL] = 104;
isch_map[0x0d7d0c0c52ULL] = 105;
isch_map[0x0d11fa238bULL] = 106;
isch_map[0x0d25c7a61cULL] = 107;
isch_map[0x0dd49228b4ULL] = 108;
isch_map[0x0de0afad23ULL] = 109;
isch_map[0x0d8c5982faULL] = 110;
isch_map[0x0db864076dULL] = 111;
isch_map[0x0645bbe548ULL] = 112;
isch_map[0x06718660dfULL] = 113;
isch_map[0x061d704f06ULL] = 114;
isch_map[0x06294dca91ULL] = 115;
isch_map[0x06d8184439ULL] = 116;
isch_map[0x06ec25c1aeULL] = 117;
isch_map[0x0680d3ee77ULL] = 118;
isch_map[0x06b4ee6be0ULL] = 119;
isch_map[0x0f41367e3aULL] = 120;
isch_map[0x0f750bfbadULL] = 121;
isch_map[0x0f19fdd474ULL] = 122;
isch_map[0x0f2dc051e3ULL] = 123;
isch_map[0x0fdc95df4bULL] = 124;
isch_map[0x0fe8a85adcULL] = 125;
isch_map[0x0f845e7505ULL] = 126;
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
char s[64];
int decoded = -2; //initialize lookup to an invalid number
sprintf(s, "%llx", isch);
decoded = isch_map[s];
return(decoded);
}
map_isch(); //initialize the lookup map
int decoded = -2;
// Must contain bit errors if no exact match, so
// look for codeword with smallest hamming distance
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;
}

203
src/m17.c
View File

@@ -40,11 +40,32 @@ uint8_t m17_scramble[369] = {
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
uint8_t p1[62] = {
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1,
1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 1, 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
//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)
@@ -136,7 +157,7 @@ void M17decodeLSF(dsd_state * state)
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
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_et = (lsf_type >> 3) & 0x3;
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
@@ -147,17 +168,16 @@ void M17decodeLSF(dsd_state * state)
state->m17_str_dt = lsf_dt;
state->m17_dst = lsf_dst;
state->m17_src = lsf_src;
state->m17_can = lsf_cn;
fprintf (stderr, "\n");
//packet or stream
if (lsf_ps == 0) fprintf (stderr, " P-");
if (lsf_ps == 1) fprintf (stderr, " S-");
// if (lsf_ps == 0) fprintf (stderr, " P-");
// if (lsf_ps == 1) fprintf (stderr, " S-");
fprintf (stderr, " CAN: %d", lsf_cn);
M17decodeCSD(state, lsf_dst, lsf_src);
if (lsf_et != 0) fprintf (stderr, " ENC");
if (lsf_dt == 0) fprintf (stderr, " Reserved");
if (lsf_dt == 1) fprintf (stderr, " Data");
@@ -166,8 +186,9 @@ void M17decodeLSF(dsd_state * state)
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
if (lsf_et == 1) fprintf (stderr, " AES-CTR");
if (lsf_et == 2) fprintf (stderr, " Scrambler - %d", lsf_es);
if (lsf_et != 0) fprintf (stderr, " ENC:");
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_st = lsf_es;
@@ -186,16 +207,16 @@ void M17decodeLSF(dsd_state * state)
if (lsf_es == 3) fprintf (stderr, " Reserved");
}
if (lsf_et == 1)
if (lsf_et == 2)
{
fprintf (stderr, " IV: ");
for (i = 0; i < 14; i++)
for (i = 0; i < 16; 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;
err = 0;
@@ -292,14 +313,10 @@ int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t lich_bits[96])
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;
unsigned char voice1[8]; //codec2_bytes_per_frame
unsigned char voice1[8];
unsigned char voice2[8];
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
size_t nsam;
nsam = 320; //codec2_samples_per_frame(state->codec2_1600);
short samp1[nsam];
// short samp2[nsam];
memset (samp1, 0, sizeof(samp1));
// memset (samp2, 0, sizeof(samp2));
nsam = 160;
//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, samp2, voice2);
if (opts->audio_out_type == 0 && state->m17_enc == 0)
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
{
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)
{
write (opts->audio_out_fd, samp1, nsam*2);
// write (opts->audio_out_fd, samp2, nsam*2);
}
#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);
}
#endif
//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, samp2, nsam);
}
//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
}
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;
unsigned char voice1[8]; //codec2_bytes_per_frame
unsigned char voice1[8];
unsigned char voice2[8];
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
size_t nsam;
nsam = 160; //codec2_samples_per_frame(state->codec2_3200);
short samp1[nsam];
short samp2[nsam];
memset (samp1, 0, sizeof(samp1));
memset (samp2, 0, sizeof(samp2));
nsam = 160;
//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, samp2, voice2);
if (opts->audio_out_type == 0 && state->m17_enc == 0)
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
{
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];
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, samp2, nsam*2);
}
//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, 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
}
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;
uint8_t m17_punc[310]; //25 * 11 = 275
int i, k, x;
uint8_t m17_punc[275]; //25 * 11 = 275
memset (m17_punc, 0, sizeof(m17_punc));
for (i = 0; i < 272; i++)
m17_punc[i] = m17_bits[i+96];
//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));
k = 0; x = 0;
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 s1;
uint8_t m_data[28];
uint8_t trellis_buf[400];
uint8_t trellis_buf[144];
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
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];
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)
fprintf (stderr, " FSN: %05d", fn);
@@ -550,13 +622,7 @@ void processM17STR(dsd_opts * opts, dsd_state * state)
{
int i, x;
//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
//overflow/memory issue returns in Cygwin for...reasons...
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_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)
{
//NOTE1: Pretty sure the flow here is all correct, but the initial (and only)
//LSF frame is demodulated incorrectly, so more than likely, this frame will
//always be bad since there is only one sent before STR
//NOTE2: Even with the preamble detection and LSF sync, we still get bad decode on this
//NOTE: Have not been able to get this to work successfully, but considering
//there is only one LSF frame at the beginning of TX, its probably just as easy to
//use and rely on the STR frame and embedded LSF chunk, which does work properly
int i, j, k, x;
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)
@@ -673,8 +736,8 @@ void processM17LSF(dsd_opts * opts, dsd_state * state)
uint8_t temp[500];
uint8_t s0;
uint8_t s1;
uint8_t m_data[32];
uint8_t trellis_buf[400];
uint8_t m_data[30];
uint8_t trellis_buf[240]; //30*8 = 240
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));

View File

@@ -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])
{
uint8_t deperm[200]; //144
uint8_t depunc[200]; //192
uint8_t trellis_buf[400]; //96
uint8_t deperm[144]; //144
uint8_t depunc[192]; //192
uint8_t trellis_buf[96]; //96
uint16_t crc = 0; //crc calculated by function
uint16_t check = 0; //crc from payload for comparison
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
uint8_t temp[210];
uint8_t temp[200];
uint8_t s0;
uint8_t s1;
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));
for (int i = 0; i < 192; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+192] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 100U; i++)
for (int i = 0; i < 96; i++)
{
s0 = temp[(2*i)];
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_chainback(m_data, 96U);
CNXDNConvolution_chainback(m_data, 92);
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);
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)
{
@@ -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])
{
//see about initializing these variables
uint8_t deperm[200]; //60
uint8_t depunc[200]; //72
uint8_t trellis_buf[400]; //32
uint8_t deperm[60]; //60
uint8_t depunc[72]; //72
uint8_t trellis_buf[32]; //32
memset (deperm, 0, sizeof(deperm));
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
uint8_t temp[90];
uint8_t temp[80];
uint8_t s0;
uint8_t s1;
uint8_t m_data[10]; //5
uint8_t m_data[5]; //5
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 72; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+72] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 36U; i++) //40
for (int i = 0; i < 36; i++)
{
s0 = temp[(2*i)];
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
CNXDNConvolution_chainback(m_data, 32U); //36
CNXDNConvolution_chainback(m_data, 32);
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);
else fprintf (stderr, " ");
uint8_t nsf_sacch[400];
uint8_t nsf_sacch[26];
memset (nsf_sacch, 0, sizeof(nsf_sacch));
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)
{
uint8_t deperm[500]; //348
uint8_t depunc[500]; //406
uint8_t trellis_buf[400]; //199
uint8_t deperm[348]; //348
uint8_t depunc[406]; //406
uint8_t trellis_buf[208]; //199
int id = 0;
uint16_t crc = 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
uint8_t temp[500]; //220, this one was way too small
uint8_t temp[406];
uint8_t s0;
uint8_t s1;
uint8_t m_data[52]; //26
uint8_t m_data[26]; //26
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
for (int i = 0; i < 406; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+203] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 207U; i++)
for (int i = 0; i < 203; i++)
{
s0 = temp[(2*i)];
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
CNXDNConvolution_chainback(m_data, 203U);
CNXDNConvolution_chainback(m_data, 199);
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,
//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];
}
@@ -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 == 0) ; //need handling for user data (text messages and AVL)
}
else if (opts->aggressive_framesync == 0)
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
// else if (opts->aggressive_framesync == 0)
// {
// 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 (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])
{
uint8_t deperm[500]; //300
uint8_t depunc[500]; //350
uint8_t trellis_buf[400]; //171
uint8_t deperm[300]; //300
uint8_t depunc[350]; //350
uint8_t trellis_buf[176]; //176
int id = 0;
int ran = 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
uint8_t temp[360];
uint8_t temp[179];
uint8_t s0;
uint8_t s1;
uint8_t m_data[52]; //26
uint8_t m_data[22]; //26
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
for (int i = 0; i < 350; i++)
{
temp[i] = depunc[i] << 1;
}
CNXDNConvolution_start();
for (int i = 0U; i < 179U; i++)
for (int i = 0; i < 175; i++) //179
{
s0 = temp[(2*i)];
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_chainback(m_data, 175U);
CNXDNConvolution_chainback(m_data, 171); //175
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);
uint8_t cac_message_buffer[400]; //171
uint8_t cac_message_buffer[147]; //171
memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field
for (int i = 0; i < 160; i++)
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field and ending crc
for (int i = 0; i < 147; i++)
{
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);
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)
{
@@ -618,9 +595,9 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
fprintf (stderr, " SCCH");
//see about initializing these variables
uint8_t deperm[200]; //60
uint8_t depunc[200]; //72
uint8_t trellis_buf[400]; //32
uint8_t deperm[60]; //60
uint8_t depunc[72]; //72
uint8_t trellis_buf[32]; //32
memset (deperm, 0, sizeof(deperm));
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
uint8_t temp[90];
uint8_t temp[72];
uint8_t s0;
uint8_t s1;
uint8_t m_data[10]; //5
uint8_t m_data[5]; //5
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 72; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+72] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 36U; i++)
for (int i = 0; i < 36; i++)
{
s0 = temp[(2*i)];
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_chainback(m_data, 32U);
CNXDNConvolution_chainback(m_data, 32);
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
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);
@@ -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)
{
uint8_t deperm[300]; //144
uint8_t depunc[300]; //192
uint8_t trellis_buf[600]; //96
uint8_t deperm[144]; //144
uint8_t depunc[192]; //192
uint8_t trellis_buf[96]; //96
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached
uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
uint16_t crc[2]; //crc calculated by function
@@ -767,10 +737,10 @@ void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[2
int out;
//switch to the convolutional decoder
uint8_t temp[500];
uint8_t temp[192];
uint8_t s0;
uint8_t s1;
uint8_t m_data[40]; //13
uint8_t m_data[12]; //13
memset (temp, 0, sizeof(temp));
memset (m_data, 0, sizeof(m_data));
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++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+192] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 100U; i++)
for (int i = 0; i < 96; i++)
{
s0 = temp[(2*i)];
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_chainback(m_data, 96U);
CNXDNConvolution_chainback(m_data, 92);
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 == 0) ; //need handling for user data (text messages and AVL)
}
else if (opts->aggressive_framesync == 0)
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
// else if (opts->aggressive_framesync == 0)
// {
// if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
// if (type == 0) {} //need handling for user data (text messages and AVL)
// }
if (opts->payload == 1)
{

View File

@@ -14,8 +14,8 @@
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
{
uint8_t SACCH[400]; //72
uint8_t sacch_bytes[10];
uint8_t SACCH[72]; //72
uint8_t sacch_bytes[9];
uint32_t i;
uint8_t CrcCorrect = 1;
@@ -38,7 +38,7 @@ void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state)
/* Decodes the element content */
// currently only going to run this if all four CRCs are good
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
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));

View File

@@ -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
sprintf (state->call_string[0], "%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;
}

View File

@@ -446,4 +446,9 @@ processTDULC (dsd_opts* opts, dsd_state* state)
sprintf (state->call_string[0], "%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;
}

View File

@@ -75,7 +75,7 @@ int dibit = 0;
int vc_counter = 0;
int framing_counter = 0;
unsigned long long int isch = 0;
uint64_t isch = 0;
int isch_decoded = -1;
int p2_duid[8] = {0};
int16_t duid_decoded = 0;

View File

@@ -463,11 +463,14 @@ void dc_block_filter(struct demod_state *fm)
}
fm->dc_avg = avg;
}
int rms(int16_t *samples, int len, int step)
//TODO: Fix This so we don't get random negative values in Cygwin (or 32-bit builds?)
//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 */
{
int i;
long int rms;
long p, t, s;
double dc, err;
@@ -481,7 +484,10 @@ int rms(int16_t *samples, int len, int step)
dc = (double)(t*step) / (double)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)
@@ -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
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);
// 'Fix' potential negative value overflow from the rms function -- Observed in Windows builds
sr = abs(sr);
if (sr > 9999) sr = 9999;
#endif
return (sr);
}

View File

@@ -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);
}

View File

@@ -812,7 +812,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
//print some useful decoded stuff
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 == 3 && err == 0) fprintf (stderr, "VWFR "); //Full Rate Voice