mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 16:57:23 -05:00
commit 833e0173f24b12a12ff80f9a35fb43107d355cc3 Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 26 22:51:02 2024 -0400 Fix Slot Preference Depending on Build; commit 716577ab09c0cee68bca3bcdcbaaa7cfa3be4f97 Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 26 22:27:24 2024 -0400 M17 - Voice Playback Only If Enabled; Misc; commit c0f9818cf38ce7f127370f19ec4afa2457cef19a Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 26 17:39:34 2024 -0400 Add DMR/P25p2 Stereo Channel Patch; commit 1a0baf0a17ccf8cc0eb0a01a809269354480d1d1 Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 26 17:37:46 2024 -0400 Add DMR Cap+ Faster Rest Patch; commit 9f5b52aa8f20bfe3eab5413f2c3fa41003d53b3c Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 26 17:36:24 2024 -0400 Disable EDACS Analog Debug; commit 7dd0de67b602f0acd111200f838fbb1a0541a8bf Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 26 17:36:04 2024 -0400 Squashed commit of the following: commit 95d46fb35d6cb6fb0a9825084f4c2accf8edad4a Author: lwvmobile <lwvmobile@gmail.com> Date: Mon Mar 25 17:48:57 2024 -0400 Enable HPF_D by default; Increase manual analog gain to 50; commit 1f37837664e16760b5cbf5653fc4d829ee6cce83 Author: lwvmobile <lwvmobile@gmail.com> Date: Mon Mar 25 08:43:17 2024 -0400 Enable HPF_D on M17 Voice; commit9bbe4de7fdAuthor: lwvmobile <lwvmobile@gmail.com> Date: Sun Mar 24 16:08:16 2024 -0400 EDACS: Digitize Analog For Analysis of 'Data Burst' Like Behavior; commit9249b7a943Author: lwvmobile <lwvmobile@gmail.com> Date: Sun Mar 24 12:28:26 2024 -0400 Simply Mono Short Playback; commit89ad0f17e3Author: lwvmobile <lwvmobile@gmail.com> Date: Sat Mar 23 21:12:44 2024 -0400 Add HPF to SS4, SS3, and SS Audio Methods; commite8184c7fbdAuthor: lwvmobile <lwvmobile@gmail.com> Date: Sat Mar 23 17:13:44 2024 -0400 RTL - Add The Sample / Volume Multiplier as a user configurable option; commitee04d11116Author: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 23:15:04 2024 -0400 Fix HPF_D so it actually works correctly; commite549b21497Author: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 20:11:34 2024 -0400 Make Analog Auto Gain Control Mostly Tolerable; commit2f9e0525feAuthor: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 18:20:38 2024 -0400 User Toggle HPF on Digital; commitff58d3a6faAuthor: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 18:10:15 2024 -0400 User Toggles and Displays for Filters; commitb6fc17c506Author: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 15:55:09 2024 -0400 More Analog Manual Audio Gain Tweaks; commit076b9fbf04Author: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 06:26:10 2024 -0400 Add SQL Hit on EDACS if Colors Disabled; commit59fe47ef05Author: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 02:23:08 2024 -0400 Disable HPF Test on Digital Voice; commit4a63068ce1Author: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 23:39:43 2024 -0400 Misc Code Organizing; audio_gainA Tweaks; commit3585e7e594Author: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 13:18:31 2024 -0400 Test Tweak to RTL Sample Multiplier; commitfa5b25283fAuthor: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 13:18:07 2024 -0400 Adjust Manual Mic Gain on M17 Encoder; Ncurses Display; commitc985fea035Author: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 12:34:01 2024 -0400 Misc Notes on using raw_rms values during testing; commitb273e5b7beAuthor: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 12:31:33 2024 -0400 Bugfix for EDACS Analog Segfault when using the digitize function for an extended period; commiteadf3fdf23Author: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 10:12:04 2024 -0400 Analog Gain Has Own Variable; Ncurses Keys; Misc; commit0debcc647eAuthor: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 08:49:51 2024 -0400 Filtering Misc Cleanup; commit98e10b2627Author: lwvmobile <lwvmobile@gmail.com> Date: Thu Mar 21 00:02:21 2024 -0400 Automatic Gain On Analog WIP; Manual Gain Control; commit89736ae543Author: lwvmobile <lwvmobile@gmail.com> Date: Wed Mar 20 10:22:20 2024 -0400 Passband Filter Testing on Raw Analog / EDACS / M17 Encoder; commit43f6218129Author: lwvmobile <lwvmobile@gmail.com> Date: Wed Mar 20 09:03:02 2024 -0400 Passband and Notch Filter Setup; Debug Output; commit35a1b53867Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 19 22:35:36 2024 -0400 HPF: Only Use On RTL Input when M17 Encoder Uses It; commitb9949f0d80Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 19 17:31:59 2024 -0400 Disable LFP on EDACS Analog Out; commit3666740674Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 19 13:42:07 2024 -0400 Test HPF On Digital Voice Out; commitef13343925Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 19 12:46:27 2024 -0400 RTL_FM Input for Analog/M17 Encoder; commit2b7de90474Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 19 11:03:55 2024 -0400 New Analog Audio Filters WIP; commit 3b9f9f5a3befb295da284379262323fad7d69c7a Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 26 17:33:34 2024 -0400 Squashed commit of the following: commit a5c5be3b955a82cc72f1486ff87d7c1b4893295f Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Tue Mar 26 17:28:35 2024 -0400 EDACS: Standard display rewrite, parsing/RE fixes, tune i-calls and all-calls (#246) * EDACS EA: Fix reversed TDMA/data calls * EDACS: deduplicate ncurses printing logic * EDACS: pass call state via new state struct field * EDACS: RE some differences from Standard spec * EDACS: show state for data calls * EDACS: tune individual calls on Standard * EDACS: tune all-calls on Standard * EDACS: properly identify emergency on channel updates * EDACS: fix build break * EDACS: fix conditions for refreshing the display source * EDACS EA: Identify calls as voice for display * EDACS: voice channel update emergency refactor * EDACS: Show interconnect calls in call log * EDACS EA: show unknown data channel assignments in log * EDACS: check LCN is not 0 before assigning it * EDACS: C operator precedence is dumb * Initialize edacs_vc_call_type * use j and not i in call_matrix for call history; --------- Co-authored-by: lwvmobile <lwvmobile@gmail.com> commitc8d00846b1Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sun Mar 24 17:48:46 2024 -0400 EDACS: Display cached call source on Standard, tune group calls on assignment (#241) * Trim trailing whitespace * EDACS: Display cached call source on Standard The logic in `edacs-fme.c` didn't work, in retrospect, because it would have depended on getting back-to-back messages for the same call. In practice, that is unlikely even on an idle system as system state gets displayed. Instead, cache on the display end, for a "better" user experience. * EDACS: Pad channel freq to "000.000000 MHz" * EDACS: Process/tune group calls on assignment commit8d432e8b3eAuthor: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sun Mar 24 12:29:22 2024 -0400 EDACS: ESK fixes, RE of standard channel assignments, cleanups (#238) * EDACS: Make i-calls very obvious on standard * EDACS: abstract target for Interconnect Channel Assignment * EDACS: little shortcut example updates * EDACS: Apply ESK to both FR1 and FR4 * EDACS: Group channel assignment by mode * EDACS: Merge MT-A 0/1 and 2/3 cases commit0440dea1deAuthor: lwvmobile <lwvmobile@gmail.com> Date: Sun Mar 24 02:47:09 2024 -0400 EDACS: Fix Call History For Standard Maybe; commit208f188e55Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sat Mar 23 21:35:42 2024 -0400 EDACS: Speculative RE of MT-A value 0, pretty colours (#231) * EDACS: fix log formatting * EDACS: Speculative RE of MT-A value 0 * EDACS: CC message pretty colours * EDACS: little formatting * EDACS: eh make interconnect magenta commit36f76a7e21Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sat Mar 23 17:35:45 2024 -0400 EDACS: Fix copy/paste error (#230) I went through by hand and I'm confident this is the last of the `get_lcn_status_string()` errors. commit4bc73d8c68Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sat Mar 23 17:24:32 2024 -0400 EDACS: Rewrite Standard/Networked parsing per TIA/EIA TSB 69.3 (#229) * EDACS EA: refactor log messages for consistency * EDACS: Log LCN status values * EDACS EA: channel assignment vs update * EDACS: Implement TIA/EIA TSB 69.3 * EDACS: clean up Site ID message * EDACS: Actually process call for Channel Update * EDACS: Update display for Standard calls * EDACS: Format of Voice Group Channel Assignment * EDACS Standard: Log LCN status values * EDACS: Rebase and fix some issues * EDACS: Fix copy/paste error commit03507055a4Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sat Mar 23 16:05:09 2024 -0400 EDACS: add EA messages / start mass Standard refactor (#226) * EDACS EA: refactor log messages for consistency * EDACS EA: channel assignment command (unknown data) * EDACS EA: status/message command * EDACS Standard: Refactor variable declarations * EDACS Standard: log raw payloads for debugging * EDACS: Fix typing * EDACS EA: update status/message CC command * EDACS: Log LCN status values * EDACS: String format * EDACS EA: channel assignment vs update * EDACS: fix syntax error * EDACS: change string for reserved LCN status commitfbe5fd2093Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Fri Mar 22 15:26:50 2024 -0400 EDACS EA: emergency calls, MT1 fixes, logging improvements (#221) * EDACS EA: Fix i-call MT1 after ESK changes * EDACS EA: Fix all-call ncurses display * EDACS EA: Make detailed log slightly more readable * EDACS EA: Improve colours in logs * EDACS EA: Space in logs for consistency * EDACS EA: Fix MT1 for analog group voice after ESK change * EDACS EA: add parsing for emergency calls commit413e5f76a2Merge:de9127c388a57dAuthor: lwvmobile <59371473+lwvmobile@users.noreply.github.com> Date: Fri Mar 22 06:59:31 2024 -0400 Merge pull request #220 from lwvmobile/edacs_manual_modes Edacs manual modes commit388a57d8fcAuthor: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 05:28:11 2024 -0400 EDACS: Re-enable the -9 switch to maintain user compatability; Fix Missing Bracket on non color mode; commit058099f1aaAuthor: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 03:24:57 2024 -0400 EDACS: Tweak Mode Toggle Display; Add Frame Dump on No Mode Set; commit68aa6b018eAuthor: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 02:19:38 2024 -0400 EDACS: Update Docs to Reflect Changes; commitc404f3c48cAuthor: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 02:01:09 2024 -0400 EDACS: Ncurses Display Working Mode Tweaks; commitb2d1608eb7Author: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 01:08:28 2024 -0400 EDACS: Toggle Keys A and S for Mode Selection; commita4553a0a0aAuthor: lwvmobile <lwvmobile@gmail.com> Date: Fri Mar 22 00:45:37 2024 -0400 EDACS: Remove Auto Detect Code; Make CLI Switches; commitde9127cfb4Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Thu Mar 21 21:02:53 2024 -0400 EDACS: support for EA system all-calls (#214) * Refactor debug printing a bit * Clean up group call logic * Minor changes to debug printing * EDACS EA: support for system all-calls * EDACS: split out MT1 for TDMA call since we can't decode it anyway * Refactor identifying call mode (digital/analog) * Maintain consistent indentation for all MT1 * EDACS: Fix Compiler Error. Had an extra right bracket on line 383 --------- Co-authored-by: lwvmobile <59371473+lwvmobile@users.noreply.github.com> commitc85dd60399Author: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 19 17:38:30 2024 -0400 EDACS: NET/STD LCN > 0 Check; commitbed766a86eAuthor: lwvmobile <lwvmobile@gmail.com> Date: Tue Mar 19 09:34:10 2024 -0400 EDACS: STD/NET Don't Tune Unless CC LCN Set; commit69f532a022Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Mon Mar 18 11:41:58 2024 -0400 EDACS: EA I-Call decoding improvements (#205) * EDACS: formatting nit * EDACS: add name to credits * EDACS: Handle initial grant vs grant update for i-call * EDACS: consistency for group vs i-call * EDACS: file naming for i-call recordings * EDACS: EA refactor when MT1 is 0x1F * EDACS: check we know CC LCN before leaving it * EDACS: fix breaking change for Standard Revert mistake inf68367c4f3* Fix patent number * EDACS: Fix Compiler Error 1; Fix Rogue Copy Paste * EDACS: Add MT1, MT2, and FR1 and FR4 Dumps on Payload; --------- Co-authored-by: lwvmobile <59371473+lwvmobile@users.noreply.github.com> commita7de24c47bAuthor: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Mon Mar 18 07:47:34 2024 -0400 EDACS: fixes and improvements to EA analog and i-call parsing (#204) * Fix MT1 math given esk_mask value is 0xA0 * EDACS: Clean up formatting for I-Calls * EDACS: typo, fix the TGID for group calls Fix copy-pasta * EDACS: Fix MT2 for I-Calls Incorrectly copied decimal values as hex - obviously MT2 is only 4 bits so it cannot be greater than 15. * EDACS: check LCN is > 0 before trying to tune An EA CC sometimes includes commands that parse as LCN 0 - but otherwise valid - analog call voice grants for TG 1. Since LCN 0 is not valid, ensure that we don't try to tune to them while we try to figure out what they're about. * EDACS: Process "login" message on CC Log "login" messages sent on the CC. Verified behaviour against UniTrunker. commit10eacd99ccAuthor: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sun Mar 17 18:56:41 2024 -0400 EDACS: Clean up formatting for I-Calls (#203) * Fix MT1 math given esk_mask value is 0xA0 * EDACS: Clean up formatting for I-Calls commitebe6e8fc65Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sun Mar 17 18:02:12 2024 -0400 Fix MT1 math given esk_mask value is 0xA0 (#202) commit8619612b76Author: lwvmobile <lwvmobile@gmail.com> Date: Sat Mar 16 22:42:44 2024 -0400 EDACS: Setup Analog Calls and WAVs on EA and ICALL; commit9ac1573f0bAuthor: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sat Mar 16 17:17:14 2024 -0400 EDACS: Add MT1 value / logging for analog group calls (#198) * Add MT1 value / logging for analog group calls * Respect user preference for tuning to group calls * Revert "Respect user preference for tuning to group calls" This reverts commit83ac8feab7. commit0aa01a45efAuthor: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sat Mar 16 17:16:52 2024 -0400 EDACS: Respect user preference for tuning to group calls (#201) commitf68367c4f3Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com> Date: Sat Mar 16 17:16:20 2024 -0400 EDACS: Add parsing for individual calls (#200) * EDACS: Add parsing for individual calls This change adds parsing for I-Calls on EA systems. Both analog and ProVoice modes are parsed and processed. See related issue for discussion. * Respect user preference for tuning to private calls * EDACS: Respect user preference for tuning to private calls * EDACS: Handle i-call target in ProVoice logging * EDACS: Show i-calls distinctly from group calls
594 lines
15 KiB
C
594 lines
15 KiB
C
/*-------------------------------------------------------------------------------
|
|
* 3.c
|
|
* Placeholder File 3 -- This file is for temporary code storage
|
|
*
|
|
* Multiple 1/2 Rate Convolutional Decoders for NXDN/M17/YSF
|
|
* Used as a secondary decoder in case convolutional decoder fails (second opinion)
|
|
*-----------------------------------------------------------------------------*/
|
|
|
|
#include "dsd.h"
|
|
|
|
static const int PARITY[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
|
|
|
|
// trellis_1_2 encode: source is in bits, result in bits
|
|
void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg)
|
|
{
|
|
for (int i=0; i<result_len; i+=2) {
|
|
reg = (reg << 1) | source[i>>1];
|
|
result[i] = PARITY[reg & 0x19];
|
|
result[i+1] = PARITY[reg & 0x17];
|
|
}
|
|
}
|
|
|
|
// simplified trellis 2:1 decode; source and result in bits
|
|
// assumes that encoding was done with NTEST trailing zero bits
|
|
// result_len should be set to the actual number of data bits
|
|
// in the original unencoded message (excl. these trailing bits)
|
|
void trellis_decode(uint8_t result[], const uint8_t source[], int result_len)
|
|
{
|
|
int reg = 0;
|
|
int min_d;
|
|
int min_bt;
|
|
static const int NTEST = 4;
|
|
static const int NTESTC = 1 << NTEST;
|
|
uint8_t bt[NTEST];
|
|
uint8_t tt[NTEST*2];
|
|
int dstats[4];
|
|
int sum;
|
|
for (int p=0; p < 4; p++)
|
|
dstats[p] = 0;
|
|
for (int p=0; p < result_len; p++) {
|
|
for (int i=0; i<NTESTC; i++) {
|
|
bt[0] = (i&8)>>3;
|
|
bt[1] = (i&4)>>2;
|
|
bt[2] = (i&2)>>1;
|
|
bt[3] = (i&1);
|
|
trellis_encode(tt, bt, NTEST*2, reg);
|
|
sum=0;
|
|
for (int j=0; j<NTEST*2; j++) {
|
|
sum += tt[j] ^ source[p*2+j];
|
|
}
|
|
if (i == 0 || sum < min_d) {
|
|
min_d = sum;
|
|
min_bt = bt[0];
|
|
}
|
|
}
|
|
result[p] = min_bt;
|
|
reg = (reg << 1) | min_bt;
|
|
dstats[(min_d > 3) ? 3 : min_d] += 1;
|
|
}
|
|
|
|
//debug output
|
|
// fprintf (stderr, "\n stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]);
|
|
}
|
|
|
|
//Original Copyright/License
|
|
|
|
/* -*- c++ -*- */
|
|
/*
|
|
* NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI
|
|
*
|
|
* This file is part of OP25
|
|
*
|
|
* This 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; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This software 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
//Ripped from libM17
|
|
#define K 5 //constraint length
|
|
#define NUM_STATES (1 << (K - 1)) //number of states
|
|
|
|
static uint32_t prevMetrics[NUM_STATES];
|
|
static uint32_t currMetrics[NUM_STATES];
|
|
static uint32_t prevMetricsData[NUM_STATES];
|
|
static uint32_t currMetricsData[NUM_STATES];
|
|
static uint16_t viterbi_history[244];
|
|
|
|
/**
|
|
* @brief Decode unpunctured convolutionally encoded data.
|
|
*
|
|
* @param out Destination array where decoded data is written.
|
|
* @param in Input data.
|
|
* @param len Input length in bits.
|
|
* @return Number of bit errors corrected.
|
|
*/
|
|
uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, const uint16_t len)
|
|
{
|
|
if(len > 244*2)
|
|
fprintf(stderr, "Input size exceeds max history\n");
|
|
|
|
viterbi_reset();
|
|
|
|
size_t pos = 0;
|
|
for(size_t i = 0; i < len; i += 2)
|
|
{
|
|
uint16_t s0 = in[i];
|
|
uint16_t s1 = in[i + 1];
|
|
|
|
viterbi_decode_bit(s0, s1, pos);
|
|
pos++;
|
|
}
|
|
uint32_t err = viterbi_chainback(out, pos, len/2);
|
|
|
|
//debug
|
|
// fprintf (stderr, "\n vcb: \n");
|
|
// for (size_t i = 0; i < len; i++)
|
|
// fprintf (stderr, "%02X", out[i]);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief Decode punctured convolutionally encoded data.
|
|
*
|
|
* @param out Destination array where decoded data is written.
|
|
* @param in Input data.
|
|
* @param punct Puncturing matrix.
|
|
* @param in_len Input data length.
|
|
* @param p_len Puncturing matrix length (entries).
|
|
* @return Number of bit errors corrected.
|
|
*/
|
|
uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len)
|
|
{
|
|
if(in_len > 244*2)
|
|
fprintf(stderr, "Input size exceeds max history\n");
|
|
|
|
uint16_t umsg[244*2]; //unpunctured message
|
|
uint8_t p=0; //puncturer matrix entry
|
|
uint16_t u=0; //bits count - unpunctured message
|
|
uint16_t i=0; //bits read from the input message
|
|
|
|
while(i<in_len)
|
|
{
|
|
if(punct[p])
|
|
{
|
|
umsg[u]=in[i];
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
umsg[u]=0x7FFF;
|
|
}
|
|
|
|
u++;
|
|
p++;
|
|
p%=p_len;
|
|
}
|
|
|
|
//debug
|
|
// fprintf (stderr, " p: %d, u: %d; p_len: %d; len: %d;", p, u, p_len, (u-in_len)*0x7FFF);
|
|
|
|
return viterbi_decode(out, umsg, u) - (u-in_len)*0x7FFF;
|
|
}
|
|
|
|
/**
|
|
* @brief Decode one bit and update trellis.
|
|
*
|
|
* @param s0 Cost of the first symbol.
|
|
* @param s1 Cost of the second symbol.
|
|
* @param pos Bit position in history.
|
|
*/
|
|
void viterbi_decode_bit(uint16_t s0, uint16_t s1, const size_t pos)
|
|
{
|
|
static const uint16_t COST_TABLE_0[] = {0, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
|
static const uint16_t COST_TABLE_1[] = {0, 0xFFFF, 0xFFFF, 0, 0, 0xFFFF, 0xFFFF, 0};
|
|
|
|
for(uint8_t i = 0; i < NUM_STATES/2; i++)
|
|
{
|
|
uint32_t metric = q_abs_diff(COST_TABLE_0[i], s0)
|
|
+ q_abs_diff(COST_TABLE_1[i], s1);
|
|
|
|
|
|
uint32_t m0 = prevMetrics[i] + metric;
|
|
uint32_t m1 = prevMetrics[i + NUM_STATES/2] + (0x1FFFE - metric);
|
|
|
|
uint32_t m2 = prevMetrics[i] + (0x1FFFE - metric);
|
|
uint32_t m3 = prevMetrics[i + NUM_STATES/2] + metric;
|
|
|
|
uint8_t i0 = 2 * i;
|
|
uint8_t i1 = i0 + 1;
|
|
|
|
if(m0 >= m1)
|
|
{
|
|
viterbi_history[pos]|=(1<<i0);
|
|
currMetrics[i0] = m1;
|
|
}
|
|
else
|
|
{
|
|
viterbi_history[pos]&=~(1<<i0);
|
|
currMetrics[i0] = m0;
|
|
}
|
|
|
|
if(m2 >= m3)
|
|
{
|
|
viterbi_history[pos]|=(1<<i1);
|
|
currMetrics[i1] = m3;
|
|
}
|
|
else
|
|
{
|
|
viterbi_history[pos]&=~(1<<i1);
|
|
currMetrics[i1] = m2;
|
|
}
|
|
}
|
|
|
|
//swap
|
|
uint32_t tmp[NUM_STATES];
|
|
for(uint8_t i=0; i<NUM_STATES; i++)
|
|
{
|
|
tmp[i]=currMetrics[i];
|
|
}
|
|
for(uint8_t i=0; i<NUM_STATES; i++)
|
|
{
|
|
currMetrics[i]=prevMetrics[i];
|
|
prevMetrics[i]=tmp[i];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief History chainback to obtain final byte array.
|
|
*
|
|
* @param out Destination byte array for decoded data.
|
|
* @param pos Starting position for the chainback.
|
|
* @param len Length of the output in bits.
|
|
* @return Minimum Viterbi cost at the end of the decode sequence.
|
|
*/
|
|
uint32_t viterbi_chainback(uint8_t* out, size_t pos, uint16_t len)
|
|
{
|
|
uint8_t state = 0;
|
|
size_t bitPos = len+4;
|
|
|
|
memset(out, 0, (len-1)/8+1);
|
|
|
|
while(pos > 0)
|
|
{
|
|
bitPos--;
|
|
pos--;
|
|
uint16_t bit = viterbi_history[pos]&((1<<(state>>4)));
|
|
state >>= 1;
|
|
if(bit)
|
|
{
|
|
state |= 0x80;
|
|
out[bitPos/8]|=1<<(7-(bitPos%8));
|
|
}
|
|
}
|
|
|
|
uint32_t cost = prevMetrics[0];
|
|
|
|
for(size_t i = 0; i < NUM_STATES; i++)
|
|
{
|
|
uint32_t m = prevMetrics[i];
|
|
if(m < cost) cost = m;
|
|
}
|
|
|
|
//debug
|
|
// fprintf (stderr, "\n cb: \n");
|
|
// for (size_t i = 0; i < len; i++)
|
|
// fprintf (stderr, "%02X", out[i]);
|
|
|
|
return cost;
|
|
}
|
|
|
|
/**
|
|
* @brief Reset the decoder state. No args.
|
|
*
|
|
*/
|
|
void viterbi_reset(void)
|
|
{
|
|
memset((uint8_t*)viterbi_history, 0, 2*244);
|
|
memset((uint8_t*)currMetrics, 0, 4*NUM_STATES);
|
|
memset((uint8_t*)prevMetrics, 0, 4*NUM_STATES);
|
|
memset((uint8_t*)currMetricsData, 0, 4*NUM_STATES);
|
|
memset((uint8_t*)prevMetricsData, 0, 4*NUM_STATES);
|
|
}
|
|
|
|
uint16_t q_abs_diff(const uint16_t v1, const uint16_t v2)
|
|
{
|
|
if(v2 > v1) return v2 - v1;
|
|
return v1 - v2;
|
|
}
|
|
|
|
//original sources
|
|
//--------------------------------------------------------------------
|
|
// M17 C library - decode/viterbi.c
|
|
//
|
|
// This file contains:
|
|
// - the Viterbi decoder
|
|
//
|
|
// Wojciech Kaczmarski, SP5WWP
|
|
// M17 Project, 29 December 2023
|
|
//--------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------
|
|
// M17 C library - math/math.c
|
|
//
|
|
// This file contains:
|
|
// - absolute difference value
|
|
// - Euclidean norm (L2) calculation for n-dimensional vectors (float)
|
|
// - soft-valued arrays to integer conversion (and vice-versa)
|
|
// - fixed-valued multiplication and division
|
|
//
|
|
// Wojciech Kaczmarski, SP5WWP
|
|
// M17 Project, 29 December 2023
|
|
//--------------------------------------------------------------------
|
|
|
|
|
|
//audio filter stuff sourced from: https://github.com/NedSimao/FilteringLibrary
|
|
//no license / information provided in source code
|
|
#define PI 3.141592653
|
|
|
|
//do we need this for test input sthit?
|
|
// #define PLOT_POINTS 100
|
|
// #define SAMPLE_TIME_S 0.001
|
|
// #define CUTOFFFREQ_HZ 50
|
|
// #define sine_freq 40
|
|
// #define sine_freq_1 500
|
|
// #define HFC 50
|
|
// #define LFC 100
|
|
|
|
|
|
void LPFilter_Init(LPFilter *filter, float cutoffFreqHz, float sampleTimeS)
|
|
{
|
|
|
|
float RC=0.0;
|
|
RC=1.0/(2*PI*cutoffFreqHz);
|
|
filter->coef[0]=sampleTimeS/(sampleTimeS+RC);
|
|
filter->coef[1]=RC/(sampleTimeS+RC);
|
|
|
|
filter->v_out[0]=0.0;
|
|
filter->v_out[1]=0.0;
|
|
|
|
}
|
|
|
|
|
|
float LPFilter_Update(LPFilter *filter, float v_in)
|
|
{
|
|
|
|
filter->v_out[1]=filter->v_out[0];
|
|
filter->v_out[0]=(filter->coef[0]*v_in) + (filter->coef[1]*filter->v_out[1]);
|
|
|
|
return (filter->v_out[0]);
|
|
|
|
}
|
|
|
|
|
|
/********************************************************************************************************
|
|
* HIGH PASS FILTER
|
|
********************************************************************************************************/
|
|
void HPFilter_Init(HPFilter *filter, float cutoffFreqHz, float sampleTimeS)
|
|
{
|
|
|
|
float RC=0.0;
|
|
RC=1.0/(2*PI*cutoffFreqHz);
|
|
|
|
filter->coef=RC/(sampleTimeS+RC);
|
|
|
|
filter->v_in[0]=0.0;
|
|
filter->v_in[1]=0.0;
|
|
|
|
filter->v_out[0]=0.0;
|
|
filter->v_out[1]=0.0;
|
|
|
|
}
|
|
|
|
|
|
float HPFilter_Update(HPFilter *filter, float v_in)
|
|
{
|
|
|
|
filter->v_in[1]=filter->v_in[0];
|
|
filter->v_in[0]=v_in;
|
|
|
|
filter->v_out[1]=filter->v_out[0];
|
|
filter->v_out[0]=filter->coef * (filter->v_in[0] - filter->v_in[1]+filter->v_out[1]);
|
|
|
|
return (filter->v_out[0]);
|
|
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* BAND PASS FILTER
|
|
********************************************************************************************************/
|
|
|
|
|
|
void PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS)
|
|
{
|
|
|
|
LPFilter_Init(&filter->lpf, LPF_cutoffFreqHz, sampleTimeS);
|
|
HPFilter_Init(&filter->hpf, HPF_cutoffFreqHz, sampleTimeS);
|
|
|
|
filter->out_in=0.0;
|
|
|
|
}
|
|
|
|
float PBFilter_Update(PBFilter *filter, float v_in)
|
|
{
|
|
|
|
filter->out_in=HPFilter_Update(&filter->hpf, v_in);
|
|
|
|
filter->out_in=LPFilter_Update(&filter->lpf, filter->out_in);
|
|
|
|
return (filter->out_in);
|
|
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* NOTCH FILTER
|
|
********************************************************************************************************/
|
|
|
|
|
|
void NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS)
|
|
{
|
|
|
|
//filter frequency to angular (rad/s)
|
|
float w0_rps=2.0 * PI *centerFreqHz;
|
|
float ww_rps=2.0 * PI *notchWidthHz;
|
|
|
|
//pre warp center frequency
|
|
float w0_pw_rps=(2.0/sampleTimeS) * tanf(0.5 * w0_rps * sampleTimeS);
|
|
|
|
//computing filter coefficients
|
|
|
|
filter->alpha=4.0 + w0_rps*w0_pw_rps*sampleTimeS*sampleTimeS;
|
|
filter->beta=2.0*ww_rps*sampleTimeS;
|
|
|
|
//clearing input and output buffers
|
|
|
|
for (uint8_t n=0; n<3; n++)
|
|
{
|
|
filter->vin[n]=0;
|
|
filter->vout[n]=0;
|
|
}
|
|
|
|
}
|
|
|
|
float NOTCHFilter_Update(NOTCHFilter *filter, float vin)
|
|
{
|
|
|
|
//shifting samples
|
|
filter->vin[2]=filter->vin[1];
|
|
filter->vin[1]=filter->vin[0];
|
|
|
|
filter->vout[2]=filter->vout[1];
|
|
filter->vout[1]=filter->vout[0];
|
|
|
|
filter->vin[0]=vin;
|
|
|
|
//compute new output
|
|
filter->vout[0]=(filter->alpha*filter->vin[0] + 2.0 *(filter->alpha -8.0)*filter->vin[1] + filter->alpha*filter->vin[2]
|
|
-(2.0f*(filter->alpha-8.0)*filter->vout[1]+(filter->alpha-filter->beta)*filter->vout[2]))/(filter->alpha+filter->beta);
|
|
|
|
|
|
return (filter->vout[0]);
|
|
}
|
|
|
|
void init_audio_filters (dsd_state * state)
|
|
{
|
|
//still not sure if this is even correct or not, but 48k sounds good now
|
|
LPFilter_Init(&state->RCFilter, 960, (float)1/(float)48000);
|
|
HPFilter_Init(&state->HRCFilter, 960, (float)1/(float)48000);
|
|
|
|
//left and right variants for stereo output testing on digital voice samples
|
|
LPFilter_Init(&state->RCFilterL, 960, (float)1/(float)16000);
|
|
HPFilter_Init(&state->HRCFilterL, 960, (float)1/(float)16000);
|
|
LPFilter_Init(&state->RCFilterR, 960, (float)1/(float)16000);
|
|
HPFilter_Init(&state->HRCFilterR, 960, (float)1/(float)16000);
|
|
|
|
//PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS);
|
|
//NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS);
|
|
|
|
//NOTE: PBFilter_init also inits a LPF and HPF, but on another set of filters, might be worth
|
|
//testing just using the PBFilter by itself and see how it does without the hpf used
|
|
|
|
//passband filter working (seems to be), notch filter unsure which values to use, doesn't have any appreciable affect when used as is
|
|
PBFilter_Init(&state->PBF, 8000, 12000, (float)1/(float)1536000); //RTL Sampling at 1536000 S/s.
|
|
NOTCHFilter_Init(&state->NF, 1000, 4000, (float)1/(float)1536000);
|
|
|
|
}
|
|
|
|
//FUNCTIONS for handing use of above filters
|
|
|
|
//lpf
|
|
void lpf(dsd_state * state, short * input, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
|
input[i] = LPFilter_Update(&state->RCFilter, input[i]);
|
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
|
}
|
|
}
|
|
|
|
//hpf
|
|
void hpf(dsd_state * state, short * input, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
|
input[i] = HPFilter_Update(&state->HRCFilter, input[i]);
|
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
|
}
|
|
}
|
|
|
|
//hpf digital left
|
|
void hpf_dL(dsd_state * state, short * input, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
|
input[i] = HPFilter_Update(&state->HRCFilterL, input[i]);
|
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
|
}
|
|
}
|
|
|
|
//hpf digital right
|
|
void hpf_dR(dsd_state * state, short * input, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
|
input[i] = HPFilter_Update(&state->HRCFilterR, input[i]);
|
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
|
}
|
|
}
|
|
|
|
//nf
|
|
void nf(dsd_state * state, short * input, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
|
input[i] = NOTCHFilter_Update(&state->NF, input[i]);
|
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
|
}
|
|
}
|
|
|
|
//pbf
|
|
void pbf(dsd_state * state, short * input, int len)
|
|
{
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
|
input[i] = PBFilter_Update(&state->PBF, input[i]);
|
|
}
|
|
}
|
|
|
|
//Generic RMS function derived from RTL_FM (RTL_SDR) RMS code (doesnt' really work correctly outside of RTL)
|
|
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;
|
|
} |