kopia lustrzana https://github.com/mobilinkd/NucleoTNC
Sync NucleoTNC firmware with TNC3 v2.1.8 codebase. Upgrade compiler to GCC 10.2. Upgrade to C++20 for std::span. Changes to reduce stack utilization. Reduce jitter by adjusting clocks & interrupt priority. Fix serial port timeout on large packets. Use floating point for M17 modulator. Fix LICH decode defect.
rodzic
bc01e2840f
commit
eb478b443a
17
.cproject
17
.cproject
|
@ -120,11 +120,11 @@
|
|||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.1924121031" name="Debug level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level" useByScannerDiscovery="true"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.437976635" name="Debug format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format" useByScannerDiscovery="true"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name.1999567545" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name" useByScannerDiscovery="false" value="GNU Tools for ARM Embedded Processors" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id.827716078" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id" value="962691777" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id.827716078" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.id" value="1287942917" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix.1226916242" name="Prefix" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix" useByScannerDiscovery="false" value="arm-none-eabi-" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.c.1790126668" name="C compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.c" useByScannerDiscovery="false" value="gcc" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp.435521309" name="C++ compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp" useByScannerDiscovery="false" value="g++" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.1588366312" name="ARM family (-mcpu)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m4" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.1588366312" name="Arm family (-mcpu)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m4" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.1503489612" name="Float ABI" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.softfp" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.310369970" name="FPU Type" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.fpv4spd16" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.noinlinefunctions.937089372" name="Do not inline functions (-fno-inline-functions)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.noinlinefunctions" useByScannerDiscovery="true" value="true" valueType="boolean"/>
|
||||
|
@ -207,14 +207,14 @@
|
|||
<listOptionValue builtIn="false" value="__weak=__attribute__((weak))"/>
|
||||
<listOptionValue builtIn="false" value="NUCLEOTNC=1"/>
|
||||
</option>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.1698432379" name="Language standard" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.gnucpp1z" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.abiversion.1773636385" name="ABI version" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.abiversion" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.abiversion.9" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.1698432379" name="Language standard" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.std.gnucpp2a" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.abiversion.1773636385" name="ABI version" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.abiversion" useByScannerDiscovery="true" value="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.abiversion.13" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.noexceptions.1798306214" name="Do not use exceptions (-fno-exceptions)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.noexceptions" useByScannerDiscovery="true" value="true" valueType="boolean"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.nortti.433035511" name="Do not use RTTI (-fno-rtti)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.nortti" useByScannerDiscovery="true" value="true" valueType="boolean"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.nousecxaatexit.1502881352" name="Do not use _cxa_atexit() (-fno-use-cxa-atexit)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.nousecxaatexit" useByScannerDiscovery="true" value="true" valueType="boolean"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.nothreadsafestatics.2021365039" name="Do not use thread-safe statics (-fno-threadsafe-statics)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.nothreadsafestatics" useByScannerDiscovery="true" value="true" valueType="boolean"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.warnabi.465405510" name="Warn on ABI violations (-Wabi)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.warnabi" useByScannerDiscovery="true" value="false" valueType="boolean"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.otherwarnings.1044945797" name="Other warning flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.otherwarnings" useByScannerDiscovery="true" value="-Wno-register" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.otherwarnings.1044945797" name="Other warning flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.otherwarnings" useByScannerDiscovery="true" value="-Wno-register -Wall -Wextra" valueType="string"/>
|
||||
<inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.906017231" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.110190447" name="GNU ARM Cross C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker">
|
||||
|
@ -251,6 +251,9 @@
|
|||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
|
@ -282,7 +285,7 @@
|
|||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.51697857" name="Debug format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format" useByScannerDiscovery="true"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name.1445567365" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name" useByScannerDiscovery="false" value="GNU Tools for ARM Embedded Processors" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.1680967491" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.architecture" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.arm" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.1498989241" name="ARM family (-mcpu)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m4" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.1498989241" name="Arm family (-mcpu)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m4" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.1207350265" name="Instruction set" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset" useByScannerDiscovery="false" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.thumb" valueType="enumerated"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix.318899792" name="Prefix" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix" useByScannerDiscovery="false" value="arm-none-eabi-" valueType="string"/>
|
||||
<option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.c.1240926089" name="C compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.c" useByScannerDiscovery="false" value="gcc" valueType="string"/>
|
||||
|
@ -560,4 +563,4 @@
|
|||
</profile>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
</cproject>
|
||||
</cproject>
|
21
.mxproject
21
.mxproject
File diff suppressed because one or more lines are too long
|
@ -59,14 +59,14 @@
|
|||
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||
#define configMAX_PRIORITIES ( 7 )
|
||||
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
||||
#define configTOTAL_HEAP_SIZE ((size_t)4096)
|
||||
#define configTOTAL_HEAP_SIZE ((size_t)3072)
|
||||
#define configMAX_TASK_NAME_LEN ( 16 )
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 1
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
#define configUSE_TICKLESS_IDLE 1
|
||||
#define configUSE_TICKLESS_IDLE 0
|
||||
|
||||
/* Co-routine definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
|
|
|
@ -4,7 +4,7 @@ ENTRY(Reset_Handler)
|
|||
/* Highest address of the user mode stack */
|
||||
_estack = 0x2000C000; /* end of RAM */
|
||||
/* Generate a link error if heap and stack don't fit into RAM */
|
||||
_Min_Heap_Size = 0x1000; /* required amount of heap */
|
||||
_Min_Heap_Size = 0x400; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x400; /* required amount of stack */
|
||||
|
||||
/* Specify the memory areas */
|
||||
|
|
|
@ -0,0 +1,581 @@
|
|||
/* ----------------------------------------------------------------------
|
||||
* Copyright (C) 2010-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* $Date: 19. March 2015
|
||||
* $Revision: V.1.4.5
|
||||
*
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: arm_fir_interpolate_f32.c
|
||||
*
|
||||
* Description: FIR interpolation for floating-point sequences.
|
||||
*
|
||||
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* - Neither the name of ARM LIMITED nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
#include "arm_math.h"
|
||||
|
||||
/**
|
||||
* @defgroup FIR_Interpolate Finite Impulse Response (FIR) Interpolator
|
||||
*
|
||||
* These functions combine an upsampler (zero stuffer) and an FIR filter.
|
||||
* They are used in multirate systems for increasing the sample rate of a signal without introducing high frequency images.
|
||||
* Conceptually, the functions are equivalent to the block diagram below:
|
||||
* \image html FIRInterpolator.gif "Components included in the FIR Interpolator functions"
|
||||
* After upsampling by a factor of <code>L</code>, the signal should be filtered by a lowpass filter with a normalized
|
||||
* cutoff frequency of <code>1/L</code> in order to eliminate high frequency copies of the spectrum.
|
||||
* The user of the function is responsible for providing the filter coefficients.
|
||||
*
|
||||
* The FIR interpolator functions provided in the CMSIS DSP Library combine the upsampler and FIR filter in an efficient manner.
|
||||
* The upsampler inserts <code>L-1</code> zeros between each sample.
|
||||
* Instead of multiplying by these zero values, the FIR filter is designed to skip them.
|
||||
* This leads to an efficient implementation without any wasted effort.
|
||||
* The functions operate on blocks of input and output data.
|
||||
* <code>pSrc</code> points to an array of <code>blockSize</code> input values and
|
||||
* <code>pDst</code> points to an array of <code>blockSize*L</code> output values.
|
||||
*
|
||||
* The library provides separate functions for Q15, Q31, and floating-point data types.
|
||||
*
|
||||
* \par Algorithm:
|
||||
* The functions use a polyphase filter structure:
|
||||
* <pre>
|
||||
* y[n] = b[0] * x[n] + b[L] * x[n-1] + ... + b[L*(phaseLength-1)] * x[n-phaseLength+1]
|
||||
* y[n+1] = b[1] * x[n] + b[L+1] * x[n-1] + ... + b[L*(phaseLength-1)+1] * x[n-phaseLength+1]
|
||||
* ...
|
||||
* y[n+(L-1)] = b[L-1] * x[n] + b[2*L-1] * x[n-1] + ....+ b[L*(phaseLength-1)+(L-1)] * x[n-phaseLength+1]
|
||||
* </pre>
|
||||
* This approach is more efficient than straightforward upsample-then-filter algorithms.
|
||||
* With this method the computation is reduced by a factor of <code>1/L</code> when compared to using a standard FIR filter.
|
||||
* \par
|
||||
* <code>pCoeffs</code> points to a coefficient array of size <code>numTaps</code>.
|
||||
* <code>numTaps</code> must be a multiple of the interpolation factor <code>L</code> and this is checked by the
|
||||
* initialization functions.
|
||||
* Internally, the function divides the FIR filter's impulse response into shorter filters of length
|
||||
* <code>phaseLength=numTaps/L</code>.
|
||||
* Coefficients are stored in time reversed order.
|
||||
* \par
|
||||
* <pre>
|
||||
* {b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
|
||||
* </pre>
|
||||
* \par
|
||||
* <code>pState</code> points to a state array of size <code>blockSize + phaseLength - 1</code>.
|
||||
* Samples in the state buffer are stored in the order:
|
||||
* \par
|
||||
* <pre>
|
||||
* {x[n-phaseLength+1], x[n-phaseLength], x[n-phaseLength-1], x[n-phaseLength-2]....x[0], x[1], ..., x[blockSize-1]}
|
||||
* </pre>
|
||||
* The state variables are updated after each block of data is processed, the coefficients are untouched.
|
||||
*
|
||||
* \par Instance Structure
|
||||
* The coefficients and state variables for a filter are stored together in an instance data structure.
|
||||
* A separate instance structure must be defined for each filter.
|
||||
* Coefficient arrays may be shared among several instances while state variable array should be allocated separately.
|
||||
* There are separate instance structure declarations for each of the 3 supported data types.
|
||||
*
|
||||
* \par Initialization Functions
|
||||
* There is also an associated initialization function for each data type.
|
||||
* The initialization function performs the following operations:
|
||||
* - Sets the values of the internal structure fields.
|
||||
* - Zeros out the values in the state buffer.
|
||||
* - Checks to make sure that the length of the filter is a multiple of the interpolation factor.
|
||||
* To do this manually without calling the init function, assign the follow subfields of the instance structure:
|
||||
* L (interpolation factor), pCoeffs, phaseLength (numTaps / L), pState. Also set all of the values in pState to zero.
|
||||
*
|
||||
* \par
|
||||
* Use of the initialization function is optional.
|
||||
* However, if the initialization function is used, then the instance structure cannot be placed into a const data section.
|
||||
* To place an instance structure into a const data section, the instance structure must be manually initialized.
|
||||
* The code below statically initializes each of the 3 different data type filter instance structures
|
||||
* <pre>
|
||||
* arm_fir_interpolate_instance_f32 S = {L, phaseLength, pCoeffs, pState};
|
||||
* arm_fir_interpolate_instance_q31 S = {L, phaseLength, pCoeffs, pState};
|
||||
* arm_fir_interpolate_instance_q15 S = {L, phaseLength, pCoeffs, pState};
|
||||
* </pre>
|
||||
* where <code>L</code> is the interpolation factor; <code>phaseLength=numTaps/L</code> is the
|
||||
* length of each of the shorter FIR filters used internally,
|
||||
* <code>pCoeffs</code> is the address of the coefficient buffer;
|
||||
* <code>pState</code> is the address of the state buffer.
|
||||
* Be sure to set the values in the state buffer to zeros when doing static initialization.
|
||||
*
|
||||
* \par Fixed-Point Behavior
|
||||
* Care must be taken when using the fixed-point versions of the FIR interpolate filter functions.
|
||||
* In particular, the overflow and saturation behavior of the accumulator used in each function must be considered.
|
||||
* Refer to the function specific documentation below for usage guidelines.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup FIR_Interpolate
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Processing function for the floating-point FIR interpolator.
|
||||
* @param[in] *S points to an instance of the floating-point FIR interpolator structure.
|
||||
* @param[in] *pSrc points to the block of input data.
|
||||
* @param[out] *pDst points to the block of output data.
|
||||
* @param[in] blockSize number of input samples to process per call.
|
||||
* @return none.
|
||||
*/
|
||||
#ifndef ARM_MATH_CM0_FAMILY
|
||||
|
||||
/* Run the below code for Cortex-M4 and Cortex-M3 */
|
||||
|
||||
void arm_fir_interpolate_f32(
|
||||
const arm_fir_interpolate_instance_f32 * S,
|
||||
float32_t * pSrc,
|
||||
float32_t * pDst,
|
||||
uint32_t blockSize)
|
||||
{
|
||||
float32_t *pState = S->pState; /* State pointer */
|
||||
float32_t *pCoeffs = S->pCoeffs; /* Coefficient pointer */
|
||||
float32_t *pStateCurnt; /* Points to the current sample of the state */
|
||||
float32_t *ptr1, *ptr2; /* Temporary pointers for state and coefficient buffers */
|
||||
float32_t sum0; /* Accumulators */
|
||||
float32_t x0, c0; /* Temporary variables to hold state and coefficient values */
|
||||
uint32_t i, blkCnt, j; /* Loop counters */
|
||||
uint16_t phaseLen = S->phaseLength, tapCnt; /* Length of each polyphase filter component */
|
||||
float32_t acc0, acc1, acc2, acc3;
|
||||
float32_t x1, x2, x3;
|
||||
uint32_t blkCntN4;
|
||||
float32_t c1, c2, c3;
|
||||
|
||||
/* S->pState buffer contains previous frame (phaseLen - 1) samples */
|
||||
/* pStateCurnt points to the location where the new input data should be written */
|
||||
pStateCurnt = S->pState + (phaseLen - 1u);
|
||||
|
||||
/* Initialise blkCnt */
|
||||
blkCnt = blockSize / 4;
|
||||
blkCntN4 = blockSize - (4 * blkCnt);
|
||||
|
||||
/* Samples loop unrolled by 4 */
|
||||
while(blkCnt > 0u)
|
||||
{
|
||||
/* Copy new input sample into the state buffer */
|
||||
*pStateCurnt++ = *pSrc++;
|
||||
*pStateCurnt++ = *pSrc++;
|
||||
*pStateCurnt++ = *pSrc++;
|
||||
*pStateCurnt++ = *pSrc++;
|
||||
|
||||
/* Address modifier index of coefficient buffer */
|
||||
j = 1u;
|
||||
|
||||
/* Loop over the Interpolation factor. */
|
||||
i = (S->L);
|
||||
|
||||
while(i > 0u)
|
||||
{
|
||||
/* Set accumulator to zero */
|
||||
acc0 = 0.0f;
|
||||
acc1 = 0.0f;
|
||||
acc2 = 0.0f;
|
||||
acc3 = 0.0f;
|
||||
|
||||
/* Initialize state pointer */
|
||||
ptr1 = pState;
|
||||
|
||||
/* Initialize coefficient pointer */
|
||||
ptr2 = pCoeffs + (S->L - j);
|
||||
|
||||
/* Loop over the polyPhase length. Unroll by a factor of 4.
|
||||
** Repeat until we've computed numTaps-(4*S->L) coefficients. */
|
||||
tapCnt = phaseLen >> 2u;
|
||||
|
||||
x0 = *(ptr1++);
|
||||
x1 = *(ptr1++);
|
||||
x2 = *(ptr1++);
|
||||
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
|
||||
/* Read the input sample */
|
||||
x3 = *(ptr1++);
|
||||
|
||||
/* Read the coefficient */
|
||||
c0 = *(ptr2);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
acc0 += x0 * c0;
|
||||
acc1 += x1 * c0;
|
||||
acc2 += x2 * c0;
|
||||
acc3 += x3 * c0;
|
||||
|
||||
/* Read the coefficient */
|
||||
c1 = *(ptr2 + S->L);
|
||||
|
||||
/* Read the input sample */
|
||||
x0 = *(ptr1++);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
acc0 += x1 * c1;
|
||||
acc1 += x2 * c1;
|
||||
acc2 += x3 * c1;
|
||||
acc3 += x0 * c1;
|
||||
|
||||
/* Read the coefficient */
|
||||
c2 = *(ptr2 + S->L * 2);
|
||||
|
||||
/* Read the input sample */
|
||||
x1 = *(ptr1++);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
acc0 += x2 * c2;
|
||||
acc1 += x3 * c2;
|
||||
acc2 += x0 * c2;
|
||||
acc3 += x1 * c2;
|
||||
|
||||
/* Read the coefficient */
|
||||
c3 = *(ptr2 + S->L * 3);
|
||||
|
||||
/* Read the input sample */
|
||||
x2 = *(ptr1++);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
acc0 += x3 * c3;
|
||||
acc1 += x0 * c3;
|
||||
acc2 += x1 * c3;
|
||||
acc3 += x2 * c3;
|
||||
|
||||
|
||||
/* Upsampling is done by stuffing L-1 zeros between each sample.
|
||||
* So instead of multiplying zeros with coefficients,
|
||||
* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += 4 * S->L;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
|
||||
/* If the polyPhase length is not a multiple of 4, compute the remaining filter taps */
|
||||
tapCnt = phaseLen % 0x4u;
|
||||
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
|
||||
/* Read the input sample */
|
||||
x3 = *(ptr1++);
|
||||
|
||||
/* Read the coefficient */
|
||||
c0 = *(ptr2);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
acc0 += x0 * c0;
|
||||
acc1 += x1 * c0;
|
||||
acc2 += x2 * c0;
|
||||
acc3 += x3 * c0;
|
||||
|
||||
/* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += S->L;
|
||||
|
||||
/* update states for next sample processing */
|
||||
x0 = x1;
|
||||
x1 = x2;
|
||||
x2 = x3;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
|
||||
/* The result is in the accumulator, store in the destination buffer. */
|
||||
*pDst = acc0;
|
||||
*(pDst + S->L) = acc1;
|
||||
*(pDst + 2 * S->L) = acc2;
|
||||
*(pDst + 3 * S->L) = acc3;
|
||||
|
||||
pDst++;
|
||||
|
||||
/* Increment the address modifier index of coefficient buffer */
|
||||
j++;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
i--;
|
||||
}
|
||||
|
||||
/* Advance the state pointer by 1
|
||||
* to process the next group of interpolation factor number samples */
|
||||
pState = pState + 4;
|
||||
|
||||
pDst += S->L * 3;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
blkCnt--;
|
||||
}
|
||||
|
||||
/* If the blockSize is not a multiple of 4, compute any remaining output samples here.
|
||||
** No loop unrolling is used. */
|
||||
|
||||
while(blkCntN4 > 0u)
|
||||
{
|
||||
/* Copy new input sample into the state buffer */
|
||||
*pStateCurnt++ = *pSrc++;
|
||||
|
||||
/* Address modifier index of coefficient buffer */
|
||||
j = 1u;
|
||||
|
||||
/* Loop over the Interpolation factor. */
|
||||
i = S->L;
|
||||
while(i > 0u)
|
||||
{
|
||||
/* Set accumulator to zero */
|
||||
sum0 = 0.0f;
|
||||
|
||||
/* Initialize state pointer */
|
||||
ptr1 = pState;
|
||||
|
||||
/* Initialize coefficient pointer */
|
||||
ptr2 = pCoeffs + (S->L - j);
|
||||
|
||||
/* Loop over the polyPhase length. Unroll by a factor of 4.
|
||||
** Repeat until we've computed numTaps-(4*S->L) coefficients. */
|
||||
tapCnt = phaseLen >> 2u;
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
|
||||
/* Read the coefficient */
|
||||
c0 = *(ptr2);
|
||||
|
||||
/* Upsampling is done by stuffing L-1 zeros between each sample.
|
||||
* So instead of multiplying zeros with coefficients,
|
||||
* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += S->L;
|
||||
|
||||
/* Read the input sample */
|
||||
x0 = *(ptr1++);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
sum0 += x0 * c0;
|
||||
|
||||
/* Read the coefficient */
|
||||
c0 = *(ptr2);
|
||||
|
||||
/* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += S->L;
|
||||
|
||||
/* Read the input sample */
|
||||
x0 = *(ptr1++);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
sum0 += x0 * c0;
|
||||
|
||||
/* Read the coefficient */
|
||||
c0 = *(ptr2);
|
||||
|
||||
/* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += S->L;
|
||||
|
||||
/* Read the input sample */
|
||||
x0 = *(ptr1++);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
sum0 += x0 * c0;
|
||||
|
||||
/* Read the coefficient */
|
||||
c0 = *(ptr2);
|
||||
|
||||
/* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += S->L;
|
||||
|
||||
/* Read the input sample */
|
||||
x0 = *(ptr1++);
|
||||
|
||||
/* Perform the multiply-accumulate */
|
||||
sum0 += x0 * c0;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
|
||||
/* If the polyPhase length is not a multiple of 4, compute the remaining filter taps */
|
||||
tapCnt = phaseLen % 0x4u;
|
||||
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
/* Perform the multiply-accumulate */
|
||||
sum0 += *(ptr1++) * (*ptr2);
|
||||
|
||||
/* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += S->L;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
|
||||
/* The result is in the accumulator, store in the destination buffer. */
|
||||
*pDst++ = sum0;
|
||||
|
||||
/* Increment the address modifier index of coefficient buffer */
|
||||
j++;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
i--;
|
||||
}
|
||||
|
||||
/* Advance the state pointer by 1
|
||||
* to process the next group of interpolation factor number samples */
|
||||
pState = pState + 1;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
blkCntN4--;
|
||||
}
|
||||
|
||||
/* Processing is complete.
|
||||
** Now copy the last phaseLen - 1 samples to the satrt of the state buffer.
|
||||
** This prepares the state buffer for the next function call. */
|
||||
|
||||
/* Points to the start of the state buffer */
|
||||
pStateCurnt = S->pState;
|
||||
|
||||
tapCnt = (phaseLen - 1u) >> 2u;
|
||||
|
||||
/* copy data */
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
*pStateCurnt++ = *pState++;
|
||||
*pStateCurnt++ = *pState++;
|
||||
*pStateCurnt++ = *pState++;
|
||||
*pStateCurnt++ = *pState++;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
|
||||
tapCnt = (phaseLen - 1u) % 0x04u;
|
||||
|
||||
/* copy data */
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
*pStateCurnt++ = *pState++;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Run the below code for Cortex-M0 */
|
||||
|
||||
void arm_fir_interpolate_f32(
|
||||
const arm_fir_interpolate_instance_f32 * S,
|
||||
float32_t * pSrc,
|
||||
float32_t * pDst,
|
||||
uint32_t blockSize)
|
||||
{
|
||||
float32_t *pState = S->pState; /* State pointer */
|
||||
float32_t *pCoeffs = S->pCoeffs; /* Coefficient pointer */
|
||||
float32_t *pStateCurnt; /* Points to the current sample of the state */
|
||||
float32_t *ptr1, *ptr2; /* Temporary pointers for state and coefficient buffers */
|
||||
|
||||
|
||||
float32_t sum; /* Accumulator */
|
||||
uint32_t i, blkCnt; /* Loop counters */
|
||||
uint16_t phaseLen = S->phaseLength, tapCnt; /* Length of each polyphase filter component */
|
||||
|
||||
|
||||
/* S->pState buffer contains previous frame (phaseLen - 1) samples */
|
||||
/* pStateCurnt points to the location where the new input data should be written */
|
||||
pStateCurnt = S->pState + (phaseLen - 1u);
|
||||
|
||||
/* Total number of intput samples */
|
||||
blkCnt = blockSize;
|
||||
|
||||
/* Loop over the blockSize. */
|
||||
while(blkCnt > 0u)
|
||||
{
|
||||
/* Copy new input sample into the state buffer */
|
||||
*pStateCurnt++ = *pSrc++;
|
||||
|
||||
/* Loop over the Interpolation factor. */
|
||||
i = S->L;
|
||||
|
||||
while(i > 0u)
|
||||
{
|
||||
/* Set accumulator to zero */
|
||||
sum = 0.0f;
|
||||
|
||||
/* Initialize state pointer */
|
||||
ptr1 = pState;
|
||||
|
||||
/* Initialize coefficient pointer */
|
||||
ptr2 = pCoeffs + (i - 1u);
|
||||
|
||||
/* Loop over the polyPhase length */
|
||||
tapCnt = phaseLen;
|
||||
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
/* Perform the multiply-accumulate */
|
||||
sum += *ptr1++ * *ptr2;
|
||||
|
||||
/* Increment the coefficient pointer by interpolation factor times. */
|
||||
ptr2 += S->L;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
|
||||
/* The result is in the accumulator, store in the destination buffer. */
|
||||
*pDst++ = sum;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
i--;
|
||||
}
|
||||
|
||||
/* Advance the state pointer by 1
|
||||
* to process the next group of interpolation factor number samples */
|
||||
pState = pState + 1;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
blkCnt--;
|
||||
}
|
||||
|
||||
/* Processing is complete.
|
||||
** Now copy the last phaseLen - 1 samples to the start of the state buffer.
|
||||
** This prepares the state buffer for the next function call. */
|
||||
|
||||
/* Points to the start of the state buffer */
|
||||
pStateCurnt = S->pState;
|
||||
|
||||
tapCnt = phaseLen - 1u;
|
||||
|
||||
while(tapCnt > 0u)
|
||||
{
|
||||
*pStateCurnt++ = *pState++;
|
||||
|
||||
/* Decrement the loop counter */
|
||||
tapCnt--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* #ifndef ARM_MATH_CM0_FAMILY */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @} end of FIR_Interpolate group
|
||||
*/
|
|
@ -0,0 +1,121 @@
|
|||
/*-----------------------------------------------------------------------------
|
||||
* Copyright (C) 2010-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* $Date: 19. March 2015
|
||||
* $Revision: V.1.4.5
|
||||
*
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: arm_fir_interpolate_init_f32.c
|
||||
*
|
||||
* Description: Floating-point FIR interpolator initialization function
|
||||
*
|
||||
* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* - Neither the name of ARM LIMITED nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* ---------------------------------------------------------------------------*/
|
||||
|
||||
#include "arm_math.h"
|
||||
|
||||
/**
|
||||
* @ingroup groupFilters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup FIR_Interpolate
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialization function for the floating-point FIR interpolator.
|
||||
* @param[in,out] *S points to an instance of the floating-point FIR interpolator structure.
|
||||
* @param[in] L upsample factor.
|
||||
* @param[in] numTaps number of filter coefficients in the filter.
|
||||
* @param[in] *pCoeffs points to the filter coefficient buffer.
|
||||
* @param[in] *pState points to the state buffer.
|
||||
* @param[in] blockSize number of input samples to process per call.
|
||||
* @return The function returns ARM_MATH_SUCCESS if initialization was successful or ARM_MATH_LENGTH_ERROR if
|
||||
* the filter length <code>numTaps</code> is not a multiple of the interpolation factor <code>L</code>.
|
||||
*
|
||||
* <b>Description:</b>
|
||||
* \par
|
||||
* <code>pCoeffs</code> points to the array of filter coefficients stored in time reversed order:
|
||||
* <pre>
|
||||
* {b[numTaps-1], b[numTaps-2], b[numTaps-2], ..., b[1], b[0]}
|
||||
* </pre>
|
||||
* The length of the filter <code>numTaps</code> must be a multiple of the interpolation factor <code>L</code>.
|
||||
* \par
|
||||
* <code>pState</code> points to the array of state variables.
|
||||
* <code>pState</code> is of length <code>(numTaps/L)+blockSize-1</code> words
|
||||
* where <code>blockSize</code> is the number of input samples processed by each call to <code>arm_fir_interpolate_f32()</code>.
|
||||
*/
|
||||
|
||||
arm_status arm_fir_interpolate_init_f32(
|
||||
arm_fir_interpolate_instance_f32 * S,
|
||||
uint8_t L,
|
||||
uint16_t numTaps,
|
||||
float32_t * pCoeffs,
|
||||
float32_t * pState,
|
||||
uint32_t blockSize)
|
||||
{
|
||||
arm_status status;
|
||||
|
||||
/* The filter length must be a multiple of the interpolation factor */
|
||||
if((numTaps % L) != 0u)
|
||||
{
|
||||
/* Set status as ARM_MATH_LENGTH_ERROR */
|
||||
status = ARM_MATH_LENGTH_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Assign coefficient pointer */
|
||||
S->pCoeffs = pCoeffs;
|
||||
|
||||
/* Assign Interpolation factor */
|
||||
S->L = L;
|
||||
|
||||
/* Assign polyPhaseLength */
|
||||
S->phaseLength = numTaps / L;
|
||||
|
||||
/* Clear state buffer and size of state array is always phaseLength + blockSize - 1 */
|
||||
memset(pState, 0,
|
||||
(blockSize +
|
||||
((uint32_t) S->phaseLength - 1u)) * sizeof(float32_t));
|
||||
|
||||
/* Assign state pointer */
|
||||
S->pState = pState;
|
||||
|
||||
status = ARM_MATH_SUCCESS;
|
||||
}
|
||||
|
||||
return (status);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @} end of FIR_Interpolate group
|
||||
*/
|
32
Src/main.c
32
Src/main.c
|
@ -90,7 +90,7 @@ osThreadId ioEventTaskHandle;
|
|||
uint32_t ioEventTaskBuffer[ 384 ];
|
||||
osStaticThreadDef_t ioEventTaskControlBlock;
|
||||
osThreadId audioInputTaskHandle;
|
||||
uint32_t audioInputTaskBuffer[ 640 ];
|
||||
uint32_t audioInputTaskBuffer[ 512 ];
|
||||
osStaticThreadDef_t audioInputTaskControlBlock;
|
||||
osThreadId modulatorTaskHandle;
|
||||
uint32_t modulatorTaskBuffer[ 384 ];
|
||||
|
@ -268,7 +268,7 @@ int main(void)
|
|||
ioEventTaskHandle = osThreadCreate(osThread(ioEventTask), NULL);
|
||||
|
||||
/* definition and creation of audioInputTask */
|
||||
osThreadStaticDef(audioInputTask, startAudioInputTask, osPriorityAboveNormal, 0, 640, audioInputTaskBuffer, &audioInputTaskControlBlock);
|
||||
osThreadStaticDef(audioInputTask, startAudioInputTask, osPriorityAboveNormal, 0, 512, audioInputTaskBuffer, &audioInputTaskControlBlock);
|
||||
audioInputTaskHandle = osThreadCreate(osThread(audioInputTask), NULL);
|
||||
|
||||
/* definition and creation of modulatorTask */
|
||||
|
@ -401,12 +401,12 @@ void SystemClock_Config(void)
|
|||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
|
||||
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
|
||||
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
|
||||
RCC_OscInitStruct.MSICalibrationValue = 0;
|
||||
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
|
||||
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
|
||||
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_8;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
|
||||
RCC_OscInitStruct.PLL.PLLM = 1;
|
||||
RCC_OscInitStruct.PLL.PLLN = 40;
|
||||
RCC_OscInitStruct.PLL.PLLN = 10;
|
||||
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
|
||||
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
|
||||
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
|
||||
|
@ -439,10 +439,10 @@ void SystemClock_Config(void)
|
|||
PeriphClkInit.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1N = 24;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1N = 12;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV4;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV4;
|
||||
PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_48M2CLK|RCC_PLLSAI1_ADC1CLK;
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
|
||||
{
|
||||
|
@ -878,19 +878,19 @@ static void MX_DMA_Init(void)
|
|||
|
||||
/* DMA interrupt init */
|
||||
/* DMA1_Channel1_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 5, 0);
|
||||
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 5, 1);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
|
||||
/* DMA1_Channel2_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 5, 0);
|
||||
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 7, 1);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
|
||||
/* DMA1_Channel3_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 5, 0);
|
||||
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 6, 1);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
|
||||
/* DMA1_Channel6_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 5, 0);
|
||||
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 7, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
|
||||
/* DMA1_Channel7_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 5, 0);
|
||||
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 6, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
|
||||
/* DMA2_Channel4_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 5, 0);
|
||||
|
@ -1066,6 +1066,12 @@ void assert_failed(uint8_t* file, uint32_t line)
|
|||
}
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
|
||||
{
|
||||
snprintf(error_message, sizeof(error_message), "stack overflow %s", pcTaskName);
|
||||
while (1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -104,7 +104,7 @@ void AFSKTestTone::fill() const
|
|||
case AFSKTestTone::State::SPACE:
|
||||
if (kiss::settings().modem_type == kiss::Hardware::ModemType::M17)
|
||||
{
|
||||
getModulator().send(0x5F);
|
||||
getModulator().send(0x22);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
|
||||
namespace mobilinkd {
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "HdlcFrame.hpp"
|
||||
#include "Log.h"
|
||||
#include "main.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
namespace mobilinkd { namespace tnc { namespace hdlc {
|
||||
|
|
|
@ -99,7 +99,7 @@ void startIOEventTask(void const*)
|
|||
{
|
||||
DEBUG("RF frame");
|
||||
frame->source(frame->source() & 0x70);
|
||||
if (!ioport->write(frame, 100))
|
||||
if (!ioport->write(frame, frame->size() + 100))
|
||||
{
|
||||
ERROR("Timed out sending frame");
|
||||
// The frame has been passed to the write() call. It owns it now.
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "KissHardware.h"
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
@ -44,10 +43,10 @@ int powerOffViaUSB(void)
|
|||
namespace mobilinkd { namespace tnc { namespace kiss {
|
||||
|
||||
#ifdef NUCLEOTNC
|
||||
const char FIRMWARE_VERSION[] = "2.1.5";
|
||||
const char FIRMWARE_VERSION[] = "2.1.8";
|
||||
const char HARDWARE_VERSION[] = "Mobilinkd NucleoTNC";
|
||||
#else
|
||||
const char FIRMWARE_VERSION[] = "2.1.5";
|
||||
const char FIRMWARE_VERSION[] = "2.1.8";
|
||||
const char HARDWARE_VERSION[] = "Mobilinkd TNC3 2.1.1";
|
||||
#endif
|
||||
|
||||
|
@ -502,7 +501,7 @@ void Hardware::handle_request(hdlc::IoFrame* frame)
|
|||
|
||||
case hardware::SET_DATETIME:
|
||||
DEBUG("SET_DATETIME");
|
||||
set_rtc_datetime(&*it);
|
||||
set_rtc_datetime(static_cast<const uint8_t*>(&*it));
|
||||
[[fallthrough]];
|
||||
case hardware::GET_DATETIME:
|
||||
DEBUG("GET_DATETIME");
|
||||
|
@ -629,23 +628,22 @@ void Hardware::handle_ext_request(hdlc::IoFrame* frame) {
|
|||
}
|
||||
}
|
||||
|
||||
Hardware tmpHardware;
|
||||
|
||||
bool Hardware::load()
|
||||
{
|
||||
INFO("Loading settings from EEPROM");
|
||||
|
||||
auto tmp = std::make_unique<Hardware>();
|
||||
memset(&tmpHardware, 0, sizeof(Hardware));
|
||||
|
||||
if (!tmp) return false;
|
||||
memset(tmp.get(), 0, sizeof(Hardware));
|
||||
|
||||
if (!I2C_Storage::load(*tmp)) {
|
||||
if (!I2C_Storage::load(tmpHardware)) {
|
||||
ERROR("EEPROM read failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tmp->crc_ok())
|
||||
if (tmpHardware.crc_ok())
|
||||
{
|
||||
memcpy(this, tmp.get(), sizeof(Hardware));
|
||||
memcpy(this, &tmpHardware, sizeof(Hardware));
|
||||
return true;
|
||||
}
|
||||
ERROR("EEPROM CRC error");
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
|
||||
extern "C" void updatePtt(void);
|
||||
|
|
79
TNC/M17.cpp
79
TNC/M17.cpp
|
@ -12,7 +12,84 @@ const std::array<int16_t, FILTER_TAP_NUM> rrc_taps = {
|
|||
17634, 18510, 18510, 17634, 15966, 13661, 10930, 8014, 5155, 2569, 427,
|
||||
-1163, -2166, -2606, -2569, -2176, -1569, -886, -249, 253, 573, 698, 654,
|
||||
485, 253, 16, -176, -293, -321, -269, -158, -19, 114, 216, 269, 267, 215,
|
||||
129, 29, -62, -130, -163};
|
||||
129, 29, -62, -130, -163
|
||||
// -151, -100, -18, 80, 175, 246, 275, 249, 170, 49,
|
||||
// -90, -219, -304, -318, -245, -88, 131, 373, 581, 695,
|
||||
// 659, 437, 22, -556, -1229, -1890, -2409, -2641, -2452, -1738,
|
||||
// -441, 1434, 3816, 6563, 9480, 12334, 14880, 16891, 18179, 18622,
|
||||
// 18179, 16891, 14880, 12334, 9480, 6563, 3816, 1434, -441, -1738,
|
||||
// -2452, -2641, -2409, -1890, -1229, -556, 22, 437, 659, 695,
|
||||
// 581, 373, 131, -88, -245, -318, -304, -219, -90, 49,
|
||||
// 170, 249, 275, 246, 175, 80, -18, -100, -151, 0
|
||||
};
|
||||
|
||||
const std::array<int16_t, FILTER_TAP_NUM_9> rrc_taps_9 = {
|
||||
33, -29, -93, -143, -165, -151, -100, -18, 80, 175, 246, 275,
|
||||
249, 170, 49, -90, -219, -304, -318, -245, -88, 131, 373, 581,
|
||||
695, 659, 437, 22, -556, -1229, -1890, -2409, -2641, -2452,
|
||||
-1738, -441, 1434, 3816, 6563, 9480, 12334, 14880, 16891, 18179,
|
||||
18622, 18179, 16891, 14880, 12334, 9480, 6563, 3816, 1434, -441,
|
||||
-1738, -2452, -2641, -2409, -1890, -1229, -556, 22, 437, 659, 695,
|
||||
581, 373, 131, -88, -245, -318, -304, -219, -90, 49, 170, 249,
|
||||
275, 246, 175, 80, -18, -100, -151, -165, -143, -93, -29, 33, 0
|
||||
};
|
||||
|
||||
const std::array<int16_t, FILTER_TAP_NUM_11> rrc_taps_11 = {
|
||||
-92, -100, -87, -55, -10, 38, 81, 106, 107, 81,
|
||||
33, -29, -93, -143, -165, -151, -100, -18, 80, 175,
|
||||
246, 275, 249, 170, 49, -90, -219, -304, -318, -245,
|
||||
-88, 131, 373, 581, 695, 659, 437, 22, -556, -1229,
|
||||
-1890, -2409, -2641, -2452, -1738, -441, 1434, 3816, 6563, 9480,
|
||||
12334, 14880, 16891, 18179, 18622, 18179, 16891, 14880, 12334, 9480,
|
||||
6563, 3816, 1434, -441, -1738, -2452, -2641, -2409, -1890, -1229,
|
||||
-556, 22, 437, 659, 695, 581, 373, 131, -88, -245,
|
||||
-318, -304, -219, -90, 49, 170, 249, 275, 246, 175,
|
||||
80, -18, -100, -151, -165, -143, -93, -29, 33, 81,
|
||||
107, 106, 81, 38, -10, -55, -87, -100, -92, 0
|
||||
};
|
||||
|
||||
const std::array<int16_t, FILTER_TAP_NUM_15> rrc_taps_15 = {
|
||||
48, 51, 44, 27, 3, -21, -41, -53, -53, -40,
|
||||
-16, 12, 41, 63, 72, 66, 43, 9, -30, -67,
|
||||
-92, -100, -87, -55, -10, 38, 81, 106, 107, 81,
|
||||
33, -29, -93, -143, -165, -151, -100, -18, 80, 175,
|
||||
246, 275, 249, 170, 49, -90, -219, -304, -318, -245,
|
||||
-88, 131, 373, 581, 695, 659, 437, 22, -556, -1229,
|
||||
-1890, -2409, -2641, -2452, -1738, -441, 1434, 3816, 6563, 9480,
|
||||
12334, 14880, 16891, 18179, 18622, 18179, 16891, 14880, 12334, 9480,
|
||||
6563, 3816, 1434, -441, -1738, -2452, -2641, -2409, -1890, -1229,
|
||||
-556, 22, 437, 659, 695, 581, 373, 131, -88, -245,
|
||||
-318, -304, -219, -90, 49, 170, 249, 275, 246, 175,
|
||||
80, -18, -100, -151, -165, -143, -93, -29, 33, 81,
|
||||
107, 106, 81, 38, -10, -55, -87, -100, -92, -67,
|
||||
-30, 9, 43, 66, 72, 63, 41, 12, -16, -40,
|
||||
-53, -53, -41, -21, 3, 27, 44, 51, 48, 0
|
||||
};
|
||||
|
||||
const std::array<int16_t, FILTER_TAP_NUM_21> rrc_taps_21 = {
|
||||
-1, 1, 3, 5, 6, 5, 3, 0, -2, -5, -7, -7, -6, -4, 0, 3, 6, 8,
|
||||
7, 6, 2, -1, -5, -8, -10, -9, -6, -1, 3, 8, 12, 12, 11, 6, 0,
|
||||
-5, -10, -13, -13, -10, -4, 3, 10, 15, 18, 16, 10, 2, -7, -16,
|
||||
-23, -25, -21, -13, -2, 9, 20, 26, 26, 20, 8, -7, -23, -35, -41,
|
||||
-37, -25, -4, 20, 43, 61, 68, 62, 42, 12, -22, -54, -76, -79,
|
||||
-61, -22, 32, 93, 145, 173, 164, 109, 5, -139, -307, -472, -602,
|
||||
-660, -613, -434, -110, 358, 954, 1640, 2370, 3083, 3720, 4222,
|
||||
4544, 4655, 4544, 4222, 3720, 3083, 2370, 1640, 954, 358, -110,
|
||||
-434, -613, -660, -602, -472, -307, -139, 5, 109, 164, 173, 145,
|
||||
93, 32, -22, -61, -79, -76, -54, -22, 12, 42, 62, 68, 61, 43, 20,
|
||||
-4, -25, -37, -41, -35, -23, -7, 8, 20, 26, 26, 20, 9, -2, -13,
|
||||
-21, -25, -23, -16, -7, 2, 10, 16, 18, 15, 10, 3, -4, -10, -13,
|
||||
-13, -10, -5, 0, 6, 11, 12, 12, 8, 3, -1, -6, -9, -10, -8, -5,
|
||||
-1, 2, 6, 7, 8, 6, 3, 0, -4, -6, -7, -7, -5, -2, 0, 3, 5, 6, 5,
|
||||
3, 1, -1, 0
|
||||
};
|
||||
|
||||
const std::array<float, FILTER_TAP_NUM_9> rrc_taps_f9 = {
|
||||
0.002017321931508163, -0.0018256054303579805, -0.00571615173291049, -0.008746639552588416, -0.010105075751866371, -0.009265784007800534, -0.006136551625729697, -0.001125978562075172, 0.004891777252042491, 0.01071805138282269, 0.01505751553351295, 0.01679337935001369, 0.015256245142156299, 0.01042830577908502, 0.003031522725559901, -0.0055333532968188165, -0.013403099825723372, -0.018598682349642525, -0.01944761739590459, -0.015005271935951746, -0.0053887880354343935, 0.008056525910253532, 0.022816244158307273, 0.035513467692208076, 0.04244131815783876, 0.04025481153629372, 0.02671818654865632, 0.0013810216516704976, -0.03394615682795165, -0.07502635967975885, -0.11540977897637611, -0.14703962203941534, -0.16119995609538576, -0.14969512896336504, -0.10610329539459686, -0.026921412469634916, 0.08757875030779196, 0.23293327870303457, 0.4006012210123992, 0.5786324696325503, 0.7528286479934068, 0.908262741447522, 1.0309661131633199, 1.1095611856548013, 1.1366197723675815, 1.1095611856548013, 1.0309661131633199, 0.908262741447522, 0.7528286479934068, 0.5786324696325503, 0.4006012210123992, 0.23293327870303457, 0.08757875030779196, -0.026921412469634916, -0.10610329539459686, -0.14969512896336504, -0.16119995609538576, -0.14703962203941534, -0.11540977897637611, -0.07502635967975885, -0.03394615682795165, 0.0013810216516704976, 0.02671818654865632, 0.04025481153629372, 0.04244131815783876, 0.035513467692208076, 0.022816244158307273, 0.008056525910253532, -0.0053887880354343935, -0.015005271935951746, -0.01944761739590459, -0.018598682349642525, -0.013403099825723372, -0.0055333532968188165, 0.003031522725559901, 0.01042830577908502, 0.015256245142156299, 0.01679337935001369, 0.01505751553351295, 0.01071805138282269, 0.004891777252042491, -0.001125978562075172, -0.006136551625729697, -0.009265784007800534, -0.010105075751866371, -0.008746639552588416, -0.00571615173291049, -0.0018256054303579805, 0.002017321931508163, 0.0
|
||||
};
|
||||
|
||||
const std::array<float, FILTER_TAP_NUM_15> rrc_taps_f15 = {
|
||||
0.0029364388513841593, 0.0031468394550958484, 0.002699564567597445, 0.001661182944400927, 0.00023319405581230247, -0.0012851320781224025, -0.0025577136087664687, -0.0032843366522956313, -0.0032697038088887226, -0.0024733964729590865, -0.0010285696910973807, 0.0007766690889758685, 0.002553421969211845, 0.0038920145144327816, 0.004451886520053017, 0.00404219185231544, 0.002674727068399207, 0.0005756567993179152, -0.0018493784971116507, -0.004092346891623224, -0.005648131453822014, -0.006126925416243605, -0.005349511529163396, -0.003403189203405097, -0.0006430502751187517, 0.002365929161655135, 0.004957956568090113, 0.006506845894531803, 0.006569574194782443, 0.0050017573119839134, 0.002017321931508163, -0.0018256054303579805, -0.00571615173291049, -0.008746639552588416, -0.010105075751866371, -0.009265784007800534, -0.006136551625729697, -0.001125978562075172, 0.004891777252042491, 0.01071805138282269, 0.01505751553351295, 0.01679337935001369, 0.015256245142156299, 0.01042830577908502, 0.003031522725559901, -0.0055333532968188165, -0.013403099825723372, -0.018598682349642525, -0.01944761739590459, -0.015005271935951746, -0.0053887880354343935, 0.008056525910253532, 0.022816244158307273, 0.035513467692208076, 0.04244131815783876, 0.04025481153629372, 0.02671818654865632, 0.0013810216516704976, -0.03394615682795165, -0.07502635967975885, -0.11540977897637611, -0.14703962203941534, -0.16119995609538576, -0.14969512896336504, -0.10610329539459686, -0.026921412469634916, 0.08757875030779196, 0.23293327870303457, 0.4006012210123992, 0.5786324696325503, 0.7528286479934068, 0.908262741447522, 1.0309661131633199, 1.1095611856548013, 1.1366197723675815, 1.1095611856548013, 1.0309661131633199, 0.908262741447522, 0.7528286479934068, 0.5786324696325503, 0.4006012210123992, 0.23293327870303457, 0.08757875030779196, -0.026921412469634916, -0.10610329539459686, -0.14969512896336504, -0.16119995609538576, -0.14703962203941534, -0.11540977897637611, -0.07502635967975885, -0.03394615682795165, 0.0013810216516704976, 0.02671818654865632, 0.04025481153629372, 0.04244131815783876, 0.035513467692208076, 0.022816244158307273, 0.008056525910253532, -0.0053887880354343935, -0.015005271935951746, -0.01944761739590459, -0.018598682349642525, -0.013403099825723372, -0.0055333532968188165, 0.003031522725559901, 0.01042830577908502, 0.015256245142156299, 0.01679337935001369, 0.01505751553351295, 0.01071805138282269, 0.004891777252042491, -0.001125978562075172, -0.006136551625729697, -0.009265784007800534, -0.010105075751866371, -0.008746639552588416, -0.00571615173291049, -0.0018256054303579805, 0.002017321931508163, 0.0050017573119839134, 0.006569574194782443, 0.006506845894531803, 0.004957956568090113, 0.002365929161655135, -0.0006430502751187517, -0.003403189203405097, -0.005349511529163396, -0.006126925416243605, -0.005648131453822014, -0.004092346891623224, -0.0018493784971116507, 0.0005756567993179152, 0.002674727068399207, 0.00404219185231544, 0.004451886520053017, 0.0038920145144327816, 0.002553421969211845, 0.0007766690889758685, -0.0010285696910973807, -0.0024733964729590865, -0.0032697038088887226, -0.0032843366522956313, -0.0025577136087664687, -0.0012851320781224025, 0.00023319405581230247, 0.001661182944400927, 0.002699564567597445, 0.0031468394550958484, 0.0029364388513841593, 0.0
|
||||
};
|
||||
|
||||
}} // mobilinkd::m17
|
||||
|
|
13
TNC/M17.h
13
TNC/M17.h
|
@ -5,12 +5,25 @@
|
|||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace mobilinkd { namespace m17 {
|
||||
|
||||
constexpr size_t FILTER_TAP_NUM = 80;
|
||||
constexpr size_t FILTER_TAP_NUM_9 = 90;
|
||||
constexpr size_t FILTER_TAP_NUM_11 = 110;
|
||||
constexpr size_t FILTER_TAP_NUM_15 = 150;
|
||||
constexpr size_t FILTER_TAP_NUM_21 = 210;
|
||||
|
||||
extern const std::array<int16_t, FILTER_TAP_NUM> rrc_taps;
|
||||
extern const std::array<int16_t, FILTER_TAP_NUM_9> rrc_taps_9;
|
||||
extern const std::array<int16_t, FILTER_TAP_NUM_11> rrc_taps_11;
|
||||
extern const std::array<int16_t, FILTER_TAP_NUM_15> rrc_taps_15;
|
||||
extern const std::array<int16_t, FILTER_TAP_NUM_21> rrc_taps_21;
|
||||
|
||||
extern const std::array<float, FILTER_TAP_NUM_9> rrc_taps_f9;
|
||||
extern const std::array<float, FILTER_TAP_NUM_15> rrc_taps_f15;
|
||||
|
||||
constexpr std::array<uint8_t, 2> LSF_SYNC = { 0x55, 0xF7 };
|
||||
constexpr std::array<uint8_t, 2> STREAM_SYNC = { 0xFF, 0x5D };
|
||||
constexpr std::array<uint8_t, 2> PACKET_SYNC = { 0x75, 0xFF };
|
||||
|
|
|
@ -16,7 +16,7 @@ void M17Demodulator::start()
|
|||
{
|
||||
SysClock80();
|
||||
|
||||
demod_filter.init(m17::rrc_taps.data());
|
||||
demod_filter.init(m17::rrc_taps_9.data());
|
||||
passall(kiss::settings().options & KISS_OPTION_PASSALL);
|
||||
|
||||
hadc1.Init.OversamplingMode = DISABLE;
|
||||
|
@ -36,7 +36,7 @@ void M17Demodulator::start()
|
|||
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
|
||||
CxxErrorHandler();
|
||||
|
||||
startADC(1666, ADC_BLOCK_SIZE);
|
||||
startADC(1665, ADC_BLOCK_SIZE);
|
||||
// getModulator().start_loopback();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,12 +43,12 @@ struct M17Demodulator : IDemodulator
|
|||
static constexpr uint32_t SAMPLE_RATE = 48000;
|
||||
static constexpr uint16_t VREF = 4095;
|
||||
|
||||
using audio_filter_t = Q15FirFilter<ADC_BLOCK_SIZE, m17::FILTER_TAP_NUM>;
|
||||
using audio_filter_t = Q15FirFilter<ADC_BLOCK_SIZE, m17::FILTER_TAP_NUM_9>;
|
||||
using demod_result_t = std::tuple<float, float, int, float>;
|
||||
|
||||
enum class DemodState { UNLOCKED, LSF_SYNC, FRAME_SYNC, FRAME };
|
||||
|
||||
audio_filter_t demod_filter{m17::rrc_taps.data()};
|
||||
audio_filter_t demod_filter{m17::rrc_taps_9.data()};
|
||||
const float sample_rate = 48000.0;
|
||||
const float symbol_rate = 4800.0;
|
||||
float gain = 0.01;
|
||||
|
@ -109,6 +109,7 @@ struct M17Demodulator : IDemodulator
|
|||
decoder.passall(enabled);
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void frame(demod_result_t demod_result, hdlc::IoFrame*& result)
|
||||
{
|
||||
auto [sample, phase, symbol, evm] = demod_result;
|
||||
|
@ -186,8 +187,9 @@ struct M17Demodulator : IDemodulator
|
|||
sync_count = 0;
|
||||
std::copy(tmp, tmp + len, buffer.begin());
|
||||
auto valid = decoder(sync_word_type, buffer, result, ber);
|
||||
if (!valid)
|
||||
switch (valid)
|
||||
{
|
||||
case M17FrameDecoder::DecodeResult::FAIL:
|
||||
WARN("decode invalid");
|
||||
if (result && !passall_)
|
||||
{
|
||||
|
@ -195,10 +197,13 @@ struct M17Demodulator : IDemodulator
|
|||
if (result) hdlc::release(result);
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
case M17FrameDecoder::DecodeResult::EOS:
|
||||
demodState = DemodState::LSF_SYNC;
|
||||
break;
|
||||
case M17FrameDecoder::DecodeResult::OK:
|
||||
INFO("valid frame for sync word type %d", int(sync_word_type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +219,7 @@ struct M17Demodulator : IDemodulator
|
|||
}
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
demod_result_t demod()
|
||||
{
|
||||
int16_t polarity = kiss::settings().rx_rev_polarity() ? -1 : 1;
|
||||
|
|
|
@ -78,7 +78,7 @@ void M17Encoder::run()
|
|||
osThreadResume(encoderTaskHandle);
|
||||
|
||||
auto start = osKernelSysTick();
|
||||
uint32_t delay_ms = 0;
|
||||
int32_t delay_ms = 0;
|
||||
|
||||
state = State::IDLE;
|
||||
|
||||
|
@ -118,14 +118,23 @@ void M17Encoder::run()
|
|||
}
|
||||
|
||||
evt = osMessagePeek(input_queue, delay_ms);
|
||||
auto msgs = osMessageWaiting(input_queue);
|
||||
// auto num_msgs = osMessageWaiting(input_queue);
|
||||
back2back = (evt.status == osEventMessage);
|
||||
if (!back2back)
|
||||
{
|
||||
if (state != State::IDLE)
|
||||
{
|
||||
state = State::IDLE;
|
||||
WARN("Timed out waiting for packet (%lums).", delay_ms);
|
||||
size_t counter = 5;
|
||||
do {
|
||||
send_link_setup();
|
||||
evt = osMessagePeek(input_queue, 40);
|
||||
} while (evt.status != osEventMessage && --counter != 0);
|
||||
|
||||
if (evt.status != osEventMessage) {
|
||||
state = State::IDLE;
|
||||
WARN("Timed out waiting for packet.");
|
||||
}
|
||||
}
|
||||
delay_ms = 0;
|
||||
}
|
||||
|
@ -235,16 +244,16 @@ void M17Encoder::send_preamble()
|
|||
|
||||
void M17Encoder::send_link_setup()
|
||||
{
|
||||
punctured.fill(0);
|
||||
m17_frame.fill(0);
|
||||
auto frame = tnc::hdlc::acquire_wait();
|
||||
|
||||
// Encoder, puncture, interleave & randomize.
|
||||
auto encoded = conv_encode(current_lsf);
|
||||
puncture_bytes(encoded, punctured, P1);
|
||||
interleaver.interleave(punctured);
|
||||
randomizer(punctured);
|
||||
puncture_bytes(encoded, m17_frame, P1);
|
||||
interleaver.interleave(m17_frame);
|
||||
randomizer(m17_frame);
|
||||
for (auto c : m17::LSF_SYNC) frame->push_back(c);
|
||||
for (auto c : punctured) frame->push_back(c);
|
||||
for (auto c : m17_frame) frame->push_back(c);
|
||||
|
||||
auto status = osMessagePut(
|
||||
m17EncoderInputQueueHandle,
|
||||
|
@ -253,7 +262,7 @@ void M17Encoder::send_link_setup()
|
|||
if (status != osOK)
|
||||
{
|
||||
tnc::hdlc::release(frame);
|
||||
WARN("M17 failed to send preamble");
|
||||
WARN("M17 failed to send LSF");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,18 +315,16 @@ void M17Encoder::send_full_packet(tnc::hdlc::IoFrame* frame)
|
|||
|
||||
void M17Encoder::send_packet_frame(const std::array<uint8_t, 26>& packet_frame)
|
||||
{
|
||||
frame_t punctured;
|
||||
|
||||
// Encoder, puncture, interleave & randomize.
|
||||
auto encoded = conv_encode(packet_frame, 206);
|
||||
puncture_bytes(encoded, punctured, P3);
|
||||
interleaver.interleave(punctured);
|
||||
randomizer(punctured);
|
||||
puncture_bytes(encoded, m17_frame, P3);
|
||||
interleaver.interleave(m17_frame);
|
||||
randomizer(m17_frame);
|
||||
|
||||
auto frame = tnc::hdlc::acquire_wait();
|
||||
|
||||
for (auto c : m17::PACKET_SYNC) frame->push_back(c);
|
||||
for (auto c : punctured) frame->push_back(c);
|
||||
for (auto c : m17_frame) frame->push_back(c);
|
||||
|
||||
auto status = osMessagePut(
|
||||
m17EncoderInputQueueHandle,
|
||||
|
@ -332,9 +339,6 @@ void M17Encoder::send_packet_frame(const std::array<uint8_t, 26>& packet_frame)
|
|||
|
||||
void M17Encoder::send_stream(tnc::hdlc::IoFrame* frame, FrameType)
|
||||
{
|
||||
payload_t punctured; // Punctured audio payload (272 bits, 34 bytes).
|
||||
frame_t m17_frame;
|
||||
|
||||
// Construct LICH.
|
||||
auto it = frame->begin();
|
||||
std::advance(it, 6);
|
||||
|
@ -347,9 +351,11 @@ void M17Encoder::send_stream(tnc::hdlc::IoFrame* frame, FrameType)
|
|||
std::array<uint8_t, 20> data;
|
||||
std::copy(it, frame->end(), data.begin());
|
||||
|
||||
if (data[0] & 0x80) state = State::IDLE; // EOS
|
||||
|
||||
auto encoded = conv_encode(data);
|
||||
puncture_bytes(encoded, punctured, P2);
|
||||
std::copy(punctured.begin(), punctured.end(), fit); // Copy after LICH.
|
||||
puncture_bytes(encoded, stream_payload, P2);
|
||||
std::copy(stream_payload.begin(), stream_payload.end(), fit); // Copy after LICH.
|
||||
|
||||
interleaver.interleave(m17_frame); // Interleave entire frame.
|
||||
randomizer(m17_frame); // Randomize entire frame.
|
||||
|
@ -409,6 +415,7 @@ void M17Encoder::create_link_setup(tnc::hdlc::IoFrame* frame, FrameType type)
|
|||
/**
|
||||
* Encode each LSF segment into a Golay-encoded LICH segment bitstream.
|
||||
*/
|
||||
[[gnu::noinline]]
|
||||
M17Encoder::lich_segment_t M17Encoder::make_lich_segment(
|
||||
std::array<uint8_t, 6> segment)
|
||||
{
|
||||
|
@ -511,6 +518,7 @@ void M17Encoder::encoderTask(void const*)
|
|||
{
|
||||
osEvent evt = osMessageGet(m17EncoderInputQueueHandle, osWaitForever);
|
||||
if (evt.status != osEventMessage) continue;
|
||||
|
||||
auto frame = static_cast<IoFrame*>(evt.value.p);
|
||||
if (frame->size() != 48) WARN("Bad frame size %u", frame->size());
|
||||
|
||||
|
|
|
@ -189,7 +189,8 @@ private:
|
|||
osThreadId encoderTaskHandle;
|
||||
State state = State::INACTIVE;
|
||||
|
||||
frame_t punctured;
|
||||
frame_t m17_frame;
|
||||
payload_t stream_payload;
|
||||
lsf_t current_lsf;
|
||||
LinkSetupFrame::encoded_call_t src;
|
||||
LinkSetupFrame::encoded_call_t dest;
|
||||
|
|
|
@ -152,8 +152,10 @@ struct M17FrameDecoder
|
|||
Viterbi<decltype(trellis_), 4> viterbi_{trellis_};
|
||||
CRC16<0x5935, 0xFFFF> crc_;
|
||||
|
||||
|
||||
enum class State {LSF, STREAM, BASIC_PACKET, FULL_PACKET};
|
||||
enum class SyncWordType { LSF, STREAM, PACKET, RESERVED };
|
||||
enum class DecodeResult { FAIL, OK, EOS };
|
||||
|
||||
State state_ = State::LSF;
|
||||
|
||||
|
@ -172,6 +174,7 @@ struct M17FrameDecoder
|
|||
audio_callback_t audio_callback_;
|
||||
union
|
||||
{
|
||||
std::array<uint8_t, 30> lich;
|
||||
std::array<uint8_t, 240> lsf;
|
||||
std::array<uint8_t, 206> packet;
|
||||
std::array<uint8_t, 160> stream;
|
||||
|
@ -261,7 +264,8 @@ struct M17FrameDecoder
|
|||
* @param ber
|
||||
* @return
|
||||
*/
|
||||
bool decode_lsf(buffer_t& buffer, tnc::hdlc::IoFrame*& lsf, int& ber)
|
||||
[[gnu::noinline]]
|
||||
DecodeResult decode_lsf(buffer_t& buffer, tnc::hdlc::IoFrame*& lsf, int& ber)
|
||||
{
|
||||
depuncture(buffer, tmp.lsf, P1);
|
||||
ber = viterbi_.decode(tmp.lsf, output.lsf);
|
||||
|
@ -282,16 +286,16 @@ struct M17FrameDecoder
|
|||
lsf->push_back(0);
|
||||
lsf->push_back(0);
|
||||
lsf->source(0x20);
|
||||
return true;
|
||||
return DecodeResult::OK;
|
||||
}
|
||||
lsf = nullptr;
|
||||
return true;
|
||||
return DecodeResult::OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
lich_segments = 0;
|
||||
output.lsf.fill(0);
|
||||
return false;
|
||||
return DecodeResult::FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,7 +319,7 @@ struct M17FrameDecoder
|
|||
return false;
|
||||
}
|
||||
decoded >>= 12; // Remove check bits and parity.
|
||||
INFO("Golay decode good for %08lx (%du)", decoded, i);
|
||||
DEBUG("Golay decode good for %08lx (%du)", decoded, i);
|
||||
// append codeword.
|
||||
if (i & 1)
|
||||
{
|
||||
|
@ -331,47 +335,51 @@ struct M17FrameDecoder
|
|||
return true;
|
||||
}
|
||||
|
||||
bool decode_lich(buffer_t& buffer, tnc::hdlc::IoFrame*& lsf, int& ber)
|
||||
[[gnu::noinline]]
|
||||
DecodeResult decode_lich(buffer_t& buffer, tnc::hdlc::IoFrame*& lsf, int& ber)
|
||||
{
|
||||
tmp.lich.fill(0);
|
||||
// Read the 4 12-bit codewords from LICH into buffers.lich.
|
||||
if (!unpack_lich(buffer)) return false;
|
||||
if (!unpack_lich(buffer)) return DecodeResult::FAIL;
|
||||
|
||||
uint8_t fragment_number = tmp.lich[5]; // Get fragment number.
|
||||
fragment_number = (fragment_number >> 5) & 7;
|
||||
|
||||
// Copy decoded LICH to superframe buffer.
|
||||
std::copy(tmp.lich.begin(), tmp.lich.begin() + 5,
|
||||
output.lsf.begin() + (fragment_number * 5));
|
||||
output.lich.begin() + (fragment_number * 5));
|
||||
|
||||
lich_segments |= (1 << fragment_number); // Indicate segment received.
|
||||
INFO("got segment %d, have %02x", int(fragment_number), int(lich_segments));
|
||||
if (lich_segments != 0x3F) return false; // More to go...
|
||||
if (lich_segments != 0x3F) return DecodeResult::FAIL; // More to go...
|
||||
|
||||
detail::to_bytes(output.lsf, current_lsf);
|
||||
crc_.reset();
|
||||
for (auto c : current_lsf) crc_(c);
|
||||
for (auto c : output.lich) crc_(c);
|
||||
auto checksum = crc_.get();
|
||||
INFO("LICH crc = %04x", checksum);
|
||||
if (checksum == 0)
|
||||
{
|
||||
state_ = State::STREAM;
|
||||
lsf = tnc::hdlc::acquire_wait();
|
||||
for (auto c : current_lsf) lsf->push_back(c);
|
||||
for (auto c : output.lich) lsf->push_back(c);
|
||||
lsf->push_back(0);
|
||||
lsf->push_back(0);
|
||||
lsf->source(0x20);
|
||||
ber = 0;
|
||||
return true;
|
||||
return DecodeResult::OK;
|
||||
}
|
||||
#ifdef KISS_LOGGING
|
||||
dump(output.lich);
|
||||
#endif
|
||||
// Failed CRC... try again.
|
||||
lich_segments = 0;
|
||||
output.lsf.fill(0);
|
||||
output.lich.fill(0);
|
||||
ber = 128;
|
||||
return false;
|
||||
return DecodeResult::FAIL;
|
||||
}
|
||||
|
||||
bool decode_stream(buffer_t& buffer, tnc::hdlc::IoFrame*& stream, int& ber)
|
||||
[[gnu::noinline]]
|
||||
DecodeResult decode_stream(buffer_t& buffer, tnc::hdlc::IoFrame*& stream, int& ber)
|
||||
{
|
||||
std::array<uint8_t, 20> stream_segment;
|
||||
|
||||
|
@ -391,10 +399,15 @@ struct M17FrameDecoder
|
|||
for (auto c : stream_segment) crc_(c);
|
||||
auto checksum = crc_.get();
|
||||
INFO("crc = %04x", checksum); // Otherwise ignored.
|
||||
if ((checksum == 0) && (stream_segment[0] & 0x80))
|
||||
{
|
||||
INFO("EOS");
|
||||
state_ = State::LSF;
|
||||
}
|
||||
stream->push_back(0);
|
||||
stream->push_back(0);
|
||||
stream->source(0x20);
|
||||
return true;
|
||||
return state_ == State::LSF ? DecodeResult::EOS : DecodeResult::OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -408,7 +421,8 @@ struct M17FrameDecoder
|
|||
* @param ber the estimated BER (really more SNR) of the packet.
|
||||
* @return true if a valid packet is returned, otherwise false.
|
||||
*/
|
||||
bool decode_basic_packet(buffer_t& buffer, tnc::hdlc::IoFrame*& packet, int& ber)
|
||||
[[gnu::noinline]]
|
||||
DecodeResult decode_basic_packet(buffer_t& buffer, tnc::hdlc::IoFrame*& packet, int& ber)
|
||||
{
|
||||
std::array<uint8_t, 26> packet_segment;
|
||||
|
||||
|
@ -439,7 +453,7 @@ struct M17FrameDecoder
|
|||
current_packet->source(0);
|
||||
packet = current_packet;
|
||||
current_packet = nullptr;
|
||||
return true;
|
||||
return DecodeResult::OK;
|
||||
}
|
||||
WARN("packet bad fcs = %04x, crc = %04x", current_packet->fcs(), current_packet->crc());
|
||||
if (passall_)
|
||||
|
@ -452,7 +466,7 @@ struct M17FrameDecoder
|
|||
tnc::hdlc::release(current_packet);
|
||||
current_packet = nullptr;
|
||||
}
|
||||
return false;
|
||||
return DecodeResult::FAIL;
|
||||
}
|
||||
|
||||
size_t frame_number = (packet_segment[25] & 0x7F) >> 2;
|
||||
|
@ -467,7 +481,7 @@ struct M17FrameDecoder
|
|||
}
|
||||
|
||||
packet = nullptr;
|
||||
return true;
|
||||
return DecodeResult::OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -481,7 +495,8 @@ struct M17FrameDecoder
|
|||
* @param ber
|
||||
* @return
|
||||
*/
|
||||
bool decode_full_packet(buffer_t& buffer, tnc::hdlc::IoFrame*& packet, int& ber)
|
||||
[[gnu::noinline]]
|
||||
DecodeResult decode_full_packet(buffer_t& buffer, tnc::hdlc::IoFrame*& packet, int& ber)
|
||||
{
|
||||
std::array<uint8_t, 26> packet_segment;
|
||||
|
||||
|
@ -510,7 +525,7 @@ struct M17FrameDecoder
|
|||
current_packet = nullptr;
|
||||
packet_frame_counter = 0;
|
||||
state_ = State::LSF;
|
||||
return true;
|
||||
return DecodeResult::OK;
|
||||
}
|
||||
|
||||
size_t frame_number = (packet_segment[25] & 0x7F) >> 2;
|
||||
|
@ -525,7 +540,7 @@ struct M17FrameDecoder
|
|||
}
|
||||
|
||||
packet = nullptr;
|
||||
return true;
|
||||
return DecodeResult::OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -564,7 +579,8 @@ struct M17FrameDecoder
|
|||
* - FULL_PACKET when any packet frame is received.
|
||||
* - LSF when the EOS indicator is set, or when a stream frame is received.
|
||||
*/
|
||||
bool operator()(SyncWordType frame_type, buffer_t& buffer,
|
||||
[[gnu::noinline]]
|
||||
DecodeResult operator()(SyncWordType frame_type, buffer_t& buffer,
|
||||
tnc::hdlc::IoFrame*& result, int& ber)
|
||||
{
|
||||
derandomize_(buffer);
|
||||
|
@ -603,7 +619,7 @@ struct M17FrameDecoder
|
|||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return DecodeResult::FAIL;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@ void M17Modulator::init(const kiss::Hardware& hw)
|
|||
SysClock80();
|
||||
|
||||
// Configure 80MHz clock for 48kHz.
|
||||
htim7.Init.Period = 1666;
|
||||
htim7.Init.Period = 1665;
|
||||
htim7.Init.Prescaler = 0;
|
||||
if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
|
||||
{
|
||||
ERROR("htim7 init failed");
|
||||
|
|
|
@ -26,29 +26,30 @@ struct M17Modulator : Modulator
|
|||
// Six buffers per M17 frame, or 12 half-buffer interrupts.
|
||||
static constexpr uint8_t UPSAMPLE = 10;
|
||||
static constexpr uint32_t BLOCKSIZE = 4;
|
||||
static constexpr uint32_t STATE_SIZE = (m17::FILTER_TAP_NUM / UPSAMPLE) + BLOCKSIZE - 1;
|
||||
static constexpr uint32_t STATE_SIZE = (m17::FILTER_TAP_NUM_15 / UPSAMPLE) + BLOCKSIZE - 1;
|
||||
static constexpr int16_t DAC_BUFFER_LEN = 80; // 8 symbols, 16 bits, 2 bytes.
|
||||
static constexpr int16_t TRANSFER_LEN = DAC_BUFFER_LEN / 2; // 4 symbols, 8 bits, 1 byte.
|
||||
static constexpr uint16_t VREF = 4095;
|
||||
enum class State { STOPPED, STARTING, RUNNING, STOPPING };
|
||||
|
||||
arm_fir_interpolate_instance_q15 fir_interpolator;
|
||||
std::array<q15_t, STATE_SIZE> fir_state;
|
||||
arm_fir_interpolate_instance_f32 fir_interpolator;
|
||||
std::array<float, STATE_SIZE> fir_state;
|
||||
std::array<int16_t, DAC_BUFFER_LEN> buffer_;
|
||||
std::array<int16_t, 4> symbols;
|
||||
std::array<float, 4> symbols;
|
||||
osMessageQId dacOutputQueueHandle_{0};
|
||||
PTT* ptt_{nullptr};
|
||||
uint16_t volume_{4096};
|
||||
volatile uint16_t delay_count = 0; // TX Delay
|
||||
volatile uint16_t stop_count = 0; // Flush the RRC matched filter.
|
||||
State state{State::STOPPED};
|
||||
float tmp[TRANSFER_LEN];
|
||||
|
||||
M17Modulator(osMessageQId queue, PTT* ptt)
|
||||
: dacOutputQueueHandle_(queue), ptt_(ptt)
|
||||
{
|
||||
arm_fir_interpolate_init_q15(
|
||||
&fir_interpolator, UPSAMPLE, m17::FILTER_TAP_NUM,
|
||||
(q15_t*) m17::rrc_taps.data(), fir_state.data(), BLOCKSIZE);
|
||||
arm_fir_interpolate_init_f32(
|
||||
&fir_interpolator, UPSAMPLE, m17::FILTER_TAP_NUM_15,
|
||||
(float32_t*) m17::rrc_taps_f15.data(), fir_state.data(), BLOCKSIZE);
|
||||
}
|
||||
|
||||
~M17Modulator() override {}
|
||||
|
@ -96,6 +97,7 @@ struct M17Modulator : Modulator
|
|||
void send(uint8_t bits) override
|
||||
{
|
||||
uint16_t txdelay = 0;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case State::STOPPING:
|
||||
|
@ -115,7 +117,7 @@ struct M17Modulator : Modulator
|
|||
start_conversion();
|
||||
ptt_->on();
|
||||
while (delay_count < txdelay) osThreadYield();
|
||||
stop_count = 2; // 8 symbols to flush the RRC filter.
|
||||
stop_count = 4; // 16 symbols to flush the RRC filter.
|
||||
osMessagePut(dacOutputQueueHandle_, bits, osWaitForever);
|
||||
state = State::RUNNING;
|
||||
break;
|
||||
|
@ -126,12 +128,13 @@ struct M17Modulator : Modulator
|
|||
}
|
||||
|
||||
// DAC DMA interrupt functions.
|
||||
|
||||
[[gnu::noinline]]
|
||||
void fill_first(uint8_t bits) override
|
||||
{
|
||||
fill(buffer_.data(), bits);
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void fill_last(uint8_t bits) override
|
||||
{
|
||||
fill(buffer_.data() + TRANSFER_LEN, bits);
|
||||
|
@ -256,11 +259,13 @@ private:
|
|||
DAC_ALIGN_12B_R);
|
||||
}
|
||||
|
||||
uint16_t adjust_level(int32_t sample) const
|
||||
uint16_t adjust_level(float sample) const
|
||||
{
|
||||
sample *= volume_;
|
||||
sample >>= 12;
|
||||
sample /= 8;
|
||||
sample += 2048;
|
||||
if (sample > 4095) sample = 4095;
|
||||
else if (sample < 0) sample = 0;
|
||||
return sample;
|
||||
}
|
||||
|
||||
|
@ -276,35 +281,51 @@ private:
|
|||
return 0;
|
||||
}
|
||||
|
||||
constexpr int16_t symbol_skew(int32_t symbol)
|
||||
{
|
||||
const size_t shift = 8;
|
||||
if (symbol == 1 || symbol == -1)
|
||||
{
|
||||
int32_t offset = ((symbol * (kiss::settings().tx_twist - 50)) << shift) / 50;
|
||||
return (symbol << shift) - offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
return symbol << shift;
|
||||
}
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void fill(int16_t* buffer, uint8_t bits)
|
||||
{
|
||||
int16_t polarity = kiss::settings().tx_rev_polarity() ? -1 : 1;
|
||||
|
||||
for (size_t i = 0; i != 4; ++i)
|
||||
{
|
||||
symbols[i] = (bits_to_symbol(bits >> 6) << 10) * polarity;
|
||||
symbols[i] = bits_to_symbol(bits >> 6) * polarity;
|
||||
bits <<= 2;
|
||||
}
|
||||
|
||||
arm_fir_interpolate_q15(
|
||||
&fir_interpolator, symbols.data(), buffer, BLOCKSIZE);
|
||||
arm_fir_interpolate_f32(
|
||||
&fir_interpolator, symbols.data(), tmp, BLOCKSIZE);
|
||||
|
||||
for (size_t i = 0; i != TRANSFER_LEN; ++i)
|
||||
{
|
||||
buffer[i] = adjust_level(buffer[i]);
|
||||
buffer[i] = adjust_level(tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void fill_empty(int16_t* buffer)
|
||||
{
|
||||
symbols.fill(0);
|
||||
|
||||
arm_fir_interpolate_q15(
|
||||
&fir_interpolator, symbols.data(), buffer, BLOCKSIZE);
|
||||
arm_fir_interpolate_f32(
|
||||
&fir_interpolator, symbols.data(), tmp, BLOCKSIZE);
|
||||
|
||||
for (size_t i = 0; i != TRANSFER_LEN; ++i)
|
||||
{
|
||||
buffer[i] = adjust_level(buffer[i]);
|
||||
buffer[i] = adjust_level(tmp[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
#include "Convolution.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
|
||||
namespace mobilinkd
|
||||
{
|
||||
|
@ -107,27 +109,62 @@ struct Viterbi
|
|||
state_transition_t nextState_;
|
||||
state_transition_t prevState_;
|
||||
|
||||
metrics_t prevMetrics, currMetrics;
|
||||
|
||||
std::array<std::bitset<NumStates>, 244> history_storage_;
|
||||
|
||||
Viterbi(Trellis_ trellis)
|
||||
: cost_(makeCost<Trellis_, LLR_>(trellis))
|
||||
, nextState_(makeNextState(trellis))
|
||||
, prevState_(makePrevState(trellis))
|
||||
{}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void calculate_path_metric(
|
||||
const std::array<int16_t, NumStates / 2>& cost0,
|
||||
const std::array<int16_t, NumStates / 2>& cost1,
|
||||
std::bitset<NumStates>& hist,
|
||||
size_t j
|
||||
) {
|
||||
auto& i0 = nextState_[j][0];
|
||||
auto& i1 = nextState_[j][1];
|
||||
|
||||
int16_t c0 = cost0[j];
|
||||
int16_t c1 = cost1[j];
|
||||
|
||||
auto& p0 = prevMetrics[j];
|
||||
auto& p1 = prevMetrics[j + NumStates / 2];
|
||||
|
||||
int32_t m0 = p0 + c0;
|
||||
int32_t m1 = p0 + c1;
|
||||
int32_t m2 = p1 + c1;
|
||||
int32_t m3 = p1 + c0;
|
||||
|
||||
bool d0 = m0 > m2;
|
||||
bool d1 = m1 > m3;
|
||||
|
||||
hist.set(i0, d0);
|
||||
hist.set(i1, d1);
|
||||
currMetrics[i0] = d0 ? m2 : m0;
|
||||
currMetrics[i1] = d1 ? m3 : m1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Viterbi soft decoder using LLR inputs where 0 == erasure.
|
||||
*
|
||||
* @return path metric for estimating BER.
|
||||
*/
|
||||
template <size_t IN, size_t OUT>
|
||||
size_t decode(std::array<int8_t, IN> in, std::array<uint8_t, OUT>& out)
|
||||
size_t decode(std::array<int8_t, IN> const& in, std::array<uint8_t, OUT>& out)
|
||||
{
|
||||
static_assert(sizeof(history_storage_) >= IN / 2);
|
||||
|
||||
constexpr auto MAX_METRIC = std::numeric_limits<typename metrics_t::value_type>::max() / 2;
|
||||
|
||||
metrics_t prevMetrics, currMetrics;
|
||||
prevMetrics.fill(MAX_METRIC);
|
||||
prevMetrics[0] = 0; // Starting point.
|
||||
|
||||
std::array<std::bitset<NumStates>, IN / 2> history;
|
||||
std::span history(history_storage_.begin(), history_storage_.begin() + IN / 2);
|
||||
|
||||
constexpr size_t BUTTERFLY_SIZE = NumStates / 2;
|
||||
|
||||
|
@ -150,27 +187,7 @@ struct Viterbi
|
|||
|
||||
for (size_t j = 0; j != BUTTERFLY_SIZE; ++j)
|
||||
{
|
||||
auto& i0 = nextState_[j][0];
|
||||
auto& i1 = nextState_[j][1];
|
||||
|
||||
int16_t c0 = cost0[j];
|
||||
int16_t c1 = cost1[j];
|
||||
|
||||
auto& p0 = prevMetrics[j];
|
||||
auto& p1 = prevMetrics[j + BUTTERFLY_SIZE];
|
||||
|
||||
int32_t m0 = p0 + c0;
|
||||
int32_t m1 = p0 + c1;
|
||||
int32_t m2 = p1 + c1;
|
||||
int32_t m3 = p1 + c0;
|
||||
|
||||
bool d0 = m0 > m2;
|
||||
bool d1 = m1 > m3;
|
||||
|
||||
hist.set(i0, d0);
|
||||
hist.set(i1, d1);
|
||||
currMetrics[i0] = d0 ? m2 : m0;
|
||||
currMetrics[i1] = d1 ? m3 : m1;
|
||||
calculate_path_metric(cost0, cost1, hist, j);
|
||||
}
|
||||
std::swap(currMetrics, prevMetrics);
|
||||
hindex += 1;
|
||||
|
|
Ładowanie…
Reference in New Issue