updated ui added new features

This commit is contained in:
zach
2025-12-27 15:32:32 -07:00
parent 02ca7801ea
commit a2cfae3a22
589 changed files with 181780 additions and 569 deletions
+259
View File
@@ -0,0 +1,259 @@
# README Codec2 STM32 Unit Test
Don Reid 2018/2019
This is the unittest system for the stm32 implementation of
codec2/FreeDV which runs on Linux systems. It requires a STM32F4xx
processor development board connected to/having a ST-LINK, e.g. a
STM32F4 Discovery board.
## Quickstart
Requirements:
* python3/numpy
* arm-none-eabi-gdb install and in your path (see codec2/stm32/README.md)
* STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 (see codec2/stm32/README.md)
* build openocd from source and have it in your path (see below)
Build codec2 for x86 Linux with unittests. This generates several artifacts required for the stm32 tests:
```
$ cd ~/codec2
$ mkdir build_linux && cd build_linux && cmake -DUNITTEST=1 .. && make
```
Now build for the stm32, and run the stm32 ctests:
```
$ cd ~/codec2/stm32 && mkdir build_stm32 && cd build_stm32
$ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/STM32_Toolchain.cmake -DPERIPHLIBDIR=~/Downloads/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 ..
$ make
$ sudo apt install python3-numpy libncurses5
$ ctest -V
```
You should see tests executing (and passing). They are slow to execute
(30 to 180 seconds each), due to the speed of the semihosting system.
## If a Test fails
Explore the files in ```codec2/stm32/unittest/test_run/name_of_test```
When each test runs, a directory is created, and several log files generated.
## Running the stm32 Unit Tests
1. Tests can be run using the ctest utility (part of cmake)
```
$ cd ~/codec2/stm32/build_stm32
$ ctest
```
You can pass -V to see more output:
```
$ ctest -V
```
You can pass -R <pattern> to run test matching <pattern>. Please note,
that some test have dependencies and will have to run other tests before
being executed
```
$ ctest -R ofdm
```
To list the available ctests:
```
$ ctest -N
```
1. To run a single test. This test exercises the entire 700D receive side,
and measures CPU load and memory:
```
$ cd ~/codec2/stm32/unittest
$ ./scripts/run_stm32_tst tst_ofdm_api_demod 700D_AWGN_codec
```
In general:
```
$ ./scripts/run_stm32_test <name_of_test> <test_option>
```
1. To run a test set (example):
```
$ cd ~/codec2/stm32/unittest
$ ./scripts/run_all_ldpc_tests
```
In general: (codec2, ofdm, ldpc):
```
$ ./scripts/run_all_<set_name>_tests
```
## When tests fail
1. If a test fails, explore the files in the ```test_run``` directory for that test.
1. Try building with ALLOC_DEBUG can be helpful with heap issues:
```
$ CFLAGS=-DEBUG_ALLOC cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/STM32_Toolchain.cmake \
-DPERIPHLIBDIR=~/Downloads/STM32F4xx_DSP_StdPeriph_Lib_V1.8.0 ..
```
## Sequence of a Test
Consider the example:
```
build_stm32$ ctest -R tst_ldpc_dec_noise
```
1. The test is kicked off based on `src/CMakeLists.txt`, which calls `scipts/run_stm32_tst`
1. `run_stm32_tst` calls the test setup script, e.g. `tst_ldpc_dec_setup`. Typically, this will run a host version to generate a reference.
1. `run_stm32_tst` runs the stm32 executable on the Discovery, e.g. `tst_ldpc_dec`, the source is in `src/tst_ldpc_dec.c`
1. The steup and check scripts can handle many sub cases, e.g. `ideal` and `noise`.
1. `run_stm32_tst` calls the test check script, e.g. `tst_ldpc_dec_check` which typically compares the host generated reference to the output from the stm32.
1. As the test runs, various files are generated in `test_run/tst_ldpc_dec_noise`
1. When debugging it's useful to run the ctest with the verbose option:
```
$ ctest -V -R tst_ldpc_dec_noise
```
Set the `-x` at the top of the scripts to trace execution:
```
#!/bin/bash -x
#
# tst_ldpc_enc_check
```
## Directory Structure
| Path | Description |
| --- | --- |
| `scripts` | Scripts for unittest system
| `src` | stm32 C sources
| `\src\CMakeLists.txt` | ctests are defined here
| `lib/python`| Python library files
| `lib/octave`| Octave library files
| `test_run` | Files created by each test as it runs
## Running the tests remotely
If the stm32 hardware is connected on a different pc with linux, the tests can be run remotely.
Test will run slower, roughly 3 times.
1. You have to build OpenOCD on the remote machine with the STM32 board. It must be built from
(https://github.com/db4ple/openocd.git).
1. You don't need OpenOCD installed on your build pc.
1. You have to be able to run ssh with public key authentication using ssh-agent so that
you can ssh into the remote machine without entering a password.
1. You have to call ctest with the proper UT_SSH_PARAMS settings, e.g.
```
UT_SSH_PARAMS="-p 22 -q remoteuser@remotemachine" ctest -V
```
## Debug and Semihosting
These tests required a connection from the arm-none-eabi-gdb debugger
to the stm32 hardware. For this we use a recent version of
OpenOCD. Running tests with the stm32 hardware connected to a remote
machine via ssh is possible. This works only with a patched (fixed)
OpenOCD, see below.
## OpenOCD
We recommend OpenOCD instead of stlink.
Most linux distributions use old packages for openocd, so you should
build it from the git source. If your test runs fail with error
messages regarding SYS_FLEN not support (see openocd_stderr.log in the
test_run directories), your openocd is too old. Make sure to have the
right openocd first in the PATH if you have multiple openocd
installed!
It is strongly recommended to build OpenOCD from sources, see below.
## Building OpenOCD
OpenOCD needs to be built from the source.
If you want to use openocd remotely via SSH, you have to use currently the patched
source from (https://github.com/db4ple/openocd.git) instead of the official repository.
1.
The executable is placed in /usr/local/bin ! Make sure to have no
other openocd installed (check output of `which openocd` to be
/usr/local/bin)
```Bash
sudo apt install libusb-1.0-0-dev libtool pkg-config autoconf automake texinfo
git clone https://git.code.sf.net/p/openocd/code openocd-code
cd openocd-code
./bootstrap
./configure
sudo make install
which openocd
sudo cp contrib/60-openocd.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
{un plug/plug-in stm32 Discovery}
```
2. Plug in a stm32 development board and test:
```
$ openocd -f board/stm32f4discovery.cfg
Open On-Chip Debugger 0.10.0+dev-00796-ga4ac5615 (2019-04-12-21:58)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 2000 kHz
adapter_nsrst_delay: 100
none separate
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 2000 kHz
Info : STLINK V2J33S0 (API v2) VID:PID 0483:3748
Info : Target voltage: 2.871855
Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
```
## st-util (deprecated)
Most distributions don't have stutil included. Easiest way is to build it from
the github sources.
The source can be downloaded from:
(https://github.com/texane/stlink)
After compiling it can be installed anywhere, as long as it is in the PATH. The program is in
`build/Release/src/gdbserver/st-util`.
The newlib stdio functions (open, fread, fwrite, flush, fclose, etc.) send
some requests that this tool does not recognize and those messages will appear
in the output of st-util. They can be ignored.
1. Build from github
```Bash
git clone https://github.com/texane/stlink
cd stlink
make
sudo cp ./etc/udev/rules.d/49-stlinkv2.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
```
3. Add the st-util util to your $PATH, if not installed in the default location ( /usr/local/bin )
4. Plug in a stm32 development board and test:
```
$ st-util
st-util 1.4.0-47-gae717b9
2018-12-29T06:52:16 INFO usb.c: -- exit_dfu_mode
2018-12-29T06:52:16 INFO common.c: Loading device parameters....
2018-12-29T06:52:16 INFO common.c: Device connected is: F4 device, id 0x10016413
2018-12-29T06:52:16 INFO common.c: SRAM size: 0x30000 bytes (192 KiB), Flash: 0x100000 bytes (1024 KiB) in pages of 16384 bytes
2018-12-29T06:52:16 INFO gdb-server.c: Chip ID is 00000413, Core ID is 2ba01477.G
2018-12-29T06:52:16 INFO gdb-server.c: Listening at *:4242...
```
# vi:set ts=3 et sts=3:
@@ -0,0 +1,62 @@
% ofdm_demod_check.m
%
% Load results from reference and stm32 run and compare
addpath("../../lib/octave")
% Constants (would prefer parameters)
err_limit = 0.001;
% Reference
load("ofdm_demod_ref_log.txt");
% DUT
load("ofdm_demod_log.txt");
% Eliminate trailing rows of all zeros (unused)
sums_ref = sum(payload_syms_log_c, 2);
last_ref = find(sums_ref, 1, 'last');
sums_dut = sum(payload_syms_log_stm32, 2);
last_dut = find(sums_dut, 1, 'last');
last_all = max(last_ref, last_dut);
syms_ref = payload_syms_log_c(1:last_all,:);
syms_dut = payload_syms_log_stm32(1:last_all,:);
% error values
err = abs(syms_ref - syms_dut);
err_max = max(max(err));
printf("MAX_ERR %f\n", err_max);
err_vals = err - err_limit;
err_vals(err_vals<0) = 0;
errors = err_vals > 0;
num_errors = nnz(errors);
%% TODO, print errors info (count locations,...)
if (num_errors > 0)
printf("%d ERRORS\n", num_errors);
else
printf("PASSED\n");
end
% EVM
evm = sqrt(meansq(err, 2));
evm_avg = mean(evm);
printf("AVG_EVM %f\n", evm_avg);
evm_max = max(evm);
printf("MAX_EVM %f\n", evm_max);
% Standard deviation
sdv = std(err, 0, 2);
sdv_max = max(sdv);
printf("MAX_SDV %f\n", sdv_max);
% Plot
figure(1)
figure(1, "visible", true)
scatter(real(syms_ref), imag(syms_ref), "g", "+")
hold on
scatter(real(syms_dut), imag(syms_dut), "b", "o")
print(1, "syms_plot.png", "-dpng")
hold off
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
""" sum_profiles """
def sum_profiles(fin, frames):
data = {}
total_time = 0.0
active = False
for line in fin:
if (not active): active = line.startswith("Start Profile Data")
elif line.startswith("End Profile Data"): active = False
else:
words = line.strip().split()
if (len(words) == 3):
part = words[0]
time_str = words[1]
time = float(time_str)
total_time += time
if (not part in data): data[part] = 0.0
data[part] += time
# end else
# end for line
data_sorted = [(p, data[p]) for p in sorted(data, key=data.get, reverse=True)]
print("Total time = {:.1f} ms".format(total_time))
if (frames):
print("{:.1f} ms per frame".format(total_time / frames))
print("")
for part, time in data_sorted:
percent = int(100*(time / total_time))
print('{:2d}% - {:10.3f} - {}'.format(percent, time, part))
return(data)
# end sum_profiles()
########################################
if __name__ == "__main__":
import argparse
#### Options
argparser = argparse.ArgumentParser()
argparser.add_argument("-f", "--frames", action="store", type=int, default=0,
help="Number of frames")
argparser.add_argument("file", metavar="FILE", help="file to read")
args = argparser.parse_args()
fin = open(args.file, "r")
sum_profiles(fin, args.frames)
Binary file not shown.
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
#
# Compare the amount of RAM used in all stm32 programs to a
# threshold. The idea is trap changes to x86 code that will
# cause out of memory issues on the stm32
#
# This can be run from the command line or via a ctest, it doesn't
# require stm32 hardware.
#
# usage:
# cd ~/codec2/stm32/build_stm32
# ./check_ram_limit [threshold]
echo "Checking end of used RAM in all stm32 programs......."
thresh=0x20006000
[[ $# -gt 0 ]] && thresh=$1
map_files=`find . -name '*.map'`
for f in $map_files
do
ram_used=`cat $f | grep bss_end | sed 's/^.*\(0x[a-f0-9]*\).*/\1/'`
printf "%-40s 0x%x\n" $f $ram_used
[[ $ram_used -gt $thresh ]] && echo -e "\n ***** FAIL - LIMIT is $thresh !!! *****\n" && exit 1
done
echo "PASS"
exit 0
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
list_descendants ()
{
local children=$(ps -o pid= --ppid "$1")
for pid in $children
do
list_descendants "$pid"
done
echo $children
}
kill $(list_descendants $(pidof -x run_stm32_tst))
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
""" plot_ofdm_demod_syms
Plot QPSK constelations of reference demods.
Later read stm32 log......
"""
import numpy as np
import os
import sys
##############################################################################
# Read Octave text file
##############################################################################
def read_octave_text(fname):
data = {}
with open(fname, "r") as f:
for line in f:
if (line[0:8] == '# name: '):
var = line.split()[2]
print('found {}'.format(var))
line = next(f)
if (line.startswith('# type: matrix')):
line = next(f)
rows = int(line.split()[2])
line = next(f)
cols = int(line.split()[2])
print(' matrix({}, {})'.format(rows, cols))
data[var] = np.empty((rows, cols), np.float32)
# Read rows one at a time
for row in range(rows):
line = next(f)
data[var][row] = np.fromstring(line, np.float32, cols, ' ')
# end while True
# end with
return(data)
##############################################################################
# Main
##############################################################################
### Text not supported!!! ref_data = sio.loadmat('ofdm_demod_ref_log.mat')
ref_data = read_octave_text('ofdm_demod_ref_log.txt')
import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(ref_data)
+27
View File
@@ -0,0 +1,27 @@
#!/bin/bash
#
# run_all_codec2_tests
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
declare -i Fails=0
run_stm32_tst tst_codec2_enc 1300 "$@" || Fails+=1
run_stm32_tst tst_codec2_enc 700C "$@" || Fails+=1
run_stm32_tst tst_codec2_dec 1300 "$@" || Fails+=1
run_stm32_tst tst_codec2_dec 700C "$@" || Fails+=1
if (( $Fails == 0 )); then
echo -e "\nAll Codec2 Tests PASSED"
else
echo -e "\n$Fails Codec2 Tests FAILED!"
fi
exit $Fails
# vi:set ts=4 et sts=4:
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
#
# run_all_ldpc_tests
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
declare -i Fails=0
run_stm32_tst tst_ldpc_enc "$@" || Fails+=1
run_stm32_tst tst_ldpc_dec ideal "$@" || Fails+=1
run_stm32_tst tst_ldpc_dec noise "$@" || Fails+=1
if (( $Fails == 0 )); then
echo -e "\nAll LDPC Tests PASSED"
else
echo -e "\n$Fails LDPC Tests FAILED!"
fi
exit $Fails
# vi:set ts=4 et sts=4:
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
#
# run_all_ofdm_tests
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
declare -i Fails=0
run_stm32_tst tst_ofdm_mod plain "$@" || Fails+=1
run_stm32_tst tst_ofdm_mod ldpc "$@" || Fails+=1
run_stm32_tst tst_ofdm_demod quick "$@" || Fails+=1
run_stm32_tst tst_ofdm_demod ideal "$@" || Fails+=1
run_stm32_tst tst_ofdm_demod AWGN "$@" || Fails+=1
run_stm32_tst tst_ofdm_demod fade "$@" || Fails+=1
run_stm32_tst tst_ofdm_demod ldpc "$@" || Fails+=1
run_stm32_tst tst_ofdm_demod ldpc_AWGN "$@" || Fails+=1
run_stm32_tst tst_ofdm_demod ldpc_fade "$@" || Fails+=1
if (( $Fails == 0 )); then
echo -e "\nAll ODFM Tests PASSED"
else
echo -e "\n$Fails ODFM Tests FAILED!"
fi
exit $Fails
# vi:set ts=4 et sts=4:
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
#
# run_all_codec2_tests
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
declare -i Fails=0
run_all_codec2_tests "$@" || Fails+=1
run_all_ofdm_tests "$@" || Fails+=1
run_all_ldpc_tests "$@" || Fails+=1
if (( $Fails == 0 )); then
echo -e "\nAll STM32 Tests PASSED"
else
echo -e "\n$Fails STM32 Tests FAILED!"
fi
exit $Fails
# vi:set ts=4 et sts=4:
+91
View File
@@ -0,0 +1,91 @@
#!/bin/bash
#######################################
# Parse command line options
# Options (starting with "--") are stored in $ARGS.
# Non-options are taken as the test name (last one sticks).
declare -A ARGS
for arg in "$@"; do
if [[ ${arg} == --* ]] ; then ARGS[${arg}]=true
else ELF=${arg}
fi
done
# Add the parameters for connecting via ssh to
# your machine with an stm32 connected to
# UT_SSH_PARAMS
# e.g.
# UT_SSH_PARAMS="-p 22 user@host_with_stm32"
if [ -z "$UT_SSH_PARAMS" ]; then
UT_SSH=""
UT_SLEEP=${UT_SLEEP:=1}
UI_SH_FIO="disable"
else
UT_SSH="ssh -f -L 3333:localhost:3333 $UT_SSH_PARAMS"
UT_SLEEP=${UT_SLEEP:=4}
UT_SH_FIO="enable"
fi
rm -f gdb_cmds
if [ ! ${ARGS[--st-util]+_} ] ; then
# OpenOCD
if [ -n "$UT_SSH" ]; then
cat <<-EEOOFF >> gdb_cmds
shell ${UT_SSH} killall -q openocd\; sleep 1\; openocd -d0 -f board/stm32f4discovery.cfg 2> >(tee stderr.log >&2) | tee stdout.log &
EEOOFF
else
cat <<-EEOOFF >> gdb_cmds
shell killall -q openocd
shell openocd -d0 -f board/stm32f4discovery.cfg 2> >(tee stderr.log >&2) | tee stdout.log &
EEOOFF
fi
cat <<-EEOOFF >> gdb_cmds
shell sleep ${UT_SLEEP}
target remote :3333
monitor arm semihosting enable
monitor arm semihosting_fileio $UT_SH_FIO
EEOOFF
SHUTDOWN="monitor shutdown"
else
# ST-Util
echo "---------------------- STARTING gdb/st-util ------------------------------"
cat <<-EEOOFF >> gdb_cmds
shell st-util --verbose=0 --semihosting 2>stutil_stderr.log >stutil_stdout.log &
shell sleep ${UT_SLEEP}
target remote :4242
EEOOFF
SHUTDOWN=""
fi
if [ ! ${ARGS[--noload]+_} ] ; then
cat <<-EEOOFF >> gdb_cmds
load
EEOOFF
fi
cat <<-EEOOFF >> gdb_cmds
monitor reset halt
monitor adapter speed 4000
break EndofMain
break abort
EEOOFF
if [ -z ${ARGS[--debug]+_} ] ; then
cat <<-EEOOFF >> gdb_cmds
shell printf "\n----------------------------STARTING PROGRAM-------------------------\n\n"
continue
set confirm off
$SHUTDOWN
quit
EEOOFF
arm-none-eabi-gdb -batch -x gdb_cmds ${ELF}
else
arm-none-eabi-gdb -x gdb_cmds ${ELF}
fi
+53
View File
@@ -0,0 +1,53 @@
#!/bin/bash
#
# run_stm32_tst <test> <test_sub_type> [--noload] [--st-util]
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
declare -i Fails=0
#####################################################################
LOAD=${ARGS[--noload]:+--noload}
STUTIL=${ARGS[--st-util]:+--st-util}
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
echo -e "test full name: ${FULL_TEST_NAME}"
setup_common "${RUN_DIR}"
if [ ! -f "${SCRIPTS}/${TEST}_setup" ]; then
echo -e "\nERROR: scripts/${TEST}_setup not found!"
echo "Test name correct?"
echo "valid test names:"
cd scripts; ls tst*setup | sed 's/_setup//'
exit 1
fi
# Call setup - run - check scripts
${TEST}_setup ${TEST} ${TEST_OPT} --clean || { echo "ERROR in ${TEST}_setup! Exiting..."; exit 1; }
cd "${RUN_DIR}"
run_stm32_prog ${UNITTEST_BIN}/${TEST}.elf ${LOAD} ${OPENOCD} | tee gdb.log
[ ! ${PIPESTATUS[0]} -eq 0 ] && { echo "ERROR in run_stm32_prog! Exiting..."; exit 1; }
# stop now if we see an assert() fire, no point running check phase
grep -q assertion gdb.log && exit 1
${TEST}_check ${TEST} ${TEST_OPT} 2>&1 | tee check.log
if [ ! "${PIPESTATUS[0]}" -eq 0 ]; then
let Fails=($Fails + 1)
fi
sleep 5 # Delay for st-util to close
if (( $Fails == 0 )); then
echo -e "\nTest ${FULL_TEST_NAME} PASSED"
else
echo -e "\nTest ${FULL_TEST_NAME} FAILED!"
cat ${RUN_DIR}/check.log
echo -e "\n -> look at log files in: ${RUN_DIR}:"
ls ${RUN_DIR}
fi
exit $Fails
# vi:set ts=4 et sts=4:
@@ -0,0 +1,79 @@
# This file must be "sourced" from a parent shell!
#
# run_tests_common.sh
#
# This is a collection of common variable settings for stm32 unit tests.
#
# The variable $SCRIPTS must be set when this is called.
if [ -z ${SCRIPTS+x} ]; then
echo "Error, run_tests_common.sh requires that \$SCRIPTS be set!"
exit 1
fi
#######################################
# Set default directories based on the parent of the SCRIPTS variable.
set -a
#UNITTEST_BASE - Location of STM32 Unittests and files
UNITTEST_BASE="$( cd "$( dirname "${SCRIPTS}" )" >/dev/null && pwd )"
# STM32_BASE - Base directory of Stm32 files
STM32_BASE="$( cd "$( dirname "${UNITTEST_BASE}" )" >/dev/null && pwd )"
# STM32_BUILD - Build directory of Stm32 files
STM32_BUILD="${STM32_BASE}/build_stm32"
# UNITTEST_BIN - Location of STM32 unittest binaries
UNITTEST_BIN="${STM32_BUILD}/unittest/src"
# CODEC2_BASE - Base directory of Codec2
CODEC2_BASE="$( cd "$( dirname "${STM32_BASE}" )" >/dev/null && pwd )"
# CODEC2_BIN - Location of x86 utiliy programs for Codec2
CODEC2_BIN="${CODEC2_BASE}/build_linux/src"
# CODEC2_UTST - Location of x86 utiliy programs for Codec2 unittest
CODEC2_UTST="${CODEC2_BASE}/build_linux/unittest"
set +a
#######################################
# Add directories to PATH
export PATH=${PATH}:${SCRIPTS}:${CODEC2_BIN}:${CODEC2_UTST}
#######################################
# Parse command line options
# Options (starting with "--") are stored in $ARGS.
# Non-options are taken as the test name, then as a test option (optional)
declare -A ARGS
unset TEST
unset TEST_OPT
for arg in "$@"; do
if [[ ${arg} == --* ]] ; then ARGS[${arg}]=true
else
if [ -z ${TEST+x} ]; then TEST=${arg}
else TEST_OPT=${arg}
fi
fi
done
# Prepend the common test name to the option if given
if [ -n "$TEST_OPT" ] ; then FULL_TEST_NAME="${TEST}_${TEST_OPT}"
else FULL_TEST_NAME="${TEST}"
fi
#######################################
# A function for setup
setup_common () {
if [ ${ARGS[--clean]+_} ] ; then
if [ -d "${1}" ] ; then rm -rf "${1}"; fi
fi
# Make run directory if needed
if [ ! -d "${1}" ] ; then mkdir -p "${1}"; fi
}
+19
View File
@@ -0,0 +1,19 @@
# This file must be "sourced" from a parent shell!
#
# setup.sh
#
# This is a collection of common variable settings for manually running
# stm32 unit tests.
#
# This assumes it is called from the "stm32/unittests" directory!!!
SCRIPTS="${PWD}/scripts"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
#######################################
# Add directories to PATH(s)
export PATH=${SCRIPTS}:${PATH}
export PATH=${CODEC2_BIN}:${CODEC2_UTST}:${CODEC2_UTST_BIN}:${CODEC2_SCRIPT}:${PATH}
export LD_LIBRARY_PATH=${CODEC2_BIN}:${LD_LIBRARY_PATH}
@@ -0,0 +1,2 @@
semihosting test - stderr
Error 2 opening fin
@@ -0,0 +1 @@
semihosting test - stdout
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
""" sum_profiles """
def sum_profiles(fin, frames):
data = {}
total_time = 0.0
for line in fin:
words = line.strip().split()
if (len(words) == 3):
part = words[0]
time_str = words[1]
time = float(time_str)
total_time += time
if (not part in data): data[part] = 0.0
data[part] += time
data_sorted = [(p, data[p]) for p in sorted(data, key=data.get, reverse=True)]
print("Total time = {:.1f} ms".format(total_time))
if (frames):
print("{:.1f} per frame".format(total_time / args.frames))
print("")
for part, time in data_sorted:
percent = int(100*(time / total_time))
print('{:2d}% - {:10.3f} - {}'.format(percent, time, part))
return(data)
# end sum_profiles()
########################################
if __name__ == "__main__":
import argparse
#### Options
argparser = argparse.ArgumentParser()
argparser.add_argument("-f", "--frames", action="store", type=int, default=0,
help="Number of frames")
argparser.add_argument("file", metavar="FILE", help="file to read")
args = argparser.parse_args()
fin = open(args.file, "r")
sum_profiles(fin, args.frames)
+214
View File
@@ -0,0 +1,214 @@
#!/bin/bash
#
# tst_api_demod_check
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
# way of performing a rough comparison of two output speech files that are not exactly the same
function compare_energy() {
energy_ref=$(python3 -c "import numpy as np; x=np.fromfile(\"ref_demod.raw\",dtype=\"int16\").astype(float); print(10*np.log10(np.dot(x,x)))")
energy_target=$(python3 -c "import numpy as np; x=np.fromfile(\"stm_out.raw\",dtype=\"int16\").astype(float); print(10*np.log10(np.dot(x,x)))")
printf "ref energy: %f target energy: %f\n" $energy_ref $energy_target
python3 -c "import sys; sys.exit(1) if abs($energy_ref-$energy_target) < 1 else sys.exit(0)"
if [[ $? -eq 1 ]]; then echo "energy compare OK";
else echo "energy compare BAD";
let Fails=($Fails + 1)
fi
}
#####################################################################
## Test CHECK actions:
declare -i Fails=0
case "${TEST_OPT}" in
700D_plain_test)
echo "Check reference decode"
p1=$(grep '^BER\.*: 0.000' ref_gen.log | wc -l)
p2=$(grep '^Coded BER: 0.000' ref_gen.log | wc -l)
if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
#
echo "Check target decode"
p1=$(grep '^BER\.*: 0.000' stderr.log | wc -l)
p2=$(grep '^Coded BER: 0.000' stderr.log | wc -l)
if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
;;
700D_AWGN_test)
echo "Check reference decode"
uber_ref=$(cat ref_gen.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p")
cber_ref=$(cat ref_gen.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p")
printf "REF uncoded BER: %f coded BER: %f\n" $uber_ref $cber_ref
# As per notes in tst_api_demod_setup, coded BER is unreliable
# for such a short test, so we'll just sanity check the
# reference uncoded BER here. Bash can't compare floats
# .... so use return code of some python script
python3 -c "import sys; sys.exit(1) if $uber_ref < 0.1 else sys.exit(0)"
if [[ $? -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
echo "Check target decode"
uber_target=$(cat stderr.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p")
cber_target=$(cat stderr.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p")
printf "TARGET uncoded BER: %f coded BER: %f\n" $uber_target $cber_target
python3 -c "import sys; sys.exit(1) if $uber_target < 0.1 and abs($cber_ref-$cber_target) < 0.01 else sys.exit(0)"
if [[ $? -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
;;
700D_AWGN_codec)
# 1/ The two output files sound OK, and when plotted look very
# similar, but they don't match on a sample-sample basis.
# 2/ Suspect some small state difference, or perhaps random
# number generator diverging, sampling codec2_rand() at the
# end of the x86 and stm32 test programs might show up any
# differences.
# 3/ At this stage - we can't make sample by sample automatic
# tests work. However there is value in running the test
# to ensure no asserts are hit and the code doesn't crash
# (e.g. due to an out of memory issues). A simple energy
# comparison is used on the output speech files, which
# will trap any large errors.
# 4/ We can also manually evaluate the output decoded speech by
# listening to the output speech files.
compare_energy;
# make sure execution time stays within bounds
execution_time=mktmp
cat stdout.log | sed -n "s/.*freedv_rx \([0-9..]*\) msecs/\1/p" > $execution_time
python3 -c "import sys; import numpy as np; x=np.loadtxt(\"$execution_time\"); print(\"execution time max:: %5.2f mean: %5.2f ms\" % (np.max(x), np.mean(x))); sys.exit(1) if np.max(x) < 80.0 else sys.exit(0)"
if [[ $? -eq 1 ]]; then echo "execution time OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
;;
700E_plain_test)
echo "Check reference decode"
p1=$(grep '^BER\.*: 0.000' ref_gen.log | wc -l)
p2=$(grep '^Coded BER: 0.000' ref_gen.log | wc -l)
if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
#
echo "Check target decode"
p1=$(grep '^BER\.*: 0.000' stderr.log | wc -l)
p2=$(grep '^Coded BER: 0.000' stderr.log | wc -l)
if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
;;
700E_AWGN_test)
echo "Check reference decode"
uber_ref=$(cat ref_gen.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p")
cber_ref=$(cat ref_gen.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p")
printf "REF uncoded BER: %f coded BER: %f\n" $uber_ref $cber_ref
# As per notes in tst_api_demod_setup, coded BER is unreliable
# for such a short test, so we'll just sanity check the
# reference uncoded BER here. Bash can't compare floats
# .... so use return code of some python script
python3 -c "import sys; sys.exit(1) if $uber_ref < 0.1 else sys.exit(0)"
if [[ $? -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
echo "Check target decode"
uber_target=$(cat stderr.log | sed -n "s/^BER.*: \([0-9..]*\).*Tbits.*/\1/p")
cber_target=$(cat stderr.log | sed -n "s/^Coded BER.*: \([0-9..]*\).*Tbits.*/\1/p")
printf "TARGET uncoded BER: %f coded BER: %f\n" $uber_target $cber_target
python3 -c "import sys; sys.exit(1) if $uber_target < 0.1 and abs($cber_ref-$cber_target) < 0.01 else sys.exit(0)"
if [[ $? -eq 1 ]]; then echo "OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
;;
700E_AWGN_codec)
# 1/ The two output files sound OK, and when plotted look very
# similar, but they don't match on a sample-sample basis.
# 2/ Suspect some small state difference, or perhaps random
# number generator diverging, sampling codec2_rand() at the
# end of the x86 and stm32 test programs might show up any
# differences.
# 3/ At this stage - we can't make sample by sample automatic
# tests work. However there is value in running the test
# to ensure no asserts are hit and the code doesn't crash
# (e.g. due to an out of memory issues). A simple energy
# comparison is used on the output speech files, which
# will trap any large errors.
# 4/ We can also manually evaluate the output decoded speech by
# listening to the output speech files.
compare_energy;
# make sure execution time stays within bounds
execution_time=mktmp
cat stdout.log | sed -n "s/.*freedv_rx \([0-9..]*\) msecs/\1/p" > $execution_time
python3 -c "import sys; import numpy as np; x=np.loadtxt(\"$execution_time\"); print(\"execution time max:: %5.2f mean: %5.2f ms\" % (np.max(x), np.mean(x))); sys.exit(1) if np.max(x) < 80.0 else sys.exit(0)"
if [[ $? -eq 1 ]]; then echo "execution time OK";
else echo "BAD";
let Fails=($Fails + 1)
fi
;;
1600_plain_codec)
compare_energy;
;;
*)
printf "ERROR: invalid test option. Valid options are:\n 700D_plain_test\n 700D_AWGN_test\n 700D_plain_codec\n 1600_plain_codec\n"
exit 1
esac
if (( $Fails == 0 )); then
echo -e "\nTest PASSED"
else
echo -e "\nTest FAILED!"
fi
exit $Fails
+151
View File
@@ -0,0 +1,151 @@
#!/bin/bash
#
# tst_api_demod_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
case "${TEST_OPT}" in
700D_plain_test )
# Config is <mode>, <teswtframes>
echo "71000010" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=100 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
freedv_tx 700D spch_in.raw stm_in.raw --testframes --txbpf 0 \
>> setup.log 2>&1
#
# Reference
freedv_rx 700D stm_in.raw ref_demod.raw -v --testframes \
> ref_gen.log 2>&1
;;
700D_AWGN_test )
# Config is <mode>, <teswtframes>
echo "71000010" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=96 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
freedv_tx 700D spch_in.raw mod_bits.raw --testframes --txbpf 0 \
>> setup.log 2>&1
ch mod_bits.raw stm_in.raw --No -20 -f -5 2>&1 | tee setup.log
# Reference: - When the OFDM modem initially syncs, it often
# has residual freq offset that causes abnormally
# high LDPC decoder bit errors forthe first few
# seconds. This leads to a high coded BER being
# reported for short duration tests. This
# settles down after a few seconds, and we get
# the expected coded BER when averaging over
# longer periods (e.g. 60s). However this
# particular test is necessarily short due to the
# slow speed of the semihosting system. It is
# therefore sufficient to check that the
# performance is similar to the x86 C version,
# rather than expecting a low coded BER for a
# short run.
freedv_rx 700D stm_in.raw ref_demod.raw -v --testframes 2>&1 --discard | tee ref_gen.log
;;
700D_AWGN_codec )
# Config is <mode>, <teswtframes>
echo "70000020" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=48 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
freedv_tx 700D spch_in.raw mod_bits.raw --txbpf 0 \
>> setup.log 2>&1
#
# Reference - give it a hard time with some noise to exercise the LDPC codec and get us to max CPU
ch mod_bits.raw stm_in.raw --No -20 -f -5 2>&1 | tee setup.log
freedv_rx 700D stm_in.raw ref_demod.raw -v \
> ref_gen.log 2>&1
;;
700E_plain_test )
# Config is <mode>, <teswtframes>
echo "81000010" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=100 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
freedv_tx 700E spch_in.raw stm_in.raw --testframes --txbpf 1 \
>> setup.log 2>&1
#
# Reference
freedv_rx 700E stm_in.raw ref_demod.raw -v --testframes \
> ref_gen.log 2>&1
;;
700E_AWGN_test )
# Config is <mode>, <teswtframes>
echo "81000010" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=96 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
freedv_tx 700E spch_in.raw mod_bits.raw --testframes --txbpf 1 \
>> setup.log 2>&1
ch mod_bits.raw stm_in.raw --No -22 -f -5 2>&1 | tee setup.log
freedv_rx 700E stm_in.raw ref_demod.raw -v --testframes 2>&1 --discard | tee ref_gen.log
;;
700E_AWGN_codec )
# Config is <mode>, <teswtframes>
echo "80000020" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=48 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
freedv_tx 700E spch_in.raw mod_bits.raw --txbpf 1 \
>> setup.log 2>&1
#
# Reference - give it a hard time with some noise to exercise the LDPC codec and get us to max CPU
ch mod_bits.raw stm_in.raw --No -20 -f -5 2>&1 | tee setup.log
freedv_rx 700E stm_in.raw ref_demod.raw -v \
> ref_gen.log 2>&1
;;
1600_plain_codec )
# Config is <mode>, <teswtframes>
echo "00000010" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=320 count=100 if=../../../../raw/hts1.raw of=spch_in.raw > setup.log 2>&1
freedv_tx 1600 spch_in.raw stm_in.raw >> setup.log 2>&1
#
# Reference
freedv_rx 1600 stm_in.raw ref_demod.raw -v \
> ref_gen.log 2>&1
;;
*)
printf "ERROR: invalid test option. Valid options are:\n 700[DE]_plain_test\n 700[DE]_AWGN_test\n 700[DE]_AWGN_codec\n 1600_plain_codec\n"
exit 1
;;
esac
+115
View File
@@ -0,0 +1,115 @@
#!/bin/bash
#
# tst_api_mod_check
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test CHECK actions:
declare -i Fails=0
case "${TEST_OPT}" in
700D_TEST)
#
echo -e "\nReference check"
if freedv_rx 700D ref_mod.raw ref_rx.raw --testframes; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
echo -e "\nTarget check"
if freedv_rx 700D stm_out.raw stm_rx.raw --testframes; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
echo -e "\nCompare output binary data"
if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
;;
700D_CODEC)
#
echo -e "\nCompare output binary data"
if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
;;
700E_TEST)
#
echo -e "\nReference check"
if freedv_rx 700E ref_mod.raw ref_rx.raw --testframes; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
echo -e "\nTarget check"
if freedv_rx 700E stm_out.raw stm_rx.raw --testframes; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
echo -e "\nCompare output binary data"
if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
;;
700E_CODEC)
#
echo -e "\nCompare output binary data"
if compare_ints -s -b2 -t4 ref_mod.raw stm_out.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
;;
esac
if (( $Fails == 0 )); then
echo -e "\nTest PASSED"
else
echo -e "\nTest FAILED!"
fi
exit $Fails
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
#
# tst_api_mod_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
case "${TEST_OPT}" in
700D_TEST )
# Config is <mode>, <teswtframes>, <clip>, <bpf>
echo "71000000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \
> setup.log 2>&1
#
# Reference
freedv_tx 700D stm_in.raw ref_mod.raw --testframes --txbpf 0 \
> ref_gen.log 2>&1
;;
700D_CODEC )
# Config is <mode>, <teswtframes>, <clip>, <bpf>
echo "70000000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \
> setup.log 2>&1
#
# Reference
freedv_tx 700D stm_in.raw ref_mod.raw --txbpf 0 \
> ref_gen.log 2>&1
;;
700E_TEST )
# Config is <mode>, <teswtframes>, <clip>, <bpf>
echo "81110000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \
> setup.log 2>&1
#
# Reference
freedv_tx 700E stm_in.raw ref_mod.raw --testframes --txbpf 1 --clip 1 \
> ref_gen.log 2>&1
;;
700E_CODEC )
# Config is <mode>, <teswtframes>, <cip>, <bpf>
echo "80110000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=1280 count=48 if=../../../../raw/hts1.raw of=stm_in.raw \
> setup.log 2>&1
#
# Reference
freedv_tx 700E stm_in.raw ref_mod.raw --txbpf 1 --clip 1 \
> ref_gen.log 2>&1
;;
*)
printf "ERROR: invalid test option. Valid options are:\n 700D_TEST\n 700D_CODEC\n 700E_TEST\n 700E_CODEC\n"
exit 1
;;
esac
exit 0
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
#
# tst_codec2_dec_check
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test CHECK actions:
declare -i Fails=0
#case "${TEST_OPT}" in
# 1300)
# 700C)
# esac
echo -e "\nMust manually listen to this!"
aplay -f S16_LE stm_out.raw
if (( $Fails == 0 )); then
echo -e "\nTest PASSED"
else
echo -e "\nTest FAILED!"
fi
exit $Fails
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
#
# tst_codec2_dec_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
case "${TEST_OPT}" in
1300 )
# Config is <mode>, <teswtframes>
echo "41000000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
c2enc 1300 spch_in.raw stm_in.raw >> setup.log 2>&1
#
# Reference
c2dec 1300 stm_in.raw ref_dec.raw > ref_gen.log 2>&1
;;
700C )
# Config is <mode>, <teswtframes>
echo "81000000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw \
> setup.log 2>&1
c2enc 700C spch_in.raw stm_in.raw >> setup.log 2>&1
#
# Reference
c2dec 700C stm_in.raw ref_dec.raw > ref_gen.log 2>&1
;;
esac
+59
View File
@@ -0,0 +1,59 @@
#!/bin/bash
#
# tst_codec2_enc_check
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test CHECK actions:
declare -i Fails=0
case "${TEST_OPT}" in
1300)
echo -e "\nCompare output binary data"
compare_ints -b1 -c ref_enc.raw stm_out.raw
error_count=$?
if [[ $error_count -le 2 ]]; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
;;
700C)
echo -e "\nCompare output binary data"
if compare_ints -b1 ref_enc.raw stm_out.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
;;
esac
if (( $Fails == 0 )); then
echo -e "\nTest PASSED"
else
echo -e "\nTest FAILED!"
fi
exit $Fails
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
#
# tst_codec2_enc_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
case "${TEST_OPT}" in
1300 )
# Config is <mode>, <teswtframes>
echo "40000000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=2560 count=30 if=../../../../raw/hts1.raw of=stm_in.raw \
> setup.log 2>&1
#
# Reference
c2enc 1300 stm_in.raw ref_enc.raw \
> ref_gen.log 2>&1
;;
700C )
# Config is <mode>, <teswtframes>
echo "80000000" > stm_cfg.txt
#
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=2560 count=30 if=../../../../raw/hts1.raw of=stm_in.raw \
> setup.log 2>&1
#
# Reference
c2enc 700C stm_in.raw ref_enc.raw \
> ref_gen.log 2>&1
;;
esac
+71
View File
@@ -0,0 +1,71 @@
#!/bin/bash
#
# tst_ldpc_enc_check
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test CHECK actions:
declare -i Fails=0
case "${TEST_OPT}" in
ideal)
BER_LIMIT_RAW=0.0
BER_LIMIT_CODED=0.0
;;
noise)
BER_LIMIT_RAW=0.15
BER_LIMIT_CODED=0.015
;;
esac
echo -e "\nCompare output binary data"
if compare_ints -b1 ref_out.raw stm_out.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
echo -e "\nReference BER values"
n=$(grep 'Raw.*BER:' ref_gen.log | awk '{print $7}')
p1=$(echo $n '<=' ${BER_LIMIT_RAW} | bc)
n=$(grep 'Coded.*BER:' ref_gen.log | awk '{print $7}')
p2=$(echo $n '<=' ${BER_LIMIT_CODED} | bc)
if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "Pass";
else echo "Fail"; let Fails=($Fails + 1); fi
#
echo -e "\nTarget BER values"
n=$(grep 'Raw.*BER:' stderr.log | cut -d ' ' -f 7)
p1=$(echo $n '<=' ${BER_LIMIT_RAW} | bc)
n=$(grep 'Coded.*BER:' stderr.log | cut -d ' ' -f 7)
p2=$(echo $n '<=' ${BER_LIMIT_CODED} | bc)
if [[ $p1 -eq 1 && $p2 -eq 1 ]]; then echo "Pass";
else echo "Fail"; let Fails=($Fails + 1); fi
if (( $Fails == 0 )); then
echo -e "\nTest PASSED"
else
echo -e "\nTest FAILED!"
fi
exit $Fails
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
#
# tst_ldpc_dec_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
case "${TEST_OPT}" in
ideal )
# # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile>
# echo "00000000" > stm_cfg.txt
ldpc_enc /dev/zero stm_in.raw --sd --code HRA_112_112 --testframes 6 \
> setup.log 2>&1
ldpc_dec stm_in.raw ref_out.raw --sd --code HRA_112_112 --testframes \
> ref_gen.log 2>&1
;;
noise )
# # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile>
# echo "00000000" > stm_cfg.txt
ldpc_enc /dev/zero enc_out.raw --sd --code HRA_112_112 --testframes 24 \
> setup.log 2>&1
ldpc_noise enc_out.raw stm_in.raw 1 \
>> setup.log 2>&1
ldpc_dec stm_in.raw ref_out.raw --sd --code HRA_112_112 --testframes \
> ref_gen.log 2>&1
;;
esac
exit 0
+68
View File
@@ -0,0 +1,68 @@
#!/bin/bash
#
# tst_ldpc_enc_check
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test CHECK actions:
declare -i Fails=0
#case "${TEST_OPT}" in
#
# plain)
# ;;
# esac
##### TODO: ldpc_dec should be able to check this outputs,
##### it currently reports Tbits = 0!
#echo -e "\nReference check"
#if ofdm_demod ref_mod_out.raw ref_ofdm_demod.raw --testframes ${LDPC}; then
# echo "Passed"
#else
# echo "Failed"
# let Fails=($Fails + 1)
#fi
##
#echo -e "\nTarget check"
#if ofdm_demod mod.raw stm_demod.raw --testframes ${LDPC}; then
# echo "Passed"
#else
# echo "Failed"
# let Fails=($Fails + 1)
#fi
##
echo -e "\nCompare output binary data"
if compare_ints -b1 ref_out.raw stm_out.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
if (( $Fails == 0 )); then
echo -e "\nTest PASSED"
else
echo -e "\nTest FAILED!"
fi
exit $Fails
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
#
# tst_ldpc_enc_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
#case "${TEST_OPT}" in
#
# plain )
# # Config is <unused>, <unused>, <ldpc_en>, <unused> <profile>
# echo "00000000" > stm_cfg.txt
ofdm_get_test_bits --out stm_in.raw --frames 6 --verbose \
> setup.log 2>&1
ldpc_enc stm_in.raw ref_out.raw --code HRA_112_112 \
> ref_gen.log 2>&1
# ;;
#
# esac
exit 0
+503
View File
@@ -0,0 +1,503 @@
#!/usr/bin/env python3
""" tst_ofdm_demod_check
Testing for tst_ofdm_demod_* tests
Usage tst_ofdm_demod_check <dummy_test_name> quick|ideal|AWGN|fade|profile|ldpc|ldpc_AWGN|ldpc_fade
Checks are different for each option, but similar
- Convert stm32 output to octave text format
(stm32 does not have memory for this)
- ...
"""
import numpy as np
import math
import argparse
import struct
import os
import sys
if ("UNITTEST_BASE" in os.environ):
sys.path.append(os.environ["UNITTEST_BASE"] + "/lib/python")
else:
sys.path.append("../../lib/python") # assume in test run dir
import sum_profiles
Nbitsperframe = 238
##############################################################################
# Read Octave text file
##############################################################################
def read_octave_text(f):
if (args.verbose): print('read_octave_text()')
data = {}
for line in f:
if (line[0:8] == "# name: "):
var = line.split()[2]
if (args.verbose): print(' var "{}"'.format(var))
line = next(f)
if (line.startswith("# type: matrix")):
line = next(f)
rows = int(line.split()[2])
line = next(f)
cols = int(line.split()[2])
if (cols > 0):
data[var] = np.empty((rows, cols), np.float32)
# Read rows one at a time
for row in range(rows):
try:
line = next(f)
data[var][row] = np.fromstring(line, np.float32, cols, " ")
except:
print("Error reading row {} of var {}".format(row, var))
raise
elif (line.startswith("# type: complex matrix")):
line = next(f)
rows = int(line.split()[2])
line = next(f)
cols = int(line.split()[2])
if (cols > 0):
data[var] = np.empty((rows, cols), np.complex64)
# Read rows one at a time
for row in range(rows):
try:
line = next(f)
# " (r,i) (r,i) ..."
col = 0
for tpl in line.split():
real, imag = tpl.strip("(,)").split(",")
data[var][row][col] = float(real) + (1j * float(imag))
col += 1
except:
print("Error reading row {} of var {}".format(row, var))
raise
# end for line in f
return(data)
##############################################################################
# Read stm32 diag data, syms, amps for each frame
##############################################################################
def read_tgt_syms(f):
# TODO: don't use hardcoded values...
syms = np.zeros((100, 112), np.complex64)
amps = np.zeros((100, 112), np.float32)
row = 0
while True:
# syms
buf = f.read(112 * 8)
if (len(buf) < (112 * 8)): break
row_lst = struct.unpack("<224f", buf)
ary = np.array(row_lst, np.float32)
ary.dtype = np.complex64
syms[row] = ary
# amps
buf = f.read(112 * 4)
if (len(buf) < (112 * 4)): break
row_lst = struct.unpack("<112f", buf)
ary = np.array(row_lst, np.float32)
amps[row] = ary
#
row += 1
if (row >= 100): break
# end While True
return(syms, amps)
# end read_stm_syms()
##############################################################################
# Write out in octave text format as 2 matricies
##############################################################################
def write_syms_as_octave(syms, amps):
with open("ofdm_demod_log.txt", "w") as f:
# syms
rows = syms.shape[0]
cols = syms.shape[1]
f.write("# name: payload_syms_log_stm32\n")
f.write("# type: complex matrix\n")
f.write("# rows: {}\n".format(rows))
f.write("# columns: {}\n".format(cols))
for row in range(rows):
for col in range(cols):
f.write(" ({},{})".format(
syms[row][col].real,
syms[row][col].imag
))
f.write("\n")
# amps
rows = amps.shape[0]
cols = amps.shape[1]
f.write("\n")
f.write("# name: payload_amps_log_stm32\n")
f.write("# type: matrix\n")
f.write("# rows: {}\n".format(rows))
f.write("# columns: {}\n".format(cols))
for row in range(rows):
for col in range(cols):
f.write(" {}".format(
amps[row][col]
))
f.write("\n")
# end write_syms_as_octave()
##############################################################################
# Main
##############################################################################
#### Options
argparser = argparse.ArgumentParser()
argparser.add_argument("-v", "--verbose", action="store_true")
argparser.add_argument("test", action="store")
argparser.add_argument("test_opt", action="store",
choices=["quick", "ideal", "AWGN", "fade", "profile",
"ldpc", "ldpc_AWGN", "ldpc_fade" ])
args = argparser.parse_args()
# Use ENV value of UNITTEST_BASE from upper level shell script (default to .)
if ('UNITTEST_BASE' in os.environ):
run_dir = os.environ['UNITTEST_BASE'] + "/test_run/"
run_dir += args.test + "_" + args.test_opt
print(run_dir)
os.chdir(run_dir)
#### Settings
# Defaults, (for tests without channel degradation, results should be close to ideal)
max_ber = 0.001 # Max BER value in Target
max_ber2 = 0.001 # Max Coded BER value in Target
compare_ber = 1 # Compare Target to Reference?
# Used if compare_ber:
tolerance_ber = 0.001 # Difference from reference for BER
tolerance_ber2 = 0.001 # Difference from reference for Coded BER
tolerance_tbits = 0
tolerance_terrs = 1
#
compare_output = 1 # Compare Target to Reference?
# Used if compare_output:
tolerance_output_differences = 0
tolerance_syms = 0.01
tolerance_amps = 0.01
#
# Per test settings
if (args.test_opt == "quick"):
pass
elif (args.test_opt == "ideal"):
pass
elif (args.test_opt == "AWGN"): # Still close enough to compare BERs loosely
max_ber = 0.1
max_ber2 = 0.1
tolerance_ber = 0.01
tolerance_ber2 = 0.005
tolerance_tbits = 1000
tolerance_terrs = 50
tolerance_output_differences = 2
compare_output = 0
elif (args.test_opt == "fade"):
max_ber = 0.1
max_ber2 = 0.1
tolerance_ber = 0.01
tolerance_ber2 = 0.005
tolerance_tbits = 1000
tolerance_terrs = 200
tolerance_output_differences = 5
compare_output = 0
pass
elif (args.test_opt == "profile"):
tolerance_output_differences = 1
pass
elif (args.test_opt == "ldpc"):
pass
elif (args.test_opt == "ldpc_AWGN"):
max_ber = 0.1
max_ber2 = 0.01
compare_ber = 0
compare_output = 0
elif (args.test_opt == "ldpc_fade"):
max_ber = 0.1
max_ber2 = 0.01
compare_ber = 0
compare_output = 0
pass
else:
print("Error: Test {} not recognized".format(args.test_opt))
sys.exit(1)
#### Check that we are in the test directory:
#### TODO:::
#### Read test configuration - a file of '0' or '1' characters
with open("stm_cfg.txt", "r") as f:
config = f.read(8)
config_verbose = (config[0] == '1')
config_testframes = (config[1] == '1')
config_ldpc_en = (config[2] == '1')
config_log_payload_syms = (config[3] == '1')
config_profile = (config[4] == '1')
####
fails = 0
if (config_testframes):
#### BER checks - log output looks like this, for non-ldpc:
# BER......: 0.1951 Tbits: 14994 Terrs: 2926
# BER2.....: 0.2001 Tbits: 10234 Terrs: 2048
#
# Or this, for ldpc:
# BER......: 0.0000 Tbits: 15008 Terrs: 0
# Coded BER: 0.0000 Tbits: 7504 Terrs: 0
#
# HACK: store "Coded BER" info as BER2.
print("\nBER checks")
# Read ref log
print("Reference")
with open("ref_gen_log.txt", "r") as f:
for line in f:
if (line[0:4] == "BER2"):
print(line, end="")
_, ref_ber2, _, ref_tbits2, _, ref_terrs2 = line.split()
elif (line[0:3] == "BER"):
print(line, end="")
_, ref_ber, _, ref_tbits, _, ref_terrs, _, ref_tpackets, _, ref_snr3k = line.split()
elif (line[0:9] == "Coded BER"):
print(line, end="")
_, _, ref_ber2, _, ref_tbits2, _, ref_terrs2 = line.split()
# Strings to integers
ref_ber = float(ref_ber)
ref_tbits = int(ref_tbits)
ref_terrs = int(ref_terrs)
ref_ber2 = float(ref_ber2)
ref_tbits2 = int(ref_tbits2)
ref_terrs2 = int(ref_terrs2)
# Read stm log
print("Target")
with open("stdout.log", "r") as f:
for line in f:
if (line[0:4] == "BER2"):
print(line, end="")
_, tgt_ber2, _, tgt_tbits2, _, tgt_terrs2 = line.split()
elif (line[0:3] == "BER"):
print(line, end="")
_, tgt_ber, _, tgt_tbits, _, tgt_terrs = line.split()
elif (line[0:9] == "Coded BER"):
print(line, end="")
_, _, tgt_ber2, _, tgt_tbits2, _, tgt_terrs2 = line.split()
# Strings to integers
tgt_ber = float(tgt_ber)
tgt_tbits = int(tgt_tbits)
tgt_terrs = int(tgt_terrs)
tgt_ber2 = float(tgt_ber2)
tgt_tbits2 = int(tgt_tbits2)
tgt_terrs2 = int(tgt_terrs2)
# simple hack to tolerate zero bits > NAN
if (math.isnan(ref_ber2)): ref_ber2 = 0
if (math.isnan(tgt_ber2)): tgt_ber2 = 0
## Max BER values
if ((tgt_ber > max_ber) or (tgt_ber2 > max_ber2)):
fails += 1
print("FAIL: max BER")
else:
print("PASS: max BER")
## Compare BER values
if (compare_ber):
chk_tolerance_ber = abs(ref_ber - tgt_ber)
chk_tolerance_tbits = abs(ref_tbits - tgt_tbits)
chk_tolerance_terrs = abs(ref_terrs - tgt_terrs)
chk_tolerance_ber2 = abs(ref_ber2 - tgt_ber2)
chk_tolerance_tbits2 = abs(ref_tbits2 - tgt_tbits2)
chk_tolerance_terrs2 = abs(ref_terrs2 - tgt_terrs2)
passes = True
if (chk_tolerance_ber > tolerance_ber):
print("fail tolerance_ber {} > {}".
format(chk_tolerance_ber, tolerance_ber))
passes = False
if (chk_tolerance_tbits > tolerance_tbits):
print("fail tolerance_tbits {} > {}".
format(chk_tolerance_tbits, tolerance_tbits))
passes = False
if (chk_tolerance_terrs > tolerance_terrs):
print("fail tolerance_terrs {} > {}".
format(chk_tolerance_terrs, tolerance_terrs))
passes = False
if (ref_tbits2 == 0):
if (chk_tolerance_ber2 > tolerance_ber2):
print("fail tolerance_ber2 {} > {}".
format(chk_tolerance_ber2, tolerance_ber2))
passes = False
if (chk_tolerance_tbits2 > tolerance_tbits):
print("fail tolerance_tbits2 {} > {}".
format(chk_tolerance_tbits2, tolerance_tbits))
passes = False
if (chk_tolerance_terrs2 > tolerance_terrs):
print("fail tolerance_terrs2 {} > {}".
format(chk_tolerance_terrs2, tolerance_terrs))
passes = False
if (passes):
print("PASS: BER compare")
else:
fails += 1
print("FAIL: BER compare")
# end Compare BER
# end BER checks
#### Output differences
if (compare_output):
print("\nOutput checks")
# Output is a binary file of bytes whose values are 0x00 or 0x01.
with open("ref_demod_out.raw", "rb") as f: ref_out_bytes = f.read()
with open("stm_out.raw", "rb") as f: tgt_out_bytes = f.read()
if (len(ref_out_bytes) != len(tgt_out_bytes)):
fails += 1
print("FAIL Output, length mismatch")
else:
output_diffs = 0
for i in range(len(ref_out_bytes)):
fnum = math.floor(i/Nbitsperframe)
bnum = i - (fnum * Nbitsperframe)
# Both legal values??
if (ref_out_bytes[i] > 1):
print("Error: Output frame {} byte {} not 0 or 1 in reference data".format(fnum, bnum))
fails += 1
if (tgt_out_bytes[i] > 1):
print("Error: Output frame {} byte {} not 0 or 1 in target data".format(fnum, bnum))
fails += 1
# Match??
if (ref_out_bytes[i] != tgt_out_bytes[i]):
print("Output frame {} byte {} mismatch: ref={} tgt={}".format(
fnum, bnum, ref_out_bytes[i], tgt_out_bytes[i]))
output_diffs += 1
# end for i
if (output_diffs > tolerance_output_differences):
print("FAIL: Output Differences = {}".format(output_diffs))
fails += 1
else:
print("PASS: Output Differences = {}".format(output_diffs))
# end not length mismatch
#### Syms data
if (config_log_payload_syms):
print("\nSyms and Amps checks")
fref = open("ofdm_demod_ref_log.txt", "r")
fdiag = open("stm_diag.raw", "rb")
ref_data = read_octave_text(fref)
(tgt_syms, tgt_amps) = read_tgt_syms(fdiag)
fdiag.close()
write_syms_as_octave(tgt_syms, tgt_amps) # for manual debug...
# Find smallest common subset
hgt = min(tgt_syms.shape[0], ref_data["payload_syms_log_c"].shape[0])
wid = min(tgt_syms.shape[1], ref_data["payload_syms_log_c"].shape[1])
ref_syms = ref_data["payload_syms_log_c"][:hgt][:wid]
ref_amps = ref_data["payload_amps_log_c"][:hgt][:wid]
tgt_syms= tgt_syms[:hgt][:wid]
tgt_amps= tgt_amps[:hgt][:wid]
# Eliminate trailing rows of all zeros
# Sum the rows to find rows of all zeros
row_sums = ref_syms.sum(axis=1) + tgt_syms.sum(axis=1)
nonzeros = row_sums.nonzero()
last_nonzero = nonzeros[0][-1]
# stop index is 1 past the last!!
# and use the Magnitude of the complex values
ref_syms = np.abs(ref_syms[:last_nonzero+1])
ref_amps = np.abs(ref_amps[:last_nonzero+1])
tgt_syms = np.abs(tgt_syms[:last_nonzero+1])
tgt_amps = np.abs(tgt_amps[:last_nonzero+1])
# Differences - Syms
#diffs_syms = np.abs(ref_syms - tgt_syms) # This is the mag of complex
diffs_syms = np.abs(np.divide((ref_syms - tgt_syms), ref_syms,
where=(ref_syms!=0)))
print("Minimum syms difference = {:.6f}".format(np.amin(diffs_syms)))
print("Maximum syms difference = {:.6f}".format(np.amax(diffs_syms)))
print("Average syms difference = {:.6f}".format(np.average(diffs_syms)))
if (args.verbose): # Print top 10 differences
diffs_syms_sorted_indexes = (diffs_syms).argsort(axis=None)[::-1]
print(" Top 10 differences")
for i in range(10):
j = diffs_syms_sorted_indexes[i]
print(" #{} @{}: {} <?> {} = {:.6f}".format(
i, j,
ref_syms.flatten()[j], tgt_syms.flatten()[j], diffs_syms.flatten()[j])
)
# Errors are differences > tolerance_syms
errors_syms = diffs_syms - tolerance_syms
errors_syms[errors_syms < 0.0] = 0.0
num_errors_syms = np.count_nonzero(errors_syms)
error_rows_syms = np.amax(errors_syms, axis=1)
num_error_rows_syms = np.count_nonzero(error_rows_syms)
print("")
print("{} symbol errors on {} rows".format(num_errors_syms, num_error_rows_syms))
# Differences - Amps
diffs_amps = np.abs(np.divide((ref_amps - tgt_amps), ref_amps,
where=(ref_amps!=0)))
print("Minimum amps difference = {:.6f}".format(np.amin(diffs_amps)))
print("Maximum amps difference = {:.6f}".format(np.amax(diffs_amps)))
print("Average amps difference = {:.6f}".format(np.average(diffs_amps)))
if (args.verbose): # Print top 10 differences
diffs_amps_sorted_indexes = (diffs_amps).argsort(axis=None)[::-1]
print(" Top 10 differences")
for i in range(10):
j = diffs_amps_sorted_indexes[i]
print(" #{} @{}: {} <?> {} = {:.6f}".format(
i, j,
ref_amps.flatten()[j], tgt_amps.flatten()[j], diffs_amps.flatten()[j])
)
# Errors are differences > tolerance_syms
errors_amps = diffs_amps - tolerance_amps
errors_amps[errors_amps < 0.0] = 0.0
num_errors_amps = np.count_nonzero(errors_amps)
error_rows_amps = np.amax(errors_amps, axis=1)
num_error_rows_amps = np.count_nonzero(error_rows_amps)
print("")
print("{} Amplitude errors on {} rows".format(num_errors_amps, num_error_rows_amps))
# End compare_output
#### Profile
if (config_profile):
print("\nProfile:")
with open("stdout.log", "r") as f:
sum_profiles.sum_profiles(f, 100)
print("\nStack:")
with open("stdout.txt", "r") as f:
for line in f:
if (line.startswith("Max stack")):
print(line)
#### Print final status message
if (fails): print("\nTest FAILED!")
else: print("\nTest PASSED")
sys.exit(fails)
+100
View File
@@ -0,0 +1,100 @@
#!/bin/bash -x
#
# tst_ofdm_demod_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
case "${TEST_OPT}" in
quick )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "01000000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out stm_in.raw --testframes 10 > setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --verbose 1 > ref_gen_log.txt 2>&1
;;
ideal )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "01000000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out stm_in.raw --testframes 10 > setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --verbose 1 > ref_gen_log.txt 2>&1
;;
AWGN )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "11000000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 10 > setup.log 2>&1
cohpsk_ch mod_bits.raw stm_in.raw -20 --Fs 8000 -f -5 >> setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --verbose 1 > ref_gen_log.txt 2>&1
;;
fade )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "11000000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 60 > setup.log 2>&1
ch mod_bits.raw stm_in.raw --No -24.5 -f -10 --mpp \
--fading_dir ${CODEC2_BASE}/build_linux/unittest >> setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --verbose 1 > ref_gen_log.txt 2>&1
;;
profile )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "00001000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 100 > setup.log 2>&1
ch mod_bits.raw stm_in.raw --No -20 -f -10 --mpp \
--fading_dir ${CODEC2_BASE}/build_linux/unittest >> setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --verbose 1 > ref_gen_log.txt 2>&1
;;
ldpc )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "01110000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out stm_in.raw --testframes 1 --ldpc 1 > setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --ldpc 1 --verbose 1 > ref_gen_log.txt 2>&1
;;
ldpc_AWGN )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "01110000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 30 --ldpc 1 > setup.log 2>&1
ch mod_bits.raw stm_in.raw --No -20 -f -10 >> setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --ldpc 1 --verbose 1 > ref_gen_log.txt 2>&1
;;
ldpc_fade )
# Config is <verbose>, <testframes>, <ldpc_en>, <log_payload_syms> <profile>
echo "01110000" > stm_cfg.txt
ofdm_mod --in /dev/zero --out mod_bits.raw --testframes 120 --ldpc 1 > setup.log 2>&1
ch mod_bits.raw stm_in.raw --No -30 -f -10 --mpp \
--fading_dir ${CODEC2_BASE}/build_linux/unittest >> setup.log 2>&1
ofdm_demod --in stm_in.raw --out ref_demod_out.raw --log ofdm_demod_ref_log.txt \
--testframes --ldpc 1 --verbose 1 > ref_gen_log.txt 2>&1;
;;
esac
+65
View File
@@ -0,0 +1,65 @@
#!/bin/bash -x
#
# tst_ofdm_mod_check
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test CHECK actions:
declare -i Fails=0
case "${TEST_OPT}" in
plain) LDPC="";;
ldpc) LDPC="--ldpc";;
esac
echo -e "\nReference check"
if ofdm_demod --in ref_mod_out.raw --out ref_ofdm_demod.raw --testframes ${LDPC}; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
echo -e "\nTarget check"
if ofdm_demod --in mod.raw --out stm_demod.raw --testframes ${LDPC}; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
echo -e "\nCompare output binary data"
if compare_ints -s -b2 -t3 ref_mod_out.raw mod.raw; then
echo "Passed"
else
echo "Failed"
let Fails=($Fails + 1)
fi
#
if (( $Fails == 0 )); then
echo -e "\nTest PASSED"
else
echo -e "\nTest FAILED!"
fi
exit $Fails
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
#
# tst_ofdm_mod_setup
#
# Setup input and reference data for one of several versions of this test.
# Find the scripts directory
SCRIPTS="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
# Setup common variables
source $SCRIPTS/run_tests_common.sh
# RUN_DIR - Directory where test will be run
RUN_DIR="${UNITTEST_BASE}/test_run/${FULL_TEST_NAME}"
# Call common setup function to make the directory
setup_common "${RUN_DIR}"
# Change to test directory
cd "${RUN_DIR}"
#####################################################################
## Test SETUP actions:
case "${TEST_OPT}" in
plain )
# Config is <unused>, <unused>, <ldpc_en>, <unused> <profile>
echo "00000000" > stm_cfg.txt
ofdm_get_test_bits --out stm_in.raw --frames 10 --verbose > setup.log 2>&1
ofdm_mod --in stm_in.raw --out ref_mod_out.raw --verbose 1 > ref_gen_log.txt 2>&1
;;
ldpc )
# Config is <unused>, <unused>, <ldpc_en>, <unused> <profile>
echo "00100000" > stm_cfg.txt
ofdm_get_test_bits --out stm_in.raw --frames 10 --length 112 --verbose > setup.log 2>&1
ofdm_mod --in stm_in.raw --out ref_mod_out.raw --ldpc --verbose 1 > ref_gen_log.txt 2>&1
;;
esac
+161
View File
@@ -0,0 +1,161 @@
set(STM32F4_SYSTEM_SRCS
../../src/system_stm32f4xx.c
../../src/memtools.c
../../src/stm32f4_machdep.c
startup_stm32f4xx.s
)
list(APPEND SEMIHOSTING_SRCS semihosting.c ${STM32F4_SYSTEM_SRCS})
list(APPEND SEMIHOSTING_PROFILE_LIBS codec2_prof stm32f4 CMSIS rdimon)
list(APPEND SEMIHOSTING_LIBS codec2 stm32f4 CMSIS rdimon)
macro(profiledSemihostedBin target)
add_mapped_executable(${target} ${target}.c ${SEMIHOSTING_SRCS})
target_link_libraries(${target} ${SEMIHOSTING_PROFILE_LIBS})
target_compile_definitions(${target} PRIVATE "-DPROFILE -DSEMIHOST_USE_STDIO --specs=rdimon.specs")
elf2bin(${target})
endmacro()
macro(semihostedBin target)
add_mapped_executable(${target} ${target}.c ${SEMIHOSTING_SRCS})
target_link_libraries(${target} ${SEMIHOSTING_LIBS})
target_compile_definitions(${target} PRIVATE "-DSEMIHOST_USE_STDIO --specs=rdimon.specs")
elf2bin(${target})
endmacro()
semihostedBin(tst_api_tx)
semihostedBin(tst_codec2_enc)
semihostedBin(tst_codec2_dec)
semihostedBin(tst_ofdm_mod)
profiledSemihostedBin(tst_ofdm_demod)
semihostedBin(tst_ldpc_enc)
semihostedBin(tst_ldpc_dec)
semihostedBin(tst_api_mod)
profiledsemihostedBin(tst_api_demod)
semihostedBin(tst_semihost)
semihostedBin(tst_codec2_fft_init)
add_test(NAME check_ram_limit
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/check_ram_limit
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test(NAME tst_ldpc_enc
COMMAND sh -c "./run_stm32_tst tst_ldpc_enc ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_ldpc_dec_ideal
COMMAND sh -c "./run_stm32_tst tst_ldpc_dec ideal ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_ldpc_dec_noise
COMMAND sh -c "./run_stm32_tst tst_ldpc_dec noise ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ldpc_dec_noise PROPERTIES DEPENDS tst_ldpc_dec_ideal)
add_test(NAME tst_ofdm_mod_plain
COMMAND sh -c "./run_stm32_tst tst_ofdm_mod plain ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_ofdm_mod_ldpc
COMMAND sh -c "./run_stm32_tst tst_ofdm_mod ldpc ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ofdm_mod_ldpc PROPERTIES DEPENDS tst_ofdm_mod_plain)
add_test(NAME tst_ofdm_demod_quick
COMMAND sh -c "./run_stm32_tst tst_ofdm_demod quick ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_ofdm_demod_ideal
COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ideal ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ofdm_demod_ideal PROPERTIES DEPENDS tst_ofdm_demod_quick)
add_test(NAME tst_ofdm_demod_AWGN
COMMAND sh -c "./run_stm32_tst tst_ofdm_demod AWGN ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ofdm_demod_AWGN PROPERTIES DEPENDS tst_ofdm_demod_quick)
add_test(NAME tst_ofdm_demod_fade
COMMAND sh -c "./run_stm32_tst tst_ofdm_demod fade ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ofdm_demod_fade PROPERTIES DEPENDS tst_ofdm_demod_quick)
add_test(NAME tst_ofdm_demod_ldpc
COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ldpc ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ofdm_demod_ldpc PROPERTIES DEPENDS tst_ofdm_demod_quick)
add_test(NAME tst_ofdm_demod_ldpc_AWGN
COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ldpc_AWGN ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ofdm_demod_ldpc_AWGN PROPERTIES DEPENDS tst_ofdm_demod_quick)
add_test(NAME tst_ofdm_demod_ldpc_fade
COMMAND sh -c "./run_stm32_tst tst_ofdm_demod ldpc_fade ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_ofdm_demod_ldpc_fade PROPERTIES DEPENDS tst_ofdm_demod_quick)
add_test(NAME tst_codec2_enc_1300
COMMAND sh -c "./run_stm32_tst tst_codec2_enc 1300 ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_codec2_enc_700C
COMMAND sh -c "./run_stm32_tst tst_codec2_enc 700C ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_codec2_enc_700C PROPERTIES DEPENDS tst_codec2_enc_1300)
add_test(NAME tst_codec2_dec_1300
COMMAND sh -c "./run_stm32_tst tst_codec2_dec 1300 ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_codec2_dec_700C
COMMAND sh -c "./run_stm32_tst tst_codec2_dec 700C ${UT_PARAMS} "
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
set_tests_properties(tst_codec2_dec_700C PROPERTIES DEPENDS tst_codec2_dec_1300)
add_test(NAME tst_api_mod_700D_TEST
COMMAND sh -c "./run_stm32_tst tst_api_mod 700D_TEST ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_mod_700D_CODEC
COMMAND sh -c "./run_stm32_tst tst_api_mod 700D_CODEC ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_mod_700E_TEST
COMMAND sh -c "./run_stm32_tst tst_api_mod 700E_TEST ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_mod_700E_CODEC
COMMAND sh -c "./run_stm32_tst tst_api_mod 700E_CODEC ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_demod_700D_plain_test
COMMAND sh -c "./run_stm32_tst tst_api_demod 700D_plain_test ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_demod_700D_AWGN_test
COMMAND sh -c "./run_stm32_tst tst_api_demod 700D_AWGN_test ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_demod_700D_AWGN_codec
COMMAND sh -c "./run_stm32_tst tst_api_demod 700D_AWGN_codec ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_demod_700E_plain_test
COMMAND sh -c "./run_stm32_tst tst_api_demod 700E_plain_test ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_demod_700E_AWGN_test
COMMAND sh -c "./run_stm32_tst tst_api_demod 700E_AWGN_test ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_demod_700E_AWGN_codec
COMMAND sh -c "./run_stm32_tst tst_api_demod 700E_AWGN_codec ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
add_test(NAME tst_api_demod_1600_plain_codec
COMMAND sh -c "./run_stm32_tst tst_api_demod 1600_plain_codec ${UT_PARAMS}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../scripts)
+745
View File
@@ -0,0 +1,745 @@
# Makefile for stm32f4 Codec 2 unittest programs
# Include local definitions if they exist.
-include local.mak
###################################################
FLOAT_TYPE=hard
###################################################
CROSS_COMPILE ?= arm-none-eabi-
CC=$(BINPATH)$(CROSS_COMPILE)gcc
AS=$(BINPATH)$(CROSS_COMPILE)as
OBJCOPY=$(BINPATH)$(CROSS_COMPILE)objcopy
SIZE=$(BINPATH)$(CROSS_COMPILE)size
SUDO ?= sudo
###################################################
CFLAGS = -std=gnu11 -O2 -g -Wall -DSTM32F40_41xxx -DCORTEX_M4
CFLAGS += -mlittle-endian -mthumb -mthumb-interwork -nostartfiles -mcpu=cortex-m4 -Wno-unused-function
ifeq ($(FLOAT_TYPE), hard)
CFLAGS += -fsingle-precision-constant -Wdouble-promotion
CFLAGS += -fdata-sections -ffunction-sections -Xlinker --gc-sections
CFLAGS += -mfpu=fpv4-sp-d16 -mfloat-abi=hard -D__FPU_PRESENT=1 -D__FPU_USED=1
else
CFLAGS += -msoft-float
endif
#CFLAGS += -DDEBUG_ALLOC
###################################################
# STM32F4 Standard Peripheral Library
PERIPHLIBDIR ?= STM32F4xx_DSP_StdPeriph_Lib
CMSIS = $(PERIPHLIBDIR)/Libraries/CMSIS
STM32F4LIB = $(PERIPHLIBDIR)/Libraries/STM32F4xx_StdPeriph_Driver
STM32F4TEMPLATE = $(PERIPHLIBDIR)/Project/STM32F4xx_StdPeriph_Templates
DSPLIB = $(PERIPHLIBDIR)/Libraries/CMSIS/DSP_Lib
CFLAGS += -DUSE_STDPERIPH_DRIVER -I$(STM32F4LIB)/inc -I$(STM32F4TEMPLATE)
CFLAGS += -I$(CMSIS)/Include -I$(CMSIS)/Device/ST/STM32F4xx/Include
CFLAGS += -DARM_MATH_CM4
CFLAGS += -DFDV_ARM_MATH
CFLAGS += -DSEMIHOST_USE_STDIO
# Precious files that should be preserved at all cost!
.PRECIOUS: dl/$(PERIPHLIBZIP)
STM32F4LIB_SRCS=\
$(STM32F4LIB)/src/misc.c\
$(STM32F4LIB)/src/stm32f4xx_adc.c\
$(STM32F4LIB)/src/stm32f4xx_can.c\
$(STM32F4LIB)/src/stm32f4xx_cec.c\
$(STM32F4LIB)/src/stm32f4xx_crc.c\
$(STM32F4LIB)/src/stm32f4xx_cryp_aes.c\
$(STM32F4LIB)/src/stm32f4xx_cryp.c\
$(STM32F4LIB)/src/stm32f4xx_cryp_des.c\
$(STM32F4LIB)/src/stm32f4xx_cryp_tdes.c\
$(STM32F4LIB)/src/stm32f4xx_dac.c\
$(STM32F4LIB)/src/stm32f4xx_dbgmcu.c\
$(STM32F4LIB)/src/stm32f4xx_dcmi.c\
$(STM32F4LIB)/src/stm32f4xx_dma2d.c\
$(STM32F4LIB)/src/stm32f4xx_dma.c\
$(STM32F4LIB)/src/stm32f4xx_exti.c\
$(STM32F4LIB)/src/stm32f4xx_flash.c\
$(STM32F4LIB)/src/stm32f4xx_flash_ramfunc.c\
$(STM32F4LIB)/src/stm32f4xx_fmpi2c.c\
$(STM32F4LIB)/src/stm32f4xx_fsmc.c\
$(STM32F4LIB)/src/stm32f4xx_gpio.c\
$(STM32F4LIB)/src/stm32f4xx_hash.c\
$(STM32F4LIB)/src/stm32f4xx_hash_md5.c\
$(STM32F4LIB)/src/stm32f4xx_hash_sha1.c\
$(STM32F4LIB)/src/stm32f4xx_i2c.c\
$(STM32F4LIB)/src/stm32f4xx_iwdg.c\
$(STM32F4LIB)/src/stm32f4xx_ltdc.c\
$(STM32F4LIB)/src/stm32f4xx_pwr.c\
$(STM32F4LIB)/src/stm32f4xx_qspi.c\
$(STM32F4LIB)/src/stm32f4xx_rcc.c\
$(STM32F4LIB)/src/stm32f4xx_rng.c\
$(STM32F4LIB)/src/stm32f4xx_rtc.c\
$(STM32F4LIB)/src/stm32f4xx_sai.c\
$(STM32F4LIB)/src/stm32f4xx_sdio.c\
$(STM32F4LIB)/src/stm32f4xx_spdifrx.c\
$(STM32F4LIB)/src/stm32f4xx_spi.c\
$(STM32F4LIB)/src/stm32f4xx_syscfg.c\
$(STM32F4LIB)/src/stm32f4xx_tim.c\
$(STM32F4LIB)/src/stm32f4xx_usart.c\
$(STM32F4LIB)/src/stm32f4xx_wwdg.c
STM32F4LIB_OBJS = $(STM32F4LIB_SRCS:.c=.o)
CMSIS_SRCS=\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_abs_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_add_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_dot_prod_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_mult_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_negate_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_offset_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_scale_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_shift_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_shift_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_shift_q7.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_f32.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_q15.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_q31.c\
$(CMSIS)/DSP_Lib/Source/BasicMathFunctions/arm_sub_q7.c\
$(CMSIS)/DSP_Lib/Source/CommonTables/arm_common_tables.c\
$(CMSIS)/DSP_Lib/Source/CommonTables/arm_const_structs.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_f32.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_q15.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_conj_q31.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f32.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q15.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q31.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_f32.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_q31.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f32.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q15.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q31.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f32.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q15.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q31.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_f32.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_q15.c\
$(CMSIS)/DSP_Lib/Source/ComplexMathFunctions/arm_cmplx_mult_real_q31.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_init_f32.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_init_q15.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_init_q31.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_f32.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_q15.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_pid_reset_q31.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_sin_cos_f32.c\
$(CMSIS)/DSP_Lib/Source/ControllerFunctions/arm_sin_cos_q31.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_cos_f32.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_cos_q15.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_cos_q31.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sin_f32.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sin_q15.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sin_q31.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sqrt_q15.c\
$(CMSIS)/DSP_Lib/Source/FastMathFunctions/arm_sqrt_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df1_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_f64.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f64.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_opt_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_fast_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_opt_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_opt_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_opt_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_fast_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_opt_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_opt_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_partial_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_conv_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_opt_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_fast_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_opt_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_opt_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_correlate_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_fast_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_fast_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_decimate_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_fast_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_init_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_interpolate_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_lattice_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_init_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_fir_sparse_q7.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_iir_lattice_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_f32.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_init_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_norm_q31.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_q15.c\
$(CMSIS)/DSP_Lib/Source/FilteringFunctions/arm_lms_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_add_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_add_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_add_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_cmplx_mult_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_init_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_init_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_init_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_inverse_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_inverse_f64.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_fast_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_fast_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_mult_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_scale_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_sub_q31.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_f32.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_q15.c\
$(CMSIS)/DSP_Lib/Source/MatrixFunctions/arm_mat_trans_q31.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_f32.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_q15.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_q31.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_max_q7.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_f32.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_q15.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_q31.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_mean_q7.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_f32.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_q15.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_q31.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_min_q7.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_f32.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_q15.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_q31.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_power_q7.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_rms_f32.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_rms_q15.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_rms_q31.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_std_f32.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_std_q15.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_std_q31.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_var_f32.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_var_q15.c\
$(CMSIS)/DSP_Lib/Source/StatisticsFunctions/arm_var_q31.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_f32.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_q15.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_q31.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_copy_q7.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_f32.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_q15.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_q31.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_fill_q7.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q15.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q31.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_float_to_q7.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q15_to_float.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q15_to_q31.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q15_to_q7.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q31_to_float.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q31_to_q15.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q31_to_q7.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q7_to_float.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q7_to_q15.c\
$(CMSIS)/DSP_Lib/Source/SupportFunctions/arm_q7_to_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_bitreversal.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_init_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix2_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_init_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix4_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_cfft_radix8_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_init_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_init_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_init_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_dct4_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_fast_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_fast_init_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_init_f32.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_init_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_init_q31.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_q15.c\
$(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_rfft_q31.c\
CMSIS_OBJS = $(CMSIS_SRCS:.c=.o) $(CMSIS)/DSP_Lib/Source/TransformFunctions/arm_bitreversal2.o
###################################################
# Codec 2
CODEC2_DIR = ../../..
CODEC2_SRC = $(CODEC2_DIR)/src
CODEC2_BLD = $(CODEC2_DIR)/build_linux
CODEC2_SRCS=\
$(CODEC2_SRC)/lpc.c \
$(CODEC2_SRC)/nlp.c \
$(CODEC2_SRC)/postfilter.c \
$(CODEC2_SRC)/sine.c \
$(CODEC2_SRC)/codec2.c \
$(CODEC2_SRC)/codec2_fft.c \
$(CODEC2_SRC)/cohpsk.c \
$(CODEC2_SRC)/linreg.c \
$(CODEC2_SRC)/kiss_fft.c \
$(CODEC2_SRC)/kiss_fftr.c \
$(CODEC2_SRC)/interp.c \
$(CODEC2_SRC)/lsp.c \
$(CODEC2_SRC)/mbest.c \
$(CODEC2_SRC)/newamp1.c \
$(CODEC2_SRC)/phase.c \
$(CODEC2_SRC)/quantise.c \
$(CODEC2_SRC)/pack.c \
$(CODEC2_SRC)/codebook.c \
$(CODEC2_SRC)/codebookd.c \
$(CODEC2_SRC)/codebookjvm.c \
$(CODEC2_SRC)/codebookge.c \
$(CODEC2_SRC)/codebooknewamp1.c \
$(CODEC2_SRC)/codebooknewamp1_energy.c \
$(CODEC2_SRC)/dump.c \
$(CODEC2_SRC)/fdmdv.c \
$(CODEC2_SRC)/freedv_api.c \
$(CODEC2_SRC)/filter.c \
$(CODEC2_SRC)/varicode.c \
$(CODEC2_SRC)/golay23.c \
$(CODEC2_SRC)/fsk.c \
$(CODEC2_SRC)/fmfsk.c \
$(CODEC2_SRC)/freedv_vhf_framing.c \
$(CODEC2_SRC)/freedv_data_channel.c \
$(CODEC2_SRC)/ofdm.c \
$(CODEC2_SRC)/phi0.c \
$(CODEC2_SRC)/mpdecode_core.c \
$(CODEC2_SRC)/gp_interleaver.c \
$(CODEC2_SRC)/interldpc.c \
$(CODEC2_SRC)/HRA_112_112.c \
CFLAGS += -D__EMBEDDED__
CFLAGS += -I$(CODEC2_SRC)
CFLAGS += -I$(CODEC2_BLD)
###################################################
# Codec2/STM32
CODEC2_STM32_DIR := ../..
CODEC2_STM32_SRC = $(CODEC2_STM32_DIR)/src
CODEC2_STM32_HDR = $(CODEC2_STM32_DIR)/inc
CFLAGS += -I$(CODEC2_STM32_HDR)
CFLAGS += -T$(CODEC2_STM32_DIR)/stm32_flash.ld
#enable this for dump files to help verify optimisation
#CFLAGS += -DDUMP
ASFLAGS += $(CFLAGS)
###################################################
ROOT=$(shell pwd)
# Library paths
LIBPATHS =
# Libraries to link
# Standard ARM semihosting
LIBS = -lg -lrdimon -lm --specs=rdimon.specs
# startup file
SRCS += startup_stm32f4xx.s
SRCS += init.c
SRCS += stm32f4_machdep.c
SRCS += $(CODEC2_STM32_SRC)/system_stm32f4xx.c
all: libstm32f4.a \
tst_codec2_enc.bin tst_codec2_dec.bin \
tst_ofdm_mod.bin tst_ofdm_demod.bin \
tst_ldpc_enc.bin tst_ldpc_dec.bin \
tst_api_mod.bin tst_api_demod.bin \
tst_semihost.bin \
tst_codec2_fft_init.bin
libstm32f4.a: $(CMSIS_OBJS) $(STM32F4LIB_OBJS)
find -L $(PERIPHLIBDIR) -type f -name '*.o' -exec $(AR) crs libstm32f4.a {} ";"
# Kludgy target to build a file with CFLAGS -DPROFILE
%.profile.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -DPROFILE -c -o $@ $<
# Rule for building .bin files from a .elf
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
#####%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%####
##### Used for debugging stdio (with semihosting) :
##
## TMP_NEWLIB_INCS = -INewlib
## TMP_NEWLIB_DEFS = -DARM_RDI_MONITOR
## TMP_NEWLIB_OBJS = Newlib/fread.o Newlib/refill.o Newlib/syscalls.o Newlib/stdio.o Newlib/readr.o Newlib/fclose.o Newlib/fflush.o
##
## Newlib/fread.o: Newlib/fread.c
## $(CC) -c $(CFLAGS) $^ -o Newlib/fread.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS)
##
## Newlib/refill.o: Newlib/refill.c
## $(CC) -c $(CFLAGS) $^ -o Newlib/refill.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS)
##
## Newlib/syscalls.o: Newlib/syscalls.c
## $(CC) -c $(CFLAGS) $^ -o Newlib/syscalls.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS)
##
## Newlib/stdio.o: Newlib/stdio.c
## $(CC) -c $(CFLAGS) $^ -o Newlib/stdio.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS)
##
## Newlib/readr.o: Newlib/readr.c
## $(CC) -c $(CFLAGS) $^ -o Newlib/readr.o $(TMP_NEWLIB_INCS) $(TMP_NEWLIB_DEFS)
##
#####%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%####
####################################################
# Test Programs
# -----------------------------------------------
TST_API_TX_SRCS=\
tst_api_tx.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
TST_API_TX_SRCS += $(CODEC2_SRCS)
TST_API_TX_SRCS += $(SRCS)
tst_api_tx.elf: $(TST_API_TX_SRCS:.c=.profile.o) libstm32f4.a
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
TST_CODEC2_ENC_SRCS=\
tst_codec2_enc.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_CODEC2_ENC_SRCS += $(CODEC2_SRCS)
TST_CODEC2_ENC_SRCS += $(SRCS)
#
tst_codec2_enc.elf: $(TST_CODEC2_ENC_SRCS:.c=.profile.o) libstm32f4.a
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_codec2_enc.map
# -----------------------------------------------
TST_CODEC2_DEC_SRCS=\
tst_codec2_dec.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_CODEC2_DEC_SRCS += $(CODEC2_SRCS)
TST_CODEC2_DEC_SRCS += $(SRCS)
#
tst_codec2_dec.elf: $(TST_CODEC2_DEC_SRCS:.c=.profile.o) libstm32f4.a
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
TST_API_MOD_SRCS=\
tst_api_mod.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_API_MOD_SRCS += $(CODEC2_SRCS)
TST_API_MOD_SRCS += $(SRCS)
#
tst_api_mod.elf: $(TST_API_MOD_SRCS:.c=.profile.o) libstm32f4.a # $(TMP_NEWLIB_OBJS)
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
# TST_API_MOD_700D_PROFILE
#
TST_API_MOD_700D_PROFILE_SRCS=\
tst_api_mod_700d_profile.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_API_MOD_700D_PROFILE_SRCS += $(CODEC2_SRCS)
TST_API_MOD_700D_PROFILE_SRCS += $(SRCS)
#
tst_api_mod_700d_profile.elf: $(TST_API_MOD_700D_PROFILE_SRCS:.c=.profile.o) libstm32f4.a
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
# TST_API_DEMOD
TST_API_DEMOD_SRCS=\
tst_api_demod.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
## (for debug use) sbrk_dbg.c \
#
TST_API_DEMOD_SRCS += $(CODEC2_SRCS)
TST_API_DEMOD_SRCS += $(SRCS)
#
tst_api_demod.elf: $(TST_API_DEMOD_SRCS:.c=.o) libstm32f4.a
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_api_demod.map
# -----------------------------------------------
# TST_API_DEMOD_700D_PROFILE
api_demod_700d_in_10f:
# Each frame of OFDM is 160ms which is 1280 speech samples of 2 bytes each.
#
dd bs=2560 count=100 if=../../../raw/hts1.raw of=tmp_spch_in.raw
cohpsk_ch tmp_spch_in.raw tmp_modout.raw -20 -Fs 8000 -f -5 --raw_dir ../../../raw
freedv_tx 700D tmp_modout.raw api_demod_700d_in_10f --txbpf 0
#
api_demod_700d_in_10f.c: api_demod_700d_in_10f
xxd -i api_demod_700d_in_10f > api_demod_700d_in_10f.c
#
TST_API_DEMOD_700D_PROFILE_SRCS=\
tst_api_demod_700d_profile.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
## (for debug use) sbrk_dbg.c \
#
tst_api_demod_700d_profile.profile.o: tst_api_demod_700d_profile.c api_demod_700d_in_10f.c
$(CC) $(CPPFLAGS) $(CFLAGS) -DPROFILE -c -o $@ $<
#
TST_API_DEMOD_700D_PROFILE_SRCS += $(CODEC2_SRCS)
TST_API_DEMOD_700D_PROFILE_SRCS += $(SRCS)
#
tst_api_demod_700d_profile.elf: $(TST_API_DEMOD_700D_PROFILE_SRCS:.c=.profile.o) libstm32f4.a
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
TST_OFDM_MOD_SRCS=\
tst_ofdm_mod.c \
semihosting.c \
$(CODEC2_SRC)/ofdm.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
TST_OFDM_MOD_SRCS += $(CODEC2_SRCS)
TST_OFDM_MOD_SRCS += $(SRCS)
tst_ofdm_mod.elf: $(TST_OFDM_MOD_SRCS:.c=.profile.o) libstm32f4.a
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
TST_OFDM_DEMOD_SRCS=\
tst_ofdm_demod.c \
semihosting.c \
$(CODEC2_SRC)/ofdm.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_OFDM_DEMOD_SRCS += $(CODEC2_SRCS)
TST_OFDM_DEMOD_SRCS += $(SRCS)
#
tst_ofdm_demod.elf: $(TST_OFDM_DEMOD_SRCS:.c=.profile.o) libstm32f4.a
$(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ofdm_demod.map
# -----------------------------------------------
# TST_OFDM_MOD_STACK
#
ofdm_mod_ref_10f:
$(CODEC2_BLD)/src/ofdm_mod /dev/zero ofdm_mod_ref_10f --testframes 1 --ldpc
#
ofdm_mod_ref_10f.c: ofdm_mod_ref_10f
xxd -g2 -e -i ofdm_mod_ref_10f > ofdm_mod_ref_10f.c
#
tst_ofdm_mod_stack.profile.o: tst_ofdm_mod_stack.c ofdm_mod_ref_10f.c
$(CC) $(CPPFLAGS) $(CFLAGS) -DPROFILE -c -o $@ $<
#
TST_OFDM_MOD_STACK_SRCS=\
tst_ofdm_mod_stack.c \
function_trace.c \
$(CODEC2_SRC)/ofdm.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_OFDM_MOD_STACK_SRCS += $(CODEC2_SRCS)
TST_OFDM_MOD_STACK_SRCS += $(SRCS)
#
tst_ofdm_mod_stack.elf: $(TST_OFDM_MOD_STACK_SRCS:.c=.o) libstm32f4.a
$(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ofdm_mod_stack.map
# -----------------------------------------------
# TST_OFDM_DEMOD_STACK
ofdm_demod_in_10f:
$(CODEC2_BLD)/src/ofdm_get_test_bits - -f 10 | \
$(CODEC2_BLD)/src/ofdm_mod - ofdm_demod_in_10f
#
ofdm_demod_in_10f.c: ofdm_demod_in_10f
xxd -i ofdm_demod_in_10f > ofdm_demod_in_10f.c
#
ofdm_demod_ref_10f: ofdm_demod_in_10f
$(CODEC2_BLD)/src/ofdm_demod ofdm_demod_in_10f ofdm_demod_ref_10f
#
ofdm_demod_ref_10f.c: ofdm_demod_ref_10f
xxd -i ofdm_demod_ref_10f > ofdm_demod_ref_10f.c
#
tst_ofdm_demod_stack.o: ofdm_demod_in_10f.c ofdm_demod_ref_10f.c
#
TST_OFDM_DEMOD_STACK_SRCS=\
tst_ofdm_demod_stack.c \
$(CODEC2_SRC)/ofdm.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_OFDM_DEMOD_STACK_SRCS += $(CODEC2_SRCS)
TST_OFDM_DEMOD_STACK_SRCS += $(SRCS)
#
tst_ofdm_demod_stack.elf: $(TST_OFDM_DEMOD_STACK_SRCS:.c=.o) libstm32f4.a
$(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ofdm_demod_stack.map
# -----------------------------------------------
# Not working yet!
TST_LDPC_ENC_SRCS= \
tst_ldpc_enc.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_LDPC_ENC_SRCS += $(CODEC2_SRCS)
TST_LDPC_ENC_SRCS += $(SRCS)
#
TST_LDPC_ENC_HDR= \
$(CODEC2_INC)/mpdecode_code_test.h
#
tst_ldpc_enc.elf: $(TST_LDPC_ENC_SRCS:.c=.profile.o) libstm32f4.a $(TST_LDPC_ENC_HRDS)
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
# Not working yet!
TST_LDPC_DEC_SRCS= \
tst_ldpc_dec.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_LDPC_DEC_SRCS += $(CODEC2_SRCS)
TST_LDPC_DEC_SRCS += $(SRCS)
#
TST_LDPC_DEC_HDR= \
$(CODEC2_INC)/mpdecode_code.h
#
tst_ldpc_dec.elf: $(TST_LDPC_DEC_SRCS:.c=.profile.o) libstm32f4.a $(TST_LDPC_DEC_HRDS)
$(CC) $(CFLAGS) -DPROFILE $^ -o $@ $(LIBPATHS) $(LIBS) -Wl,-Map=tst_ldpc_dec.map
# -----------------------------------------------
TST_SEMIHOST_SRCS=\
tst_semihost.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_SEMIHOST_SRCS += $(CODEC2_SRCS)
TST_SEMIHOST_SRCS += $(SRCS)
#
tst_semihost.elf: $(TST_SEMIHOST_SRCS:.c=.o) libstm32f4.a #$(TMP_NEWLIB_OBJS)
$(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS)
# -----------------------------------------------
TST_CODEC2_FFT_INIT_SRCS=\
tst_codec2_fft_init.c \
semihosting.c \
$(CODEC2_STM32_SRC)/system_stm32f4xx.c
#
TST_CODEC2_FFT_INIT_SRCS += $(CODEC2_SRCS)
TST_CODEC2_FFT_INIT_SRCS += $(SRCS)
#
tst_codec2_fft_init.elf: $(TST_CODEC2_FFT_INIT_SRCS:.c=.o) libstm32f4.a
$(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS)
###################################################
clean:
rm -f *.elf *.bin
rm -f libstm32f4.a
rm -f $(CMSIS_OBJS) $(STM32F4LIB_OBJS) $(CODEC2_SRC)/*.o
find . -type f -name '*.o' | xargs rm -f
+10
View File
@@ -0,0 +1,10 @@
/*
* Dummy function to avoid compiler error
*/
void _init() {
}
void _fini() {
}
+19
View File
@@ -0,0 +1,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include "semihosting.h"
extern void initialise_monitor_handles(void);
extern int errno;
int semihosting_init(void) {
initialise_monitor_handles();
setvbuf(stderr, NULL, _IOLBF, 256);
return(0);
}
/* vi:set ts=4 et sts=4: */
+7
View File
@@ -0,0 +1,7 @@
#ifndef SEMIHOSTING_H
#define SEMIHOSTING_H
extern int semihosting_init(void);
#endif // SEMIHOSTING_H
/* vi:set ts=4 et sts=4: */
@@ -0,0 +1,529 @@
/**
******************************************************************************
* @file startup_stm32f4xx.s
* @author MCD Application Team
* @version V1.0.0
* @date 30-September-2011
* @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Configure the clock system and the external SRAM mounted on
* STM324xG-EVAL board to be used as data memory (optional,
* to be enabled by user)
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M4 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
.global EndofMain
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Fill stack area with a fix pattern for observince max stack use */
mov r2, r3
ldr r3, = _estack
ldr r4, =0x55555555
b LoopFillStack
FillStack:
str r4, [r2], #4
LoopFillStack:
cmp r2, r3
bcc FillStack
/* Call the clock system initialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
EndofMain:
bl .
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
* @param None
* @retval None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_IRQHandler /* EXTI Line0 */
.word EXTI1_IRQHandler /* EXTI Line1 */
.word EXTI2_IRQHandler /* EXTI Line2 */
.word EXTI3_IRQHandler /* EXTI Line3 */
.word EXTI4_IRQHandler /* EXTI Line4 */
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
.word CAN1_TX_IRQHandler /* CAN1 TX */
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word TIM2_IRQHandler /* TIM2 */
.word TIM3_IRQHandler /* TIM3 */
.word TIM4_IRQHandler /* TIM4 */
.word I2C1_EV_IRQHandler /* I2C1 Event */
.word I2C1_ER_IRQHandler /* I2C1 Error */
.word I2C2_EV_IRQHandler /* I2C2 Event */
.word I2C2_ER_IRQHandler /* I2C2 Error */
.word SPI1_IRQHandler /* SPI1 */
.word SPI2_IRQHandler /* SPI2 */
.word USART1_IRQHandler /* USART1 */
.word USART2_IRQHandler /* USART2 */
.word USART3_IRQHandler /* USART3 */
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
.word FSMC_IRQHandler /* FSMC */
.word SDIO_IRQHandler /* SDIO */
.word TIM5_IRQHandler /* TIM5 */
.word SPI3_IRQHandler /* SPI3 */
.word UART4_IRQHandler /* UART4 */
.word UART5_IRQHandler /* UART5 */
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
.word TIM7_IRQHandler /* TIM7 */
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
.word ETH_IRQHandler /* Ethernet */
.word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
.word CAN2_TX_IRQHandler /* CAN2 TX */
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
.word OTG_FS_IRQHandler /* USB OTG FS */
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
.word USART6_IRQHandler /* USART6 */
.word I2C3_EV_IRQHandler /* I2C3 event */
.word I2C3_ER_IRQHandler /* I2C3 error */
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
.word OTG_HS_IRQHandler /* USB OTG HS */
.word DCMI_IRQHandler /* DCMI */
.word CRYP_IRQHandler /* CRYP crypto */
.word HASH_RNG_IRQHandler /* Hash and Rng */
.word FPU_IRQHandler /* FPU */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMP_STAMP_IRQHandler
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
.weak RTC_WKUP_IRQHandler
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Stream0_IRQHandler
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
.weak DMA1_Stream1_IRQHandler
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
.weak DMA1_Stream2_IRQHandler
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
.weak DMA1_Stream3_IRQHandler
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
.weak DMA1_Stream4_IRQHandler
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
.weak DMA1_Stream5_IRQHandler
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
.weak DMA1_Stream6_IRQHandler
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
.weak ADC_IRQHandler
.thumb_set ADC_IRQHandler,Default_Handler
.weak CAN1_TX_IRQHandler
.thumb_set CAN1_TX_IRQHandler,Default_Handler
.weak CAN1_RX0_IRQHandler
.thumb_set CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_TIM9_IRQHandler
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_TIM11_IRQHandler
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak OTG_FS_WKUP_IRQHandler
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
.weak TIM8_BRK_TIM12_IRQHandler
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
.weak TIM8_UP_TIM13_IRQHandler
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
.weak TIM8_TRG_COM_TIM14_IRQHandler
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
.weak TIM8_CC_IRQHandler
.thumb_set TIM8_CC_IRQHandler,Default_Handler
.weak DMA1_Stream7_IRQHandler
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
.weak FSMC_IRQHandler
.thumb_set FSMC_IRQHandler,Default_Handler
.weak SDIO_IRQHandler
.thumb_set SDIO_IRQHandler,Default_Handler
.weak TIM5_IRQHandler
.thumb_set TIM5_IRQHandler,Default_Handler
.weak SPI3_IRQHandler
.thumb_set SPI3_IRQHandler,Default_Handler
.weak UART4_IRQHandler
.thumb_set UART4_IRQHandler,Default_Handler
.weak UART5_IRQHandler
.thumb_set UART5_IRQHandler,Default_Handler
.weak TIM6_DAC_IRQHandler
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
.weak TIM7_IRQHandler
.thumb_set TIM7_IRQHandler,Default_Handler
.weak DMA2_Stream0_IRQHandler
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
.weak DMA2_Stream1_IRQHandler
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
.weak DMA2_Stream2_IRQHandler
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
.weak DMA2_Stream3_IRQHandler
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
.weak DMA2_Stream4_IRQHandler
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
.weak ETH_IRQHandler
.thumb_set ETH_IRQHandler,Default_Handler
.weak ETH_WKUP_IRQHandler
.thumb_set ETH_WKUP_IRQHandler,Default_Handler
.weak CAN2_TX_IRQHandler
.thumb_set CAN2_TX_IRQHandler,Default_Handler
.weak CAN2_RX0_IRQHandler
.thumb_set CAN2_RX0_IRQHandler,Default_Handler
.weak CAN2_RX1_IRQHandler
.thumb_set CAN2_RX1_IRQHandler,Default_Handler
.weak CAN2_SCE_IRQHandler
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
.weak OTG_FS_IRQHandler
.thumb_set OTG_FS_IRQHandler,Default_Handler
.weak DMA2_Stream5_IRQHandler
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
.weak DMA2_Stream6_IRQHandler
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
.weak DMA2_Stream7_IRQHandler
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
.weak USART6_IRQHandler
.thumb_set USART6_IRQHandler,Default_Handler
.weak I2C3_EV_IRQHandler
.thumb_set I2C3_EV_IRQHandler,Default_Handler
.weak I2C3_ER_IRQHandler
.thumb_set I2C3_ER_IRQHandler,Default_Handler
.weak OTG_HS_EP1_OUT_IRQHandler
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
.weak OTG_HS_EP1_IN_IRQHandler
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
.weak OTG_HS_WKUP_IRQHandler
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
.weak OTG_HS_IRQHandler
.thumb_set OTG_HS_IRQHandler,Default_Handler
.weak DCMI_IRQHandler
.thumb_set DCMI_IRQHandler,Default_Handler
.weak CRYP_IRQHandler
.thumb_set CRYP_IRQHandler,Default_Handler
.weak HASH_RNG_IRQHandler
.thumb_set HASH_RNG_IRQHandler,Default_Handler
.weak FPU_IRQHandler
.thumb_set FPU_IRQHandler,Default_Handler
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
+235
View File
@@ -0,0 +1,235 @@
/*------------------------------------------------------
FILE........: tst_api_demod.c
AUTHOR......: David Rowe, Don Reid
DATE CREATED: 7 July 2018
Test and profile OFDM de-modulation on the STM32F4.
-------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* Typical run, using internal testframes:
# Input
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw
freedv_tx 700D spch_in.raw stm_in.raw --testframes
# Reference
freedv_rx 700D stm_in.raw ref_demod.raw --testframes
# Create config
echo "71000010" > stm_cfg.txt
# Run stm32
run_stm32_prog ../../src/tst_api_demod.elf --load
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>
#include "freedv_api.h"
#include "modem_stats.h"
#include "codec2.h"
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
#include "memtools.h"
struct my_callback_state {
//FILE *ftxt;
};
void my_put_next_rx_char(void *callback_state, char c) {
//fprintf(stdout, "text msg: %c\n", c);
}
void my_put_next_rx_proto(void *callback_state,char *proto_bits){
//fprintf(stdout, "proto chars: %.*s\n",2, proto_bits);
}
/* Called when a packet has been received */
void my_datarx(void *callback_state, unsigned char *packet, size_t size) {
//size_t i;
//
//fprintf(stdout, "data (%zd bytes): ", size);
//for (i = 0; i < size; i++) {
// fprintf(stdout, "0x%02x ", packet[i]);
//}
//fprintf(stdout, "\n");
}
/* Called when a new packet can be send */
void my_datatx(void *callback_state, unsigned char *packet, size_t *size) {
/* This should not happen while receiving.. */
fprintf(stderr, "datarx callback called, this should not happen!\n");
*size = 0;
}
#define SPARE_RAM 3000
int main(int argc, char *argv[]) {
char dummy[SPARE_RAM];
int f_cfg, f_in, f_out;
struct freedv *freedv;
struct my_callback_state my_cb_state;
int frame;
int nread, nin, nout;
int sync;
float snr_est;
// Force test to fail unless we have this much spare RAM (adjusted by experiment)
memset(dummy, 0, SPARE_RAM);
semihosting_init();
PROFILE_VAR(freedv_rx_start);
machdep_profile_init();
////////
// Test configuration, read from stm_cfg.txt
int config_mode; // 0
int config_testframes; // 1
int config_verbose; // 6
//int config_profile; // 7
char config[8];
f_cfg = open("stm_cfg.txt", O_RDONLY);
if (f_cfg == -1) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (read(f_cfg, &config[0], 8) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_mode = config[0] - '0';
if (config_mode == 8)
{
// For the purposes of the UT system, '8' is 700E.
config_mode = FREEDV_MODE_700E;
}
config_testframes = config[1] - '0';
config_verbose = config[6] - '0';
//config_profile = config[7] - '0';
close(f_cfg);
printf("config_mode: %d config_verbose: %d\n", config_mode, config_verbose);
////////
freedv = freedv_open(config_mode);
assert(freedv != NULL);
memtools_find_unused(printf);
freedv_set_test_frames(freedv, config_testframes);
freedv_set_verbose(freedv, config_verbose);
freedv_set_snr_squelch_thresh(freedv, -100.0);
freedv_set_squelch_en(freedv, 0);
short speech_out[freedv_get_n_speech_samples(freedv)];
short demod_in[freedv_get_n_max_modem_samples(freedv)];
freedv_set_callback_txt(freedv, &my_put_next_rx_char, NULL, &my_cb_state);
freedv_set_callback_protocol(freedv, &my_put_next_rx_proto, NULL, &my_cb_state);
freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state);
////////
// Streams
f_in = open("stm_in.raw", O_RDONLY);
if (f_in == -1) {
perror("Error opening input file\n");
exit(1);
}
f_out = open("stm_out.raw", (O_CREAT | O_WRONLY), 0644);
if (f_out == -1) {
perror("Error opening output file\n");
exit(1);
}
frame = 0;
////////
// Main loop
nin = freedv_nin(freedv);
while((nread = read(f_in, demod_in, (sizeof(short) * nin))) == (nin * sizeof(short))) {
fprintf(stderr, "frame: %d, %d bytes read\n", frame, nread);
PROFILE_SAMPLE(freedv_rx_start);
nout = freedv_rx(freedv, speech_out, demod_in);
PROFILE_SAMPLE_AND_LOG2(freedv_rx_start, " freedv_rx");
machdep_profile_print_logged_samples();
fprintf(stderr, " %d short speech values returned\n", nout);
if (nout) write(f_out, speech_out, (sizeof(short) * nout));
if (sync == 0) {
// discard BER results if we get out of sync, helps us get sensible BER results
freedv_set_total_bits(freedv, 0); freedv_set_total_bit_errors(freedv, 0);
freedv_set_total_bits_coded(freedv, 0); freedv_set_total_bit_errors_coded(freedv, 0);
}
freedv_get_modem_stats(freedv, &sync, &snr_est);
int total_bit_errors = freedv_get_total_bit_errors(freedv);
fprintf(stderr,
"frame: %d demod sync: %d nin: %d demod snr: %3.2f dB bit errors: %d\n",
frame, sync, nin, (double)snr_est, total_bit_errors);
frame++;
nin = freedv_nin(freedv);
}
//////
if (freedv_get_test_frames(freedv)) {
int Tbits = freedv_get_total_bits(freedv);
int Terrs = freedv_get_total_bit_errors(freedv);
fprintf(stderr, "BER......: %5.4f Tbits: %5d Terrs: %5d\n",
(double)Terrs/Tbits, Tbits, Terrs);
if (config_mode == FREEDV_MODE_700D || config_mode == FREEDV_MODE_700E) {
int Tbits_coded = freedv_get_total_bits_coded(freedv);
int Terrs_coded = freedv_get_total_bit_errors_coded(freedv);
fprintf(stderr, "Coded BER: %5.4f Tbits: %5d Terrs: %5d\n",
(double)Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded);
}
}
printf("Done\n");
close(f_in);
close(f_out);
memtools_find_unused(printf);
printf("\nEnd of Test\n");
}
/* vi:set ts=4 et sts=4: */
@@ -0,0 +1,136 @@
/*------------------------------------------------------
FILE........: tst_api_demod.c
AUTHOR......: David Rowe, Don Reid
DATE CREATED: 7 July 2018
Test and profile OFDM de-modulation on the STM32F4.
-------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>
#include "freedv_api.h"
#include "modem_stats.h"
#include "codec2.h"
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
/* Input and Reference data */
const
#include "api_demod_700d_in_10f.c"
struct my_callback_state {
//FILE *ftxt;
};
void my_put_next_rx_char(void *callback_state, char c) {
//fprintf(stdout, "text msg: %c\n", c);
}
void my_put_next_rx_proto(void *callback_state,char *proto_bits){
//fprintf(stdout, "proto chars: %.*s\n",2, proto_bits);
}
/* Called when a packet has been received */
void my_datarx(void *callback_state, unsigned char *packet, size_t size) {
//size_t i;
//
//fprintf(stdout, "data (%zd bytes): ", size);
//for (i = 0; i < size; i++) {
// fprintf(stdout, "0x%02x ", packet[i]);
//}
//fprintf(stdout, "\n");
}
/* Called when a new packet can be send */
void my_datatx(void *callback_state, unsigned char *packet, size_t *size) {
/* This should not happen while receiving.. */
fprintf(stderr, "datarx callback called, this should not happen!\n");
*size = 0;
}
int main(int argc, char *argv[]) {
struct freedv *freedv;
struct my_callback_state my_cb_state;
int frame;
int nin, nout;
////////
PROFILE_VAR(prof_freedv_rx);
machdep_profile_init();
semihosting_init();
////////
freedv = freedv_open(FREEDV_MODE_700D);
freedv_set_snr_squelch_thresh(freedv, -100.0);
freedv_set_squelch_en(freedv, 0);
short speech_out[freedv_get_n_speech_samples(freedv)];
freedv_set_callback_txt(freedv, &my_put_next_rx_char, NULL, &my_cb_state);
freedv_set_callback_protocol(freedv, &my_put_next_rx_proto, NULL, &my_cb_state);
freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state);
frame = 0;
////////
// Main loop
nin = freedv_nin(freedv);
int in_ptr = 0;
while(in_ptr < api_demod_700d_in_10f_len) {
PROFILE_SAMPLE(prof_freedv_rx);
nout = freedv_shortrx(freedv, speech_out, (short *)&api_demod_700d_in_10f[in_ptr], 1.0f);
PROFILE_SAMPLE_AND_LOG2(prof_freedv_rx, "freedv_rx");
//if (nout) write(f_out, speech_out, (sizeof(short) * nout));
frame++;
in_ptr += nin * 2;
}
machdep_profile_print_logged_samples();
fclose(stdout);
fclose(stderr);
}
/* vi:set ts=4 et sts=4: */
+274
View File
@@ -0,0 +1,274 @@
/*---------------------------------------------------------------------------*\
FILE........: tst_api_mod.c
AUTHOR......: David Rowe, Don Reid
DATE CREATED: August 2014, Oct 2018
Test modem modulation via freedv API on the STM32F4.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* Typical run, using internal testframes:
# Copy N frames of a raw audio file to stm_in.raw.
# N=6, count = 6 * 1280 * 2 = 15360
dd bs=1 count=15360 if=../../../../raw/hts1.raw of=stm_in.raw
# Reference
freedv_tx 700D stm_in.raw ref_mod.raw --testframes
# Create config
echo "71000000" > stm_cfg.txt
# Run stm32
run_stm32_prog ../../src/tst_api_mod.elf --load
# Check output
freedv_rx 700D ref_mod.raw ref_rx.raw --testframes
freedv_rx 700D stm_out.raw stm_rx.raw --testframes
#optional: ofdm_demod ref_mod.raw ref_demod.raw --ldpc --testframes
#optional: ofdm_demod stm_out.raw stm_demod.raw --ldpc --testframes
compare_ints -s -b 2 ref_mod.raw stm_out.raw
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>
#include "freedv_api.h"
#include "codec2.h"
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
#include "memtools.h"
struct my_callback_state {
char tx_str[80];
char *ptx_str;
int calls;
};
char my_get_next_tx_char(void *callback_state) {
struct my_callback_state* pstate = (struct my_callback_state*)callback_state;
char c = *pstate->ptx_str++;
//fprintf(stderr, "my_get_next_tx_char: %c\n", c);
if (*pstate->ptx_str == 0) {
pstate->ptx_str = pstate->tx_str;
}
return c;
}
void my_get_next_proto(void *callback_state,char *proto_bits){
struct my_callback_state* cb_states = (struct my_callback_state*)(callback_state);
snprintf(proto_bits,3,"%2d",cb_states->calls);
cb_states->calls = cb_states->calls + 1;
}
/* Called when a packet has been received */
void my_datarx(void *callback_state, unsigned char *packet, size_t size) {
/* This should not happen while sending... */
fprintf(stderr, "datarx callback called, this should not happen!\n");
}
/* Called when a new packet can be send */
void my_datatx(void *callback_state, unsigned char *packet, size_t *size) {
static int data_toggle;
/* Data could come from a network interface, here we just make up some */
data_toggle = !data_toggle;
if (data_toggle) {
/* Send a packet with data */
int i;
for (i = 0; i < 64; i++)
packet[i] = i;
*size = i;
} else {
/* set size to zero, the freedv api will insert a header frame */
*size = 0;
}
}
int main(int argc, char *argv[]) {
struct freedv *freedv;
int f_cfg, f_in, f_out;
int frame;
int num_read;
//struct CODEC2 *c2;
struct my_callback_state my_cb_state;
semihosting_init();
memtools_find_unused(printf);
////////
// Test configuration, read from stm_cfg.txt
int config_mode; // 0
int config_testframes; // 1
int use_clip = 0; // 2
int use_txbpf = 0; // 3
//int config_verbose; // 6
//int config_profile; // 7
char config[8];
f_cfg = open("stm_cfg.txt", O_RDONLY);
if (f_cfg == -1) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (read(f_cfg, &config[0], 8) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_mode = config[0] - '0';
if (config_mode == 8)
{
// For the purposes of the UT system, '8' is 700E.
config_mode = FREEDV_MODE_700E;
}
config_testframes = config[1] - '0';
use_clip = config[2] - '0';
use_txbpf = config[3] - '0';
//config_verbose = config[6] - '0';
//config_profile = config[7] - '0';
close(f_cfg);
//int use_codectx = 0;
//int use_datatx = 0;
//int use_testframes = 0;
int use_ext_vco = 0;
////////
//PROFILE_VAR(freedv_start);
//machdep_profile_init();
////////
freedv = freedv_open(config_mode);
assert(freedv != NULL);
fprintf(stderr, "freedv opened %p\n", freedv);
freedv_set_test_frames(freedv, config_testframes);
int n_speech_samples = freedv_get_n_speech_samples(freedv);
short *speech_in = (short*)malloc(sizeof(short)*n_speech_samples);
int n_nom_modem_samples = freedv_get_n_nom_modem_samples(freedv);
short *mod_out = (short*)malloc(sizeof(short)*n_nom_modem_samples);
fprintf(stderr, "n_speech_samples: %d n_nom_modem_samples: %d\n",
n_speech_samples, n_nom_modem_samples);
fprintf(stderr, "mod_out: %p\n", mod_out);
/*
// This is "codectx" operation:
int c2_mode;
if (config_mode == FREEDV_MODE_700) {
c2_mode = CODEC2_MODE_700;
} else if ((config_mode == FREEDV_MODE_700B) ||
(config_mode == FREEDV_MODE_800XA)) {
c2_mode = CODEC2_MODE_700B;
} else if ((config_mode == FREEDV_MODE_700C) ||
(config_mode == FREEDV_MODE_700D)) {
c2_mode = CODEC2_MODE_700C;
} else {
c2_mode = CODEC2_MODE_1300;
}
c2 = codec2_create(c2_mode);
int bits_per_codec_frame = codec2_bits_per_frame(c2);
int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
int codec_frames = freedv_get_n_codec_bits(freedv) / bits_per_codec_frame;
int inbuf_size = bytes_per_codec_frame * codec_frames;
unsigned char inbuf[inbuf_size];
*/
freedv_set_snr_squelch_thresh(freedv, -100.0);
freedv_set_squelch_en(freedv, 1);
freedv_set_clip(freedv, use_clip);
freedv_set_tx_bpf(freedv, use_txbpf);
freedv_set_ext_vco(freedv, use_ext_vco);
freedv_set_eq(freedv, 1);
memtools_find_unused(printf);
// set up callback for txt msg chars
sprintf(my_cb_state.tx_str, "cq cq cq hello world\r");
my_cb_state.ptx_str = my_cb_state.tx_str;
my_cb_state.calls = 0;
freedv_set_callback_txt(freedv, NULL, &my_get_next_tx_char, &my_cb_state);
// set up callback for protocol bits
freedv_set_callback_protocol(freedv, NULL, &my_get_next_proto, &my_cb_state);
// set up callback for data packets
freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state);
////////
// Streams
f_in = open("stm_in.raw", O_RDONLY);
if (f_in == -1) {
perror("Error opening input file\n");
exit(1);
}
f_out = open("stm_out.raw", (O_CREAT | O_WRONLY), 0644);
if (f_out == -1) {
perror("Error opening output file\n");
exit(1);
}
frame = 0;
fprintf(stderr, "starting main loop\n");
////////
// Main loop
while ((num_read = read(f_in, speech_in, (sizeof(short) * n_speech_samples))) ==
(sizeof(short) * n_speech_samples)) {
fprintf(stderr, "frame: %d\r", frame);
freedv_tx(freedv, mod_out, speech_in);
write(f_out, mod_out, (sizeof(short) * n_nom_modem_samples));
frame++ ;
//machdep_profile_print_logged_samples();
}
printf("Done\n");
close(f_in);
close(f_out);
printf("\nEnd of Test\n");
return(0);
}
/* vi:set ts=4 et sts=4: */
@@ -0,0 +1,167 @@
/*---------------------------------------------------------------------------*\
FILE........: tst_api_mod.c
AUTHOR......: David Rowe, Don Reid
DATE CREATED: August 2014, Oct 2018
Test modem modulation via freedv API on the STM32F4.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This is a test implementation of the Freev API Modulation function.
* It is used for profiling performance.
*
* The input is generated within the test.
* The output is ignored.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <math.h>
#include <assert.h>
#include "freedv_api.h"
#include "codec2.h"
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
struct my_callback_state {
char tx_str[80];
char *ptx_str;
int calls;
};
char my_get_next_tx_char(void *callback_state) {
struct my_callback_state* pstate = (struct my_callback_state*)callback_state;
char c = *pstate->ptx_str++;
if (*pstate->ptx_str == 0) {
pstate->ptx_str = pstate->tx_str;
}
return c;
}
void my_get_next_proto(void *callback_state,char *proto_bits){
struct my_callback_state* cb_states = (struct my_callback_state*)(callback_state);
snprintf(proto_bits,3,"%2d",cb_states->calls);
cb_states->calls = cb_states->calls + 1;
}
/* Called when a packet has been received */
void my_datarx(void *callback_state, unsigned char *packet, size_t size) {
/* This should not happen while sending... */
assert(0);
}
/* Called when a new packet can be send */
void my_datatx(void *callback_state, unsigned char *packet, size_t *size) {
static int data_toggle;
/* Data could come from a network interface, here we just make up some */
data_toggle = !data_toggle;
if (data_toggle) {
/* Send a packet with data */
int i;
for (i = 0; i < 64; i++)
packet[i] = i;
*size = i;
} else {
/* set size to zero, the freedv api will insert a header frame */
*size = 0;
}
}
int main(int argc, char *argv[]) {
struct freedv *freedv;
int i;
struct my_callback_state my_cb_state;
int use_clip = 0;
int use_txbpf = 0;
int use_ext_vco = 0;
////////
PROFILE_VAR(prof_freedv_tx);
machdep_profile_init();
semihosting_init();
////////
freedv = freedv_open(FREEDV_MODE_700D);
int n_speech_samples = freedv_get_n_speech_samples(freedv);
short *speech_in = (short*)malloc(sizeof(short)*n_speech_samples);
int n_nom_modem_samples = freedv_get_n_nom_modem_samples(freedv);
short *mod_out = (short*)malloc(sizeof(short)*n_nom_modem_samples);
freedv_set_snr_squelch_thresh(freedv, -100.0);
freedv_set_squelch_en(freedv, 1);
freedv_set_clip(freedv, use_clip);
freedv_set_tx_bpf(freedv, use_txbpf);
freedv_set_ext_vco(freedv, use_ext_vco);
// set up callback for txt msg chars
sprintf(my_cb_state.tx_str, "cq cq cq hello world\r");
my_cb_state.ptx_str = my_cb_state.tx_str;
my_cb_state.calls = 0;
freedv_set_callback_txt(freedv, NULL, &my_get_next_tx_char, &my_cb_state);
// set up callback for protocol bits
freedv_set_callback_protocol(freedv, NULL, &my_get_next_proto, &my_cb_state);
// set up callback for data packets
freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state);
int frame = 0;
for (i=0; i<n_speech_samples; i++) speech_in[i] = 0;
////////
// Main loop
while(frame < 10) {
PROFILE_SAMPLE(prof_freedv_tx);
freedv_tx(freedv, mod_out, speech_in);
PROFILE_SAMPLE_AND_LOG2(prof_freedv_tx, "freedv_tx");
//write(f_out, mod_out, (sizeof(short) * n_nom_modem_samples));
frame++ ;
}
machdep_profile_print_logged_samples();
fclose(stdout);
fclose(stderr);
return(0);
}
/* vi:set ts=4 et sts=4: */
+94
View File
@@ -0,0 +1,94 @@
/*---------------------------------------------------------------------------*\
FILE........: freedv_tx_profile.c
AUTHOR......: David Rowe
DATE CREATED: 13 August 2014
Profiling freedv_tx() operation on the STM32F4.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <errno.h>
#include "semihosting.h"
#include "codec2_ofdm.h"
#include "ofdm_internal.h"
#include "interldpc.h"
#include "gp_interleaver.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "freedv_api.h"
#include "machdep.h"
int main(int argc, char *argv[]) {
struct freedv *f;
FILE *fin, *fout;
int frame, n_samples;
semihosting_init();
//PROFILE_VAR(freedv_start);
//machdep_profile_init();
f = freedv_open(FREEDV_MODE_1600);
n_samples = freedv_get_n_speech_samples(f);
short inbuf[n_samples], outbuf[n_samples];
freedv_set_test_frames(f, 1);
// Transmit ---------------------------------------------------------------------
fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
printf("Error opening input file\n");
exit(1);
}
fout = fopen("mod.raw", "wb");
if (fout == NULL) {
printf("Error opening output file\n");
exit(1);
}
frame = 0;
while (fread(inbuf, sizeof(short), n_samples, fin) == n_samples) {
//PROFILE_SAMPLE(freedv_start);
freedv_tx(f, outbuf, inbuf);
//PROFILE_SAMPLE_AND_LOG2(freedv_start, " freedv_tx");
fwrite(outbuf, sizeof(short), n_samples, fout);
printf("frame: %d\n", ++frame);
//machdep_profile_print_logged_samples();
}
fclose(fin);
fclose(fout);
return 0;
}
/* vi:set ts=4 et sts=4: */
+164
View File
@@ -0,0 +1,164 @@
/*------------------------------------------------------
FILE........: tst_codec2_dec.c
AUTHOR......: David Rowe, Don Reid
DATE CREATED: 30 May 2013, Oct 2018
Test Codec 2 decoding on the STM32F4.
-------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* Typical run, using internal testframes:
# Input
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=2560 count=30 if=../../../../raw/hts1.raw of=spch_in.raw
c2enc 700C spch_in.raw stm_in.raw
# Reference
c2dec 700C stm_in.raw ref_dec.raw
# Create config
echo "81000000" > stm_cfg.txt
# Run stm32
run_stm32_prog ../../src/tst_codec2_dec.elf --load
# Compare outputs
compare_ints -s -b 2 ref_dec.raw stm_out.raw
# Manual play (and listen)
aplay -f S16_LE ref_dec.raw
#
aplay -f S16_LE stm_out.raw
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <errno.h>
#include <assert.h>
#include "codec2.h"
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
static char fin_buffer[1024];
static __attribute__ ((section (".ccm"))) char fout_buffer[4*8192];
int main(int argc, char *argv[]) {
int f_cfg;
int frame;
void *codec2;
short *buf;
unsigned char *bits;
int nsam, nbit, nbyte;
semihosting_init();
////////
// Test configuration, read from stm_cfg.txt
int config_mode; // 0
int config_gray; // 1
//int config_verbose; // 6
//int config_profile; // 7
char config[8];
f_cfg = open("stm_cfg.txt", O_RDONLY);
if (f_cfg == -1) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (read(f_cfg, &config[0], 8) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_mode = config[0] - '0';
config_gray = config[1] - '0';
//config_verbose = config[6] - '0';
//config_profile = config[7] - '0';
close(f_cfg);
////////
// Setup
codec2 = codec2_create(config_mode);
assert(codec2 != NULL);
codec2_set_natural_or_gray(codec2, config_gray);
nsam = codec2_samples_per_frame(codec2);
nbit = codec2_bits_per_frame(codec2);
buf = (short*)malloc(nsam*sizeof(short));
nbyte = (nbit + 7) / 8;
bits = (unsigned char*)malloc(nbyte*sizeof(char));
////////
// Streams
FILE* fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
perror("Error opening input file\n");
exit(1);
}
setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer));
FILE *fout = fopen("stm_out.raw", "wb" );
if (fout == NULL) {
perror("Error opening output file\n");
exit(1);
}
setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer));
frame = 0;
////////
// Main loop
int bytes_per_frame = (sizeof(char) * nbyte);
while (fread(bits, 1, bytes_per_frame, fin) == (size_t)bytes_per_frame) {
codec2_decode_ber(codec2, buf, bits, 0.0);
fwrite(buf, sizeof(short) , nsam, fout);
frame ++;
}
fclose(fin);
fclose(fout);
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
}
/* vi:set ts=4 et sts=4: */
+172
View File
@@ -0,0 +1,172 @@
/*---------------------------------------------------------------------------*\
FILE........: tst_codec2_enc.c, (derived from codec2_profile.c)
AUTHOR......: David Rowe, Don Reid
DATE CREATED: 30 May 2013, Oct 2018
Test Codec 2 encoding on the STM32F4.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This is a unit test implementation of the Codec2_encode function.
*
* Typical run:
# Copy N frames of a raw audio file to stm_in.raw.
dd bs=2560 count=30 if=../../../../raw/hts1.raw of=stm_in.raw
# Run x86 command for reference output
c2enc 700C stm_in.raw ref_enc.raw
# Create config
echo "80000000" > stm_cfg.txt
# Run stm32
run_stm32_prog ../../src/tst_codec2_enc.elf --load
# Compare outputs
comare_ints -b 1 ref_enc.raw stm_out.raw
# Manual play (and listen)
c2dec 700C ref_enc.raw ref_dec.raw
aplay -f S16_LE ref_out.raw
#
c2dec 700C stm_out.raw stm_dec.raw
aplay -f S16_LE stm_dec.raw
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include "codec2.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "semihosting.h"
#include "machdep.h"
static __attribute__ ((section (".ccm"))) char fin_buffer[8*8192];
char fout_buffer[1024];
int main(int argc, char *argv[]) {
int f_cfg;
struct CODEC2 *codec2;
short *buf;
unsigned char *bits;
int nsam, nbit, nbyte;
int gray;
int frame;
////////
// Semihosting
semihosting_init();
////////
// Test configuration, read from stm_cfg.txt
int config_mode; // 0
//int config_verbose; // 6
//int config_profile; // 7
char config[8];
f_cfg = open("stm_cfg.txt", O_RDONLY);
if (f_cfg == -1) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (read(f_cfg, &config[0], 8) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_mode = config[0] - '0';
//config_verbose = config[6] - '0';
//config_profile = config[7] - '0';
close(f_cfg);
////////
//PROFILE_VAR(freedv_start);
//machdep_profile_init();
////////
codec2 = codec2_create(config_mode);
nsam = codec2_samples_per_frame(codec2);
nbit = codec2_bits_per_frame(codec2);
buf = (short*)malloc(nsam*sizeof(short));
nbyte = (nbit + 7) / 8;
bits = (unsigned char*)malloc(nbyte*sizeof(char));
gray = 1;
//softdec = 0;
//bitperchar = 0;
codec2_set_natural_or_gray(codec2, gray);
////////
// Streams
FILE* fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
perror("Error opening input file\n");
exit(1);
}
setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer));
FILE* fout = fopen("stm_out.raw", "wb");
if (fout == NULL) {
perror("Error opening output file\n");
exit(1);
}
frame = 0;
int bytes_per_frame = (sizeof(short) * nsam);
while (fread(buf,1, bytes_per_frame, fin) == bytes_per_frame) {
//PROFILE_SAMPLE(enc_start);
codec2_encode(codec2, bits, buf);
//PROFILE_SAMPLE_AND_LOG2(, enc_start, " enc");
fwrite(bits, 1, (sizeof(char) * nbyte), fout);
printf("frame: %d\n", ++frame);
//machdep_profile_print_logged_samples();
}
codec2_destroy(codec2);
free(buf);
free(bits);
fclose(fin);
fclose(fout);
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
return(0);
}
/* vi:set ts=4 et sts=4: */
@@ -0,0 +1,104 @@
/*---------------------------------------------------------------------------*\
FILE........: tst_codec2_fft_init.c,
AUTHOR......: David Rowe, Don Reid
DATE CREATED: 30 May 2013, Oct 2018, Feb 2018
Test FFT Window initialization in Codec2_create
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "codec2.h"
#include "codec2_internal.h"
#include "defines.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "semihosting.h"
#include "machdep.h"
static const float expect_w[] = {
0.004293, 0.004301, 0.004309, 0.004315,
0.004320, 0.004323, 0.004326, 0.004328,
0.004328, 0.004328, 0.004326, 0.004323,
0.004320, 0.004315, 0.004309, 0.004301};
static const float expect_W[] = {
-0.002176, 0.002195, 0.004429, -0.008645,
-0.012196, 0.065359, 0.262390, 0.495616,
0.601647, 0.495616, 0.262390, 0.065359,
-0.012196, -0.008645, 0.004429, 0.002195};
int float_cmp(float a, float b) {
if ( fabsf(a - b) < 1e-6f ) return 1;
else return 0;
}
int main(int argc, char *argv[]) {
struct CODEC2 *codec2;
int i, j;
////////
// Semihosting
semihosting_init();
////////
codec2 = codec2_create(CODEC2_MODE_700C);
j = (codec2->c2const.m_pitch / 2) - 8;
for (i=0; i<16; i++) {
printf("w[%d] = %f", j+i,
(double)codec2->w[j+i]);
if (!float_cmp(codec2->w[j+i], expect_w[i])) {
printf(" Error, expected %f", (double)expect_w[i]);
}
printf("\n");
}
printf("\n");
j = (FFT_ENC / 2) - 8;
for (i=0; i<16; i++) {
printf("W[%d] = %f", j+i,
(double)codec2->W[j+i]);
if (!float_cmp(codec2->W[j+i], expect_W[i])) {
printf(" Error, expected %f", (double)expect_W[i]);
}
printf("\n");
}
codec2_destroy(codec2);
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
return(0);
}
/* vi:set ts=4 et sts=4: */
+204
View File
@@ -0,0 +1,204 @@
/*
FILE...: ldpc_dec.c
AUTHOR.: Matthew C. Valenti, Rohit Iyer Seshadri, David Rowe, Don Reid
CREATED: Sep 2016
Command line C LDPC decoder derived from MpDecode.c in the CML
library. Allows us to run the same decoder in Octave and C. The
code is defined by the parameters and array stored in the include
file below, which can be machine generated from the Octave function
ldpc_fsk_lib.m:ldpc_decode()
The include file also contains test input/output vectors for the LDPC
decoder for testing this program. If no input file "stm_in.raw" is found
then the built in test mode will run.
If there is an input is should be encoded data from the x86 ldpc_enc
program. Here is the suggested way to run:
ldpc_enc /dev/zero stm_in.raw --sd --code HRA_112_112 --testframes 6
ldpc_dec stm_in.raw ref_out.raw --sd --code HRA_112_112 --testframes
<Load stm32 and run>
cmp -l ref_out.raw stm_out.raw
<< Check BER values in logs >>
*/
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "mpdecode_core.h"
#include "ofdm_internal.h"
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
/* generated by ldpc_fsk_lib.m:ldpc_decode() */
/* Machine generated consts, H_rows, H_cols, test input/output data to
change LDPC code regenerate this file. */
#include "HRA_112_112.h"
int testframes = 1;
static char fin_buffer[1024];
static __attribute__ ((section (".ccm"))) char fout_buffer[8*8192];
int main(int argc, char *argv[]) {
int CodeLength, NumberParityBits;
int i, parityCheckCount;
uint8_t out_data[HRA_112_112_CODELENGTH];
struct LDPC ldpc;
int data_bits_per_frame;
FILE *fout;
int iter, total_iters;
int Tbits, Terrs, Tbits_raw, Terrs_raw;
int nread, frame;
semihosting_init();
fprintf(stderr, "LDPC decode test and profile\n");
PROFILE_VAR(ldpc_decode);
machdep_profile_init();
ldpc.max_iter = HRA_112_112_MAX_ITER;
ldpc.dec_type = 0;
ldpc.q_scale_factor = 1;
ldpc.r_scale_factor = 1;
ldpc.CodeLength = HRA_112_112_CODELENGTH;
ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS;
ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS;
ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT;
ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT;
ldpc.H_rows = (uint16_t *)HRA_112_112_H_rows;
ldpc.H_cols = (uint16_t *)HRA_112_112_H_cols;
CodeLength = ldpc.CodeLength;
NumberParityBits = ldpc.NumberParityBits;
data_bits_per_frame = ldpc.NumberRowsHcols;
unsigned char ibits[data_bits_per_frame];
unsigned char pbits[NumberParityBits];
// // Allocate common space which can be shared with other functions.
// int size_common;
// uint8_t *common_array;
// ldpc_init(&ldpc, &size_common);
// fprintf(stderr, "ldpc needs %d bytes of shared memory\n", size_common);
// common_array = malloc(size_common);
testframes = 1;
total_iters = 0;
if (testframes) {
uint16_t r[data_bits_per_frame];
ofdm_rand(r, data_bits_per_frame);
for(i=0; i<data_bits_per_frame; i++) {
ibits[i] = r[i] > 16384;
}
encode(&ldpc, ibits, pbits);
Tbits = Terrs = Tbits_raw = Terrs_raw = 0;
}
FILE* fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
fprintf(stderr, "Error opening input file\n");
fflush(stderr);
exit(1);
}
setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer));
fout = fopen("stm_out.raw", "wb");
if (fout == NULL) {
fprintf(stderr, "Error opening output file\n");
fflush(stderr);
exit(1);
}
setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer));
float *input_float = calloc(CodeLength, sizeof(float));
nread = CodeLength;
fprintf(stderr, "CodeLength: %d\n", CodeLength);
frame = 0;
while(fread(input_float, sizeof(float) , nread, fin) == nread) {
fprintf(stderr, "frame %d\n", frame);
if (testframes) {
char in_char;
for (i=0; i<data_bits_per_frame; i++) {
in_char = input_float[i] < 0;
if (in_char != ibits[i]) {
Terrs_raw++;
}
Tbits_raw++;
}
for (i=0; i<NumberParityBits; i++) {
in_char = input_float[i+data_bits_per_frame] < 0;
if (in_char != pbits[i]) {
Terrs_raw++;
}
Tbits_raw++;
}
}
float llr[CodeLength];
sd_to_llr(llr, input_float, CodeLength);
PROFILE_SAMPLE(ldpc_decode);
iter = run_ldpc_decoder(&ldpc, out_data, llr, &parityCheckCount);
PROFILE_SAMPLE_AND_LOG2(ldpc_decode, "ldpc_decode");
//fprintf(stderr, "iter: %d\n", iter);
total_iters += iter;
fwrite(out_data, sizeof(char), data_bits_per_frame, fout);
if (testframes) {
for (i=0; i<data_bits_per_frame; i++) {
if (out_data[i] != ibits[i]) {
Terrs++;
//fprintf(stderr, "%d %d %d\n", i, out_data[i], ibits[i]);
}
Tbits++;
}
}
frame++;
}
fclose(fin);
fclose(fout);
fprintf(stderr, "total iters %d\n", total_iters);
if (testframes) {
fprintf(stderr, "Raw Tbits..: %d Terr: %d BER: %4.3f\n",
Tbits_raw, Terrs_raw, (double)(Terrs_raw/(Tbits_raw+1E-12)));
fprintf(stderr, "Coded Tbits: %d Terr: %d BER: %4.3f\n",
Tbits, Terrs, (double)(Terrs/(Tbits+1E-12)));
}
printf("\nStart Profile Data\n");
machdep_profile_print_logged_samples();
printf("End Profile Data\n");
fclose(stdout);
fclose(stderr);
return 0;
}
/* vi:set ts=4 et sts=4: */
+114
View File
@@ -0,0 +1,114 @@
/*
FILE...: ldpc_enc.c
AUTHOR.: Bill Cowley, David Rowe
CREATED: Sep 2016
STM32 Version: Aug 2018 - Don Reid
*/
/* This is a unit test implementation of the LDPC encode function.
*
* Typical run:
ofdm_gen_test_bits stm_in.raw 6 --rand --ldpc
ldpc_enc stm_in.raw ref_out.raw --code HRA_112_112
<Load stm32 and run>
cmp -l ref_out.raw stm_out.raw
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "mpdecode_core.h"
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
/* generated by ldpc_fsk_lib.m:ldpc_decode() */
#include "HRA_112_112.h"
static __attribute__ ((section (".ccm"))) char fin_buffer[8*8192];
char fout_buffer[1024];
int opt_exists(char *argv[], int argc, char opt[]) {
int i;
for (i=0; i<argc; i++) {
if (strcmp(argv[i], opt) == 0) {
return i;
}
}
return 0;
}
int main(int argc, char *argv[])
{
unsigned char ibits[HRA_112_112_NUMBERROWSHCOLS];
unsigned char pbits[HRA_112_112_NUMBERPARITYBITS];
struct LDPC ldpc;
semihosting_init();
printf("LDPC encode test and profile\n");
PROFILE_VAR(ldpc_encode);
machdep_profile_init();
/* set up LDPC code from include file constants */
/* short rate 1/2 code for FreeDV HF digital voice */
ldpc.CodeLength = HRA_112_112_CODELENGTH;
ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS;
ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS;
ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT;
ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT;
ldpc.H_rows = (uint16_t *)HRA_112_112_H_rows;
ldpc.H_cols = (uint16_t *)HRA_112_112_H_cols;
FILE* fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
printf("Error opening input file\n");
exit(1);
}
setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer));
FILE* fout = fopen("stm_out.raw", "wb");
if (fout == NULL) {
printf("Error opening output file\n");
exit(1);
}
while (fread(ibits, sizeof(char) , ldpc.NumberParityBits, fin) ==
ldpc.NumberParityBits) {
PROFILE_SAMPLE(ldpc_encode);
encode(&ldpc, ibits, pbits);
PROFILE_SAMPLE_AND_LOG2(ldpc_encode, " ldpc_encode");
fwrite(ibits, sizeof(char) , ldpc.NumberRowsHcols, fout);
fwrite(pbits, sizeof(char) , ldpc.NumberParityBits, fout);
}
fclose(fin);
fclose(fout);
fflush(stdout);
stdout = freopen("stm_profile", "w", stdout);
machdep_profile_print_logged_samples();
fclose(stdout);
fclose(stderr);
return 0;
}
+438
View File
@@ -0,0 +1,438 @@
/*---------------------------------------------------------------------------*\
FILE........: tst_ofdm_demod.c
AUTHOR......: David Rowe, Don Reid
DATE CREATED: 7 July 2018
Test and profile OFDM de-modulation on the STM32F4.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This is a unit test implementation of the OFDM Demod function.
* It is used for several tests:
*
* tst_ofdm_demod_ideal Simple 10 frames with no degradation.
* tst_ofdm_demod_AWGN Just AWGN in channel.
* tst_ofdm_demod_fade AWGN and fading in channel.
* tst_ofdm_demod_profile Profile, disable verbose logging.
*
* See tst_ofdm_demod_setup and tst_ofdm_demod_check scripts for details.
*
* This program reads a file "stm_cfg.txt" at startup to configure its options.
*
* This program is intended to be run using input data, typically
* Codec2 frames, which may have had simulated RF degradation applied.
* For example:
*
* ofdm_get_test_bits - 10 | * ofdm_mod - - | \
* cohpsk_ch - stm_in.raw -20 -Fs 8000 -f -5
*
* Reference data can be created by running the same input through the x86
* ofdm_demod tool.
*
* ofdm_demod stm_in.raw ref_demod_out.raw -o ofdm_demod_ref_log.txt --testframes
*
* Comparison of the results to the reference will depend on the test conditions.
* Some small differences are expected due to differences in implementation.
*
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "semihosting.h"
#include "codec2_ofdm.h"
#include "ofdm_internal.h"
#include "mpdecode_core.h"
#include "ldpc_codes.h"
#include "interldpc.h"
#include "gp_interleaver.h"
#include "test_bits_ofdm.h"
#include "debug_alloc.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
#define NDISCARD 20
extern const uint8_t payload_data_bits[];
extern const int test_bits_ofdm[];
static struct OFDM_CONFIG *ofdm_config;
static int ofdm_bitsperframe;
static int ofdm_rowsperframe;
static int ofdm_nuwbits;
static int ofdm_ntxtbits;
static int ofdm_nin;
static char fout_buffer[4*4096];
static __attribute__ ((section (".ccm"))) char fdiag_buffer[4*8192];
static __attribute__ ((section (".ccm"))) char fin_buffer[4096*8];
static char *statemode[] = {
"search",
"trial",
"synced"
};
static FILE *fout, *fdiag;
void flush_all(void) {
fflush(fout);
fflush(fdiag);
fflush(stdout);
fflush(stderr);
}
int main(int argc, char *argv[]) {
struct OFDM *ofdm;
FILE *fcfg;
int nin_frame;
struct LDPC ldpc;
// Test configuration, read from stm_cfg.txt
int config_verbose;
int config_testframes;
int config_ldpc_en;
int config_log_payload_syms;
int config_profile;
int i;
int Nerrs, Terrs, Tbits, Terrs2, Tbits2, frame_count;
int Tbits_coded, Terrs_coded;
semihosting_init();
fprintf(stdout, "OFDM Demod test\n");
// Read configuration - a file of '0' or '1' characters
char config[8];
fcfg = fopen("stm_cfg.txt", "r");
if (fcfg == NULL) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (fread(&config[0], 1, 8, fcfg) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_verbose = config[0] - '0';
config_testframes = config[1] - '0';
config_ldpc_en = config[2] - '0';
config_log_payload_syms = config[3] - '0';
config_profile = config[4] - '0';
fclose(fcfg);
int Nerrs_raw = 0;
int Nerrs_coded = 0;
int iter = 0;
int parityCheckCount = 0;
PROFILE_VAR(ofdm_demod_start, ofdm_demod_sync_search,
ofdm_demod_demod, ofdm_demod_diss, ofdm_demod_snr);
ofdm_demod_start = 0;
ofdm_demod_sync_search = 0;
ofdm_demod_demod = 0;
ofdm_demod_diss = 0;
ofdm_demod_snr = 0;
if (config_profile) machdep_profile_init();
ofdm = ofdm_create(NULL);
assert(ofdm != NULL);
/* Get a copy of the actual modem config */
ofdm_config = ofdm_get_config_param(ofdm);
ldpc_codes_setup(&ldpc, "HRA_112_112");
ofdm_bitsperframe = ofdm_get_bits_per_frame(ofdm);
ofdm_rowsperframe = ofdm_bitsperframe / (ofdm_config->nc * ofdm_config->bps);
ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits;
ofdm_ntxtbits = ofdm_config->txtbits;
ofdm_nin = ofdm_get_nin(ofdm);
ofdm_set_verbose(ofdm, config_verbose);
int Nmaxsamperframe = ofdm_get_max_samples_per_frame(ofdm);
int data_bits_per_frame = ldpc.data_bits_per_frame;
int coded_bits_per_frame = ldpc.coded_bits_per_frame;
int coded_syms_per_frame = ldpc.coded_bits_per_frame/ofdm->bps;
short rx_scaled[Nmaxsamperframe];
int rx_bits[ofdm_bitsperframe];
char rx_bits_char[ofdm_bitsperframe];
uint8_t rx_uw[ofdm_nuwbits];
short txt_bits[ofdm_ntxtbits];
int f = 0;
Nerrs = Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = 0;
float snr_est_smoothed_dB = 0.0;
float EsNo = 3.0f; // Constant from ofdm_demod.c
COMP payload_syms[coded_syms_per_frame];
float payload_amps[coded_syms_per_frame];
COMP codeword_symbols[coded_syms_per_frame];
float codeword_amps[coded_syms_per_frame];
FILE* fin = fopen("stm_in.raw", "rb");
if (fin == NULL) {
fprintf(stderr, "Error opening input file\n");
exit(1);
}
setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer));
fout = fopen("stm_out.raw", "wb");
if (fout == NULL) {
fprintf(stderr, "Error opening output file\n");
exit(1);
}
setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer));
fdiag = fopen("stm_diag.raw", "wb");
if (fdiag == NULL) {
fprintf(stderr, "Error opening diag file\n");
exit(1);
}
setvbuf(fdiag, fdiag_buffer,_IOFBF,sizeof(fdiag_buffer));
nin_frame = ofdm_get_nin(ofdm);
int num_read;
while((num_read = fread(rx_scaled, sizeof(short) , nin_frame, fin)) == nin_frame) {
int log_payload_syms_flag = 0;
if (config_profile) PROFILE_SAMPLE(ofdm_demod_start);
/* demod */
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_start, " ofdm_demod_start");
if (ofdm->sync_state == search) {
if (config_profile) PROFILE_SAMPLE(ofdm_demod_sync_search);
ofdm_sync_search_shorts(ofdm, rx_scaled, (OFDM_PEAK/2));
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_sync_search, " ofdm_demod_sync_search");
}
if ((ofdm->sync_state == synced) || (ofdm->sync_state == trial) ) {
if (config_profile) PROFILE_SAMPLE(ofdm_demod_demod);
ofdm_demod_shorts(ofdm, rx_bits, rx_scaled, (OFDM_PEAK/2));
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_demod, " ofdm_demod_demod");
if (config_profile) PROFILE_SAMPLE(ofdm_demod_diss);
ofdm_extract_uw(ofdm, ofdm->rx_np, ofdm->rx_amp, rx_uw);
ofdm_disassemble_qpsk_modem_packet(ofdm, ofdm->rx_np, ofdm->rx_amp, payload_syms, payload_amps, txt_bits);
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_demod_diss, " ofdm_demod_diss");
log_payload_syms_flag = 1;
/* SNR estimation and smoothing */
if (config_profile) PROFILE_SAMPLE(ofdm_demod_snr);
float EsNodB = ofdm_esno_est_calc((complex float*)payload_syms, coded_syms_per_frame);
float snr_est_dB = ofdm_snr_from_esno(ofdm, EsNodB);
snr_est_smoothed_dB = 0.9f * snr_est_smoothed_dB + 0.1f *snr_est_dB;
if (config_profile) {
PROFILE_SAMPLE_AND_LOG2(ofdm_demod_snr, " ofdm_demod_snr");
}
// LDPC
if (config_ldpc_en) { // was llr_en in orig
/* first few symbols are used for UW and txt bits, find
start of (224,112) LDPC codeword and extract QPSK
symbols and amplitude estimates */
assert((ofdm_nuwbits + ofdm_ntxtbits + coded_bits_per_frame)
== ofdm_bitsperframe);
/* newest symbols at end of buffer (uses final i from last loop) */
for(i=0; i < coded_syms_per_frame; i++) {
codeword_symbols[i] = payload_syms[i];
codeword_amps[i] = payload_amps[i];
}
/* run de-interleaver */
COMP codeword_symbols_de[coded_syms_per_frame];
float codeword_amps_de[coded_syms_per_frame];
gp_deinterleave_comp (codeword_symbols_de, codeword_symbols, coded_syms_per_frame);
gp_deinterleave_float(codeword_amps_de, codeword_amps, coded_syms_per_frame);
float llr[coded_bits_per_frame];
if (config_ldpc_en) {
uint8_t out_char[coded_bits_per_frame];
if (config_testframes) {
Terrs += count_uncoded_errors(&ldpc, ofdm_config, codeword_symbols_de, 0);
Tbits += coded_bits_per_frame;
}
symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de,
EsNo, ofdm->mean_amp, coded_syms_per_frame);
iter = run_ldpc_decoder(&ldpc, out_char, llr, &parityCheckCount);
//fprintf(stderr,"iter: %d pcc: %d\n", iter, parityCheckCount);
if (config_testframes) {
/* construct payload data bits */
uint8_t payload_data_bits[data_bits_per_frame];
ofdm_generate_payload_data_bits(payload_data_bits, data_bits_per_frame);
Nerrs_coded = count_errors(payload_data_bits, out_char, data_bits_per_frame);
Terrs_coded += Nerrs_coded;
Tbits_coded += data_bits_per_frame;
}
fwrite(out_char, sizeof(char), data_bits_per_frame, fout);
} else {
/* lpdc_en == 0, external LDPC decoder, so output LLRs */
symbols_to_llrs(llr, codeword_symbols_de, codeword_amps_de, EsNo, ofdm->mean_amp, coded_syms_per_frame);
fwrite(llr, sizeof(double), coded_bits_per_frame, fout);
}
} else { // !llrs_en (or ldpc_en)
/* simple hard decision output for uncoded testing, excluding UW and txt */
assert(coded_syms_per_frame*ofdm_config->bps == coded_bits_per_frame);
for (i = 0; i < coded_syms_per_frame; i++) {
int bits[2];
complex float s = payload_syms[i].real + I * payload_syms[i].imag;
qpsk_demod(s, bits);
rx_bits_char[ofdm_config->bps * i] = bits[1];
rx_bits_char[ofdm_config->bps * i + 1] = bits[0];
}
fwrite(rx_bits_char, sizeof (uint8_t), coded_bits_per_frame, fout);
}
/* optional error counting on uncoded data in non-LDPC testframe mode */
if (config_testframes && (config_ldpc_en == 0)) {
/* build up a test frame consisting of unique word, txt bits, and psuedo-random
uncoded payload bits. The psuedo-random generator is the same as Octave so
it can interoperate with ofdm_tx.m/ofdm_rx.m */
int Npayloadbits = ofdm_bitsperframe-(ofdm_nuwbits+ofdm_ntxtbits);
uint16_t r[Npayloadbits];
uint8_t payload_bits[Npayloadbits];
uint8_t tx_bits[Npayloadbits];
ofdm_rand(r, Npayloadbits);
for(i=0; i<Npayloadbits; i++) {
payload_bits[i] = r[i] > 16384;
//fprintf(stderr,"%d %d ", r[i], tx_bits_char[i]);
}
uint8_t txt_bits[ofdm_ntxtbits];
for(i=0; i<ofdm_ntxtbits; i++) {
txt_bits[i] = 0;
}
ofdm_assemble_qpsk_modem_packet(ofdm, tx_bits, payload_bits, txt_bits);
Nerrs = 0;
for(i=0; i<ofdm_bitsperframe; i++) {
if (tx_bits[i] != rx_bits[i]) {
Nerrs++;
}
}
Terrs += Nerrs;
Tbits += ofdm_bitsperframe;
if (frame_count >= NDISCARD) {
Terrs2 += Nerrs;
Tbits2 += ofdm_bitsperframe;
}
} // config_testframes ...
frame_count++;
} // state "synced" or "trial"
nin_frame = ofdm_get_nin(ofdm);
ofdm_sync_state_machine(ofdm, rx_uw);
/* act on any events returned by state machine */
if (ofdm->sync_start) {
Terrs = Tbits = Terrs2 = Tbits2 = Terrs_coded = Tbits_coded = frame_count = Nerrs_raw = Nerrs_coded = 0;
}
if (config_testframes && config_verbose) {
fprintf(stderr, "%3d st: %-6s", f, statemode[ofdm->last_sync_state]);
fprintf(stderr, " euw: %2d %1d f: %5.1f eraw: %3d ecdd: %3d iter: %3d pcc: %3d\n",
ofdm->uw_errors, ofdm->sync_counter,
(double)ofdm->foff_est_hz,
Nerrs, Nerrs_coded, iter, parityCheckCount);
}
if (config_log_payload_syms) {
if (! log_payload_syms_flag) {
memset(payload_syms, 0, (sizeof(COMP)*coded_syms_per_frame));
memset(payload_amps, 0, (sizeof(float)*coded_syms_per_frame));
}
fwrite(payload_syms, sizeof(COMP), coded_syms_per_frame, fdiag);
fwrite(payload_amps, sizeof(float), coded_syms_per_frame, fdiag);
}
f++;
} // while(fread(.., fin))
flush_all(); // To make sure this function is included in binary.
fclose(fin);
fclose(fout);
fclose(fdiag);
if (config_testframes) {
printf("BER......: %5.4f Tbits: %5d Terrs: %5d\n", (double)Terrs/Tbits, Tbits, Terrs);
if (!config_ldpc_en) {
printf("BER2.....: %5.4f Tbits: %5d Terrs: %5d\n", (double)Terrs2/Tbits2, Tbits2, Terrs2);
}
if (config_ldpc_en) {
printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d\n",
(double)Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded);
}
}
if (config_profile) {
printf("\nStart Profile Data\n");
machdep_profile_print_logged_samples();
printf("End Profile Data\n");
}
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
return 0;
}
/* vi:set ts=4 et sts=4: */
+248
View File
@@ -0,0 +1,248 @@
/*---------------------------------------------------------------------------*\
FILE........: tst_ofdm_mod.c
AUTHOR......: David Rowe, Don Reid
DATE CREATED: 25 June 2018
Test and profile OFDM modulation on the STM32F4.
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2014 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* This is a unit test implementation of the OFDM Mod function.
*
* Typical run:
ofdm_gen_test_bits stm_in.raw 6 --rand
ofdm_mod stm_in.raw ref_mod_out.raw
echo "00000000" > stm_cfg.txt
<Load stm32 and run>
compare_ints -s -b2 ref_mod_out.raw mod.raw
ofdm_demod ref_mod_out.raw ref_ofdm_demod.raw --testframes
ofdm_demod mod.raw stm_demod.raw --testframes
* For LDPC use:
ofdm_gen_test_bits stm_in.raw 6 --rand --ldpc
ofdm_mod stm_in.raw ref_mod_out.raw --ldpc
echo "00100000" > stm_cfg.txt
<Load stm32 and run>
ofdm_demod ref_mod_out.raw ref_ofdm_demod.raw --ldpc --testframes
ofdm_demod mod.raw stm_demod.raw --ldpc --testframes
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "semihosting.h"
#include "codec2_ofdm.h"
#include "ofdm_internal.h"
#include "ldpc_codes.h"
#include "interldpc.h"
#include "gp_interleaver.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
#include "debug_alloc.h"
int main(int argc, char *argv[]) {
struct OFDM *ofdm;
FILE *fcfg;
struct LDPC ldpc;
// Test configuration, read from stm_cfg.txt
int config_verbose;
// int config_testframes;
int config_ldpc_en;
// int config_log_payload_syms;
int config_profile;
int Nbitsperframe, Nsamperframe;
int frame = 0;
int i;
semihosting_init();
printf("OFDM_mod test and profile\n");
// Read configuration - a file of '0' or '1' characters
char config[8];
fcfg = fopen("stm_cfg.txt", "r");
if (fcfg == NULL) {
fprintf(stderr, "Error opening config file\n");
exit(1);
}
if (fread(&config[0], 1, 8, fcfg) != 8) {
fprintf(stderr, "Error reading config file\n");
exit(1);
}
config_verbose = config[0] - '0';
// config_testframes = config[1] - '0';
config_ldpc_en = config[2] - '0';
// config_log_payload_syms = config[3] - '0';
config_profile = config[4] - '0';
fclose(fcfg);
PROFILE_VAR(ofdm_mod_start);
if (config_profile) machdep_profile_init();
struct OFDM_CONFIG *ofdm_config;
ofdm = ofdm_create(NULL);
assert(ofdm != NULL);
/* Get a copy of the actual modem config */
ofdm_config = ofdm_get_config_param(ofdm);
ldpc_codes_setup(&ldpc, "HRA_112_112");
Nbitsperframe = ofdm_get_bits_per_frame(ofdm);
int Ndatabitsperframe;
if (config_ldpc_en) {
Ndatabitsperframe = ldpc.data_bits_per_frame;
} else {
Ndatabitsperframe = ofdm_get_bits_per_frame(ofdm) - ofdm->nuwbits - ofdm->ntxtbits;
}
Nsamperframe = ofdm_get_samples_per_frame(ofdm);
// int ofdm_nuwbits = (ofdm_config->ns - 1) * ofdm_config->bps - ofdm_config->txtbits;
if (config_verbose) {
ofdm_set_verbose(ofdm, config_verbose);
fprintf(stderr, "Nsamperframe: %d, Nbitsperframe: %d \n", Nsamperframe, Nbitsperframe);
}
int ofdm_ntxtbits = ofdm_config->txtbits;
uint8_t tx_bits_char[Ndatabitsperframe];
int16_t tx_scaled[Nsamperframe];
uint8_t txt_bits_char[ofdm_ntxtbits];
for(i=0; i< ofdm_ntxtbits; i++) {
txt_bits_char[i] = 0;
}
if (config_verbose) {
ofdm_print_info(ofdm);
}
int sin = open("stm_in.raw", O_RDONLY);
if (sin < 0) {
printf("Error opening input file\n");
exit(1);
}
int sout = open("mod.raw", O_WRONLY|O_TRUNC|O_CREAT, 0666);
if (sout < 0) {
printf("Error opening output file\n");
exit(1);
}
while (read(sin, tx_bits_char, sizeof(char) * Ndatabitsperframe) == Ndatabitsperframe) {
fprintf(stderr, "Frame %d\n", frame);
if (config_profile) { PROFILE_SAMPLE(ofdm_mod_start); }
if (config_ldpc_en) {
complex float tx_sams[Nsamperframe];
ofdm_ldpc_interleave_tx(ofdm, &ldpc, tx_sams, tx_bits_char, txt_bits_char);
for(i=0; i<Nsamperframe; i++) {
tx_scaled[i] = crealf(tx_sams[i]);
}
} else { // !config_ldpc_en
uint8_t tx_frame[Nbitsperframe];
ofdm_assemble_qpsk_modem_packet(ofdm, tx_frame, tx_bits_char, txt_bits_char);
int tx_bits[Nbitsperframe];
for(i=0; i<Nbitsperframe; i++) {
tx_bits[i] = tx_frame[i];
}
if (config_verbose >=3) {
fprintf(stderr, "\ntx_bits:\n");
for (i = 0; i < Nbitsperframe; i++) {
fprintf(stderr, " %3d %8d\n", i, tx_bits[i]);
}
}
COMP tx_sams[Nsamperframe];
ofdm_mod(ofdm, tx_sams, tx_bits);
if (config_verbose >=3) {
fprintf(stderr, "\ntx_sams:\n");
for (i = 0; i < Nsamperframe; i++) {
fprintf(stderr, " %3d % f\n", i, (double)tx_sams[i].real);
}
}
for(i=0; i<Nsamperframe; i++) {
tx_scaled[i] = tx_sams[i].real;
}
}
if (config_profile) PROFILE_SAMPLE_AND_LOG2(ofdm_mod_start, " ofdm_mod");
write(sout, tx_scaled, sizeof(int16_t) * Nsamperframe);
frame ++;
} // while (fread(...
close(sin);
close(sout);
if (config_verbose)
printf("%d frames processed\n", frame);
if (config_profile) {
printf("\nStart Profile Data\n");
machdep_profile_print_logged_samples();
printf("End Profile Data\n");
}
printf("\nEnd of Test\n");
fclose(stdout);
fclose(stderr);
return 0;
}
/* vi:set ts=4 et sts=4: */
+91
View File
@@ -0,0 +1,91 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include "semihosting.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "machdep.h"
#define min(a, b) ((a < b) ? (a) : (b))
int main(int argc, char *argv[]) {
semihosting_init();
printf("semihosting test - stdout\n");
fprintf(stderr, "semihosting test - stderr\n");
uint8_t buf[128];
int count;
int i;
FILE *fin = fopen("stm_in.raw", "rb");
if (!fin) {
fprintf(stderr, "Error %d opening fin\n", errno);
}
setbuf(fin, NULL);
FILE *fout = fopen("stm_out.raw", "wb");
if (!fout) {
fprintf(stderr, "Error %d opening fout\n", errno);
}
setbuf(fout, NULL);
// Unrolled while loop for simpler debugging:
// Pass 0: expect 16 bytes 00-0f
printf("Pass 0: feof(fin) = %d\n", feof(fin));
count = fread(&buf[0], 1, 16, fin);
printf("read %d bytes: ", count);
for (i=0; i<count; i++) printf(" %02x", buf[i]);
printf("\nfeof(fin) = %d\n", feof(fin));
for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i];
if (count) count = fwrite(&buf[0], 1, count, fout);
printf("Wrote %d bytes\n\n", count);
// Pass 1: expect 16 bytes 10-1f
printf("Pass 1: feof(fin) = %d\n", feof(fin));
count = fread(&buf[0], 1, 16, fin);
printf("read %d bytes: ", count);
for (i=0; i<count; i++) printf(" %02x", buf[i]);
printf("\nfeof(fin) = %d\n", feof(fin));
for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i];
if (count) count = fwrite(&buf[0], 1, count, fout);
printf("Wrote %d bytes\n\n", count);
// Pass 2: expect 3 bytes 20-22
printf("Pass 2: feof(fin) = %d\n", feof(fin));
count = fread(&buf[0], 1, 16, fin);
printf("read %d bytes: ", count);
for (i=0; i<count; i++) printf(" %02x", buf[i]);
printf("\nfeof(fin) = %d\n", feof(fin));
for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i];
if (count) count = fwrite(&buf[0], 1, count, fout);
printf("Wrote %d bytes\n\n", count);
// Pass 3: expect 0 result (EOF)
printf("Pass 3: feof(fin) = %d\n", feof(fin));
count = fread(&buf[0], 1, 16, fin);
printf("read %d bytes: ", count);
for (i=0; i<count; i++) printf(" %02x", buf[i]);
printf("\nfeof(fin) = %d\n", feof(fin));
for (i=0; i<min(count, 16); i++) buf[i] = ~buf[i];
if (count) count = fwrite(&buf[0], 1, count, fout);
printf("Wrote %d bytes\n\n", count);
fclose(fin);
fclose(fout);
printf("End of test\n");
fflush(stdout);
fflush(stderr);
return 0;
}
/* vi:set ts=4 et sts=4: */