diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..24c90aa --- /dev/null +++ b/.clang-format @@ -0,0 +1,103 @@ +--- +BasedOnStyle: Google +--- +Language: Cpp + +# 1. Two space indentation (never-ever use tabs) +IndentWidth: 2 +UseTab: Never + +# 2. Max number of columns is 80 +ColumnLimit: 80 + +# 3. No space before parenthesis except for flow control statements +# (if, for, switch, etc) and sizeof. +# Warning: It seems there is no option for spacing after sizeof +SpaceBeforeCaseColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true + +# 4. Opening and closing braces in the same line as the statement they refer to, +# preceded by a space (if () {) except for function definitions +# (opening braces in a new line) +BreakBeforeBraces: Linux + +# 5. Variable declarations at the beginning of the innermost block they are +# required. +# Warn: Cannot be tested + +# 6. Return type and qualifiers of a function prototype goes in the same line +# as the function name. +# 7. Return type and qualifiers of a function definition goes in two separate +# lines (qualifiers, types, line break, name(...)) +AlwaysBreakAfterDefinitionReturnType: All +AlwaysBreakAfterReturnType: AllDefinitions + +# 8. If a line is too long (more than 80 chars) we break it according to the +# following rules: +# - We break from left to right, until all sublines honor the 80 column limit +# - Line break increments the indentation level of all sublines in one unit +# (2 spaces) except the first one +# - Unary operations are never broken +# - Binary operations are broken between the first operand and the operation +# - Ternary operations are broken in three lines, with the first break +# between the conditional expression and the "?", and the second break +# right before the ":" +# - Function calls are broken right after the parenthesis, with every +# argument in a separate line except if the grouping of certain arguments +# improves readability (e.g. pairs of I/Q components, groups of 3 spatial +# coordinates, etc) +# - Function definitions are broken right after the parenthesis, with every +# argument definition in a separate line, always. +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeTernaryOperators: true +AllowAllArgumentsOnNextLine: false +BinPackArguments: false +AllowAllParametersOfDeclarationOnNextLine: false +BinPackParameters: false + +# 9. Assignments inside conditional statements are allowed, unless it impacts +# readability +# Warn: Cannot be tested + +# 10. Braceless blocks (i.e. when the body of certain control flow statement +# consists in only one statement) are preferred, according to the following +# rules: +# - The statement itself and its body is separated by a line break, with the +# body indentation incremented by one unit. +# - If the statement is an if-else construct, and one of either blocks +# contain more than 1 statement, both blocks use braces. +# - If the statement consists of several nested blocks of the same kind, and +# any of the statement bodies cannot be expressed as a braceless block, all +# nested blocks use braces. +# Warn: Cannot be tested. +# Note: Going by the statements above, one-liners will be avoided. +AllowShortIfStatementsOnASingleLine: Never +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLoopsOnASingleLine: false +AlignAfterOpenBracket: AlwaysBreak + +# 11. Variable names in declarations are not aligned, unless it improves +# readability. +# Warn: A general rule must be set. Going for not aligned. + +# 12. Structure member names are not aligned, unless it improves readability. +# Warn: A general rule must be set. Going for not aligned. + +# 13. Pointer declarations leave a space between the type and the stars, and no +# space between the stars and the identifier, or between the stars themselves. +DerivePointerAlignment: false +PointerAlignment: Right + +# 14. In C code, we favor lower snake case for variables, types and function +# names. +# Warn: Cannot be checked. User responsibility. + +# 15. In C/C++ code, we favor upper snake case for #defines and enumerated constants. +# Warn: Cannot be checked. User responsibility. + +# 16. Ident preprocessor directives after the hash +IndentPPDirectives: AfterHash diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index abb0500..90864fd 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -2,23 +2,40 @@ name: CI on: push: - branches: [ develop ] + branches: [ master ] pull_request: - branches: [ develop ] + branches: [ master ] workflow_dispatch: - + inputs: + debug_enabled: + description: 'Build and run interactive shell' + required: false + default: false + env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: - build-all: - strategy: - matrix: - os: [ubuntu-latest, macos-latest] + # Installation of dependencies is too OS-dependent now, we don't + # miss that much by particularizing this in a per-OS basis. - runs-on: ${{ matrix.os }} + build-linux: + runs-on: ubuntu-latest steps: + - name: Setup interactive shell session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + + - name: Install sndfile + run: sudo apt-get install libsndfile1-dev + + - name: Install Volk + run: sudo apt-get install libvolk2-dev + + - name: Install FFTW3 + run: sudo apt-get install libfftw3-dev + - name: Checkout uses: actions/checkout@v2 @@ -27,4 +44,49 @@ jobs: - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + + build-macos: + runs-on: macos-latest + steps: + - name: Setup interactive shell session + uses: mxschmitt/action-tmate@v3 + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} + + - name: Install sndfile + run: brew install libsndfile + + - name: Install Volk + run: brew install volk + + - name: Install FFTW3 + run: brew install fftw + - name: Checkout + uses: actions/checkout@v2 + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + build-windows: + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v2 + - uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: git mingw-w64-x86_64-cc mingw-w64-x86_64-make mingw-w64-x86_64-cmake mingw-w64-x86_64-libsndfile mingw-w64-x86_64-fftw mingw-w64-x86_64-volk + + - name: Configure CMake + run: /mingw64/bin/cmake -B '${{github.workspace}}/build' -G"MinGW Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=/mingw64 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + - name: Build + run: /mingw64/bin/cmake --build '${{github.workspace}}/build' --config ${{env.BUILD_TYPE}} + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/AUTHORS b/AUTHORS index febdd5a..c13e077 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,4 +3,6 @@ - Mehdi Asgari Complex float API support in C++ - \ No newline at end of file + +- Ángel Ruiz Fernández + Windows support \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index a593e5c..6fccbbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ cmake_minimum_required(VERSION 3.5.1) set(SIGUTILS_VERSION_MAJOR 0) -set(SIGUTILS_VERSION_MINOR 2) +set(SIGUTILS_VERSION_MINOR 3) set(SIGUTILS_VERSION_PATCH 0) set(SIGUTILS_ABI_VERSION 1) @@ -48,12 +48,14 @@ pkg_check_modules(SNDFILE REQUIRED sndfile>=1.0.2) pkg_check_modules(FFTW3 REQUIRED fftw3f>=3.0) pkg_check_modules(VOLK volk>=1.0) +# Find cppcheck (if available) +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") +include(CodeAnalysis) + # Source location set(SRCDIR sigutils) set(UTILDIR util) -set(CODECDIR ${SRCDIR}/codecs) -set(BLOCKDIR ${SRCDIR}/blocks) -set(MODEMDIR ${SRCDIR}/modems) +set(SPECDIR ${SRCDIR}/specific) # Compiler configuration set(SIGUTILS_CONFIG_CFLAGS "-D_SU_SINGLE_PRECISION") @@ -113,20 +115,73 @@ install( set(SIGUTILS_UTIL_HEADERS ${UTILDIR}/util.h) set(SIGUTILS_UTIL_SOURCES ${UTILDIR}/util.c) +set(SIGUTILS_COMPAT_SOURCES "") +set(SIGUTILS_COMPAT_HEADERS + ${UTILDIR}/compat-mman.h + ${UTILDIR}/compat-time.h + ${UTILDIR}/compat-stat.h + ${UTILDIR}/compat-fcntl.h + ${UTILDIR}/compat-in.h + ${UTILDIR}/compat-inet.h + ${UTILDIR}/compat-netdb.h + ${UTILDIR}/compat-poll.h + ${UTILDIR}/compat-pwd.h + ${UTILDIR}/compat-select.h + ${UTILDIR}/compat-socket.h + ${UTILDIR}/compat-statvfs.h + ${UTILDIR}/compat-stdlib.h + ${UTILDIR}/compat-termios.h + ${UTILDIR}/compat-unistd.h) + +if(WIN32) + set(SIGUTILS_COMPAT_HEADERS + ${SIGUTILS_COMPAT_HEADERS} + ${UTILDIR}/win32-mman.h + ${UTILDIR}/win32-time.h + ${UTILDIR}/win32-stat.h + ${UTILDIR}/win32-fcntl.h + ${UTILDIR}/win32-in.h + ${UTILDIR}/win32-inet.h + ${UTILDIR}/win32-netdb.h + ${UTILDIR}/win32-poll.h + ${UTILDIR}/win32-pwd.h + ${UTILDIR}/win32-socket.h + ${UTILDIR}/win32-statvfs.h + ${UTILDIR}/win32-stdlib.h + ${UTILDIR}/win32-termios.h + ${UTILDIR}/win32-unistd.h) + + set(SIGUTILS_COMPAT_SOURCES + ${SIGUTILS_COMPAT_SOURCES} + ${UTILDIR}/win32-fcntl.c + ${UTILDIR}/win32-mman.c + ${UTILDIR}/win32-time.c + ${UTILDIR}/win32-poll.c + ${UTILDIR}/win32-pwd.c + ${UTILDIR}/win32-statvfs.c + ${UTILDIR}/win32-stdlib.c + ${UTILDIR}/win32-termios.c + ${UTILDIR}/win32-unistd.c) +endif() + +set(SIGUTILS_SPECIFIC_HEADERS + ${SPECDIR}/apt.h) +set(SIGUTILS_SPECIFIC_SOURCES + ${SPECDIR}/apt.c) + set(SIGUTILS_LIB_HEADERS ${SRCDIR}/agc.h ${SRCDIR}/block.h ${SRCDIR}/clock.h - ${SRCDIR}/codec.h ${SRCDIR}/coef.h ${SRCDIR}/decider.h + ${SRCDIR}/defs.h ${SRCDIR}/detect.h ${SRCDIR}/equalizer.h ${SRCDIR}/iir.h ${SRCDIR}/lfsr.h ${SRCDIR}/log.h ${SRCDIR}/matfile.h - ${SRCDIR}/modem.h ${SRCDIR}/ncqo.h ${SRCDIR}/pll.h ${SRCDIR}/property.h @@ -144,7 +199,6 @@ set(SIGUTILS_LIB_SOURCES ${SRCDIR}/agc.c ${SRCDIR}/block.c ${SRCDIR}/clock.c - ${SRCDIR}/codec.c ${SRCDIR}/coef.c ${SRCDIR}/detect.c ${SRCDIR}/equalizer.c @@ -153,7 +207,6 @@ set(SIGUTILS_LIB_SOURCES ${SRCDIR}/lib.c ${SRCDIR}/log.c ${SRCDIR}/matfile.c - ${SRCDIR}/modem.c ${SRCDIR}/ncqo.c ${SRCDIR}/pll.c ${SRCDIR}/property.c @@ -163,30 +216,18 @@ set(SIGUTILS_LIB_SOURCES ${SRCDIR}/taps.c ${SRCDIR}/tvproc.c ${SRCDIR}/version.c) - -set(SIGUTILS_BLOCK_SOURCES - ${BLOCKDIR}/agc.c - ${BLOCKDIR}/clock.c - ${BLOCKDIR}/pll.c - ${BLOCKDIR}/tuner.c - ${BLOCKDIR}/filt.c - ${BLOCKDIR}/siggen.c - ${BLOCKDIR}/wavfile.c) - -set(SIGUTILS_CODEC_SOURCES ${CODECDIR}/diff.c) -set(SIGUTILS_MODEM_SOURCES ${MODEMDIR}/qpsk.c) link_directories(${PROJECT_BINARY_DIR} ${SNDFILE_LIBRARY_DIRS} ${FFTW3_LIBRARY_DIRS}) - + add_library( sigutils SHARED + ${SIGUTILS_COMPAT_SOURCES} + ${SIGUTILS_COMPAT_HEADERS} ${SIGUTILS_UTIL_SOURCES} ${SIGUTILS_UTIL_HEADERS} ${SIGUTILS_LIB_SOURCES} ${SIGUTILS_LIB_HEADERS} - ${SIGUTILS_BLOCK_SOURCES} - ${SIGUTILS_CODEC_SOURCES} - ${SIGUTILS_MODEM_SOURCES}) + ${SIGUTILS_SPECIFIC_SOURCES}) set_property(TARGET sigutils PROPERTY VERSION ${SIGUTILS_VERSION}) set_property(TARGET sigutils PROPERTY SOVERSION ${SIGUTILS_ABI_VERSION}) @@ -204,6 +245,11 @@ target_link_libraries(sigutils ${FFTW3_LIBRARIES}) target_link_libraries(sigutils ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(sigutils m) +if(WIN32) + # In Windows systems, winsock is required + target_link_libraries(sigutils ws2_32) +endif() + # Optional dependencies if(VOLK_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_VOLK=1") @@ -216,7 +262,11 @@ install( DESTINATION include/sigutils/sigutils) install( - FILES ${SIGUTILS_UTIL_HEADERS} + FILES ${SIGUTILS_SPECIFIC_HEADERS} + DESTINATION include/sigutils/sigutils/specific) + +install( + FILES ${SIGUTILS_UTIL_HEADERS} ${SIGUTILS_COMPAT_HEADERS} DESTINATION include/sigutils/util) install(TARGETS sigutils DESTINATION ${CMAKE_INSTALL_LIBDIR}) @@ -245,7 +295,6 @@ set(SIGUTILS_TEST_SOURCES ${MAINDIR}/main.c ${TESTDIR}/mat.c ${TESTDIR}/ncqo.c - ${TESTDIR}/codec.c ${TESTDIR}/pll.c ${TESTDIR}/specttuner.c) diff --git a/README.md b/README.md index cf8627f..6b12d54 100644 --- a/README.md +++ b/README.md @@ -159,3 +159,32 @@ Once we are done using the modem object, it must be released using the `su_modem ``` su_modem_destroy(modem); ``` + +## Building and installing sigutils under Windows +Under MSYS2 MinGW64 +First, install dependencies: + +``` +pacman -S git mingw-w64-x86_64-cc mingw-w64-x86_64-make mingw-w64-x86_64-cmake mingw-w64-x86_64-libsndfile mingw-w64-x86_64-fftw mingw-w64-x86_64-volk +``` + +Then, clone the repos, create build directory and configure cmake: + +``` +% git clone --branch develop https://github.com/arf20/sigutils.git +% mkdir build +% cd build +% /msys64/mingw64/bin/cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=/msys64/mingw64 -DCMAKE_BUILD_TYPE=Release .. +``` + +If the previous commands were successful, you can start the build by typing: + +``` +% /msys64/mingw64/bin/cmake --build . --config Release +``` + +And proceed to install the library in your system by running as root: + +``` +# make install +``` diff --git a/cmake/modules/CodeAnalysis.cmake b/cmake/modules/CodeAnalysis.cmake new file mode 100644 index 0000000..3e4d8e2 --- /dev/null +++ b/cmake/modules/CodeAnalysis.cmake @@ -0,0 +1,32 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CodeAnalysis +------- + +Add code format target. + +Custom Targets +^^^^^^^^^^^^^^^^ + +This module provides the following custom target, if found: + +``cppcheck-analysis`` + The code analysis custom target. + +#]=======================================================================] + +if(TARGET codeanalysis) + return() +endif() + +find_package(CppCheck) + +if(CppCheck_FOUND) + message("Cppcheck analysis already added") + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/analysis/cppcheck) + add_custom_target(codeanalysis + COMMAND ${CPPCHECK_COMMAND}) +endif() diff --git a/cmake/modules/FindCppCheck.cmake b/cmake/modules/FindCppCheck.cmake new file mode 100644 index 0000000..f2a30da --- /dev/null +++ b/cmake/modules/FindCppCheck.cmake @@ -0,0 +1,140 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindCppCheck +------- + +Finds the CppCheck Tool. + +Custom Targets +^^^^^^^^^^^^^^^^ + +This module provides the following custom targets, if found: + +``cppcheck-analysis`` + The CppCheck custom target + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``CppCheck_FOUND`` + True if the system has the cppcheck tool. +``CppCheck_VERSION`` + Version of cppcheck tool. + +#]=======================================================================] + +if(CPPCHECK_ROOT_DIR) + find_program(CPPCHECK_BIN + NAMES + cppcheck + PATHS + "${CPPCHECK_ROOT_DIR}" + NO_DEFAULT_PATH) +endif() + +if(NOT CPPCHECK_BIN) + find_program(CPPCHECK_BIN NAMES cppcheck) +endif() + +if(CPPCHECK_BIN) + execute_process( + COMMAND ${CPPCHECK_BIN} --version + OUTPUT_VARIABLE CppCheck_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + set(CPPCHECK_THREADS_ARG "-j4" + CACHE STRING "The number of threads to use") + set(CPPCHECK_PROJECT_ARG "--project=${PROJECT_BINARY_DIR}/compile_commands.json" + CACHE STRING "The project directory to use") + set(CPPCHECK_BUILD_DIR_ARG "--cppcheck-build-dir=${PROJECT_BINARY_DIR}/analysis/cppcheck" + CACHE STRING "The build directory to use") + + # Don't show these errors + if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck-suppressions") + set(CPPCHECK_SUPPRESSIONS "--suppressions-list=${CMAKE_SOURCE_DIR}/.cppcheck-suppressions" + CACHE STRING "The suppressions file to use") + else() + set(CPPCHECK_SUPPRESSIONS "" + CACHE STRING "The suppressions file to use") + endif() + + # Show these errors but don't fail the build + if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck-exitcode-suppressions") + set(CPPCHECK_EXITCODE_SUPPRESSIONS "--exitcode-suppressions=${CMAKE_SOURCE_DIR}/.cppcheck-exitcode-suppressions" + CACHE STRING "The exitcode suppressions file to use") + else() + set(CPPCHECK_EXITCODE_SUPPRESSIONS "" + CACHE STRING "The exitcode suppressions file to use") + endif() + + set(CPPCHECK_ERROR_EXITCODE_ARG "--error-exitcode=1" + CACHE STRING "The exitcode to use if an error is found") + set(CPPCHECK_CHECKS_ARGS "--enable=warning" + CACHE STRING "Arguments for the checks to run") + set(CPPCHECK_OTHER_ARGS "" + CACHE STRING "Other arguments") + + set(_CPPCHECK_EXCLUDES) + foreach(ex ${CPPCHECK_EXCLUDES}) + list(APPEND _CPPCHECK_EXCLUDES "-i${ex}") + endforeach(ex) + + set(CPPCHECK_ALL_ARGS + ${CPPCHECK_THREADS_ARG} + ${CPPCHECK_PROJECT_ARG} + ${CPPCHECK_BUILD_DIR_ARG} + ${CPPCHECK_ERROR_EXITCODE_ARG} + ${CPPCHECK_SUPPRESSIONS} + ${CPPCHECK_EXITCODE_SUPPRESSIONS} + ${CPPCHECK_CHECKS_ARGS} + ${CPPCHECK_OTHER_ARGS} + ${_CPPCHECK_EXCLUDES} + ) + + if(NOT CPPCHECK_XML_OUTPUT) + set(CPPCHECK_COMMAND + ${CPPCHECK_BIN} + ${CPPCHECK_ALL_ARGS} + ) + else() + set(CPPCHECK_COMMAND + ${CPPCHECK_BIN} + ${CPPCHECK_ALL_ARGS} + --xml + --xml-version=2 + 2> ${CPPCHECK_XML_OUTPUT}) + endif() +endif() + +# handle the QUIETLY and REQUIRED arguments and set YAMLCPP_FOUND to TRUE if all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + CppCheck + DEFAULT_MSG + CPPCHECK_BIN) + +mark_as_advanced( + CPPCHECK_BIN + CPPCHECK_THREADS_ARG + CPPCHECK_PROJECT_ARG + CPPCHECK_BUILD_DIR_ARG + CPPCHECK_SUPPRESSIONS + CPPCHECK_EXITCODE_SUPPRESSIONS + CPPCHECK_ERROR_EXITCODE_ARG + CPPCHECK_CHECKS_ARGS + CPPCHECK_OTHER_ARGS) + +if(CppCheck_FOUND) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/analysis/cppcheck) + add_custom_target(cppcheck-analysis + COMMAND ${CPPCHECK_COMMAND}) + message("CppCheck found. Use cppcheck-analysis targets to run it") +else() + message("CppCheck not found") +endif() diff --git a/sigutils/agc.c b/sigutils/agc.c index 3ac8974..44ebaee 100644 --- a/sigutils/agc.c +++ b/sigutils/agc.c @@ -17,56 +17,49 @@ */ +#include "agc.h" + #include #include -#include "agc.h" -SUBOOL -su_agc_init(su_agc_t *agc, const struct su_agc_params *params) -{ - SUFLOAT *mag_buf = NULL; - SUCOMPLEX *delay_line = NULL; +#include "log.h" - memset(agc, 0, sizeof (su_agc_t)); +SU_CONSTRUCTOR(su_agc, const struct su_agc_params *params) +{ + memset(self, 0, sizeof(su_agc_t)); - if ((mag_buf = calloc(params->mag_history_size, sizeof (SUFLOAT))) == NULL) - goto fail; + SU_ALLOCATE_MANY_FAIL(self->mag_history, params->mag_history_size, SUFLOAT); - if ((delay_line = calloc(params->delay_line_size, sizeof (SUCOMPLEX))) == NULL) - goto fail; + SU_ALLOCATE_MANY_FAIL(self->delay_line, params->delay_line_size, SUCOMPLEX); - agc->mag_history = mag_buf; - agc->delay_line = delay_line; - agc->mag_history_size = params->mag_history_size; - agc->delay_line_size = params->delay_line_size; - agc->knee = params->threshold; - agc->hang_max = params->hang_max; - agc->gain_slope = params->slope_factor * 1e-2; - agc->fast_alpha_rise = 1 - SU_EXP(-1. / params->fast_rise_t); - agc->fast_alpha_fall = 1 - SU_EXP(-1. / params->fast_fall_t); - agc->slow_alpha_rise = 1 - SU_EXP(-1. / params->slow_rise_t); - agc->slow_alpha_fall = 1 - SU_EXP(-1. / params->slow_fall_t); - agc->fixed_gain = SU_MAG_RAW(agc->knee * (agc->gain_slope - 1)); + self->mag_history_size = params->mag_history_size; + self->delay_line_size = params->delay_line_size; + self->knee = params->threshold; + self->hang_max = params->hang_max; + self->gain_slope = params->slope_factor * 1e-2; + self->fast_alpha_rise = 1 - SU_EXP(-1. / params->fast_rise_t); + self->fast_alpha_fall = 1 - SU_EXP(-1. / params->fast_fall_t); + self->slow_alpha_rise = 1 - SU_EXP(-1. / params->slow_rise_t); + self->slow_alpha_fall = 1 - SU_EXP(-1. / params->slow_fall_t); + self->fixed_gain = SU_MAG_RAW(self->knee * (self->gain_slope - 1)); - agc->enabled = SU_TRUE; + self->enabled = SU_TRUE; return SU_TRUE; fail: - - su_agc_finalize(agc); + SU_DESTRUCT(su_agc, self); return SU_FALSE; } -void -su_agc_finalize(su_agc_t *agc) +SU_DESTRUCTOR(su_agc) { - if (agc->mag_history != NULL) - free(agc->mag_history); + if (self->mag_history != NULL) + free(self->mag_history); - if (agc->delay_line != NULL) - free(agc->delay_line); + if (self->delay_line != NULL) + free(self->delay_line); } /* @@ -81,8 +74,7 @@ su_agc_finalize(su_agc_t *agc) * 7. Output sample */ -SUCOMPLEX -su_agc_feed(su_agc_t *agc, SUCOMPLEX x) +SU_METHOD(su_agc, SUCOMPLEX, feed, SUCOMPLEX x) { unsigned int i; @@ -92,62 +84,62 @@ su_agc_feed(su_agc_t *agc, SUCOMPLEX x) SUFLOAT peak_delta; /* Push sample */ - x_delayed = agc->delay_line[agc->delay_line_ptr]; + x_delayed = self->delay_line[self->delay_line_ptr]; - agc->delay_line[agc->delay_line_ptr++] = x; - if (agc->delay_line_ptr >= agc->delay_line_size) - agc->delay_line_ptr = 0; + self->delay_line[self->delay_line_ptr++] = x; + if (self->delay_line_ptr >= self->delay_line_size) + self->delay_line_ptr = 0; - if (agc->enabled) { + if (self->enabled) { x_dBFS = .5 * SU_DB(x * SU_C_CONJ(x)) - SUFLOAT_MAX_REF_DB; /* Push mag */ - x_dBFS_delayed = agc->mag_history[agc->mag_history_ptr]; + x_dBFS_delayed = self->mag_history[self->mag_history_ptr]; - agc->mag_history[agc->mag_history_ptr++] = x_dBFS; - if (agc->mag_history_ptr >= agc->mag_history_size) - agc->mag_history_ptr = 0; + self->mag_history[self->mag_history_ptr++] = x_dBFS; + if (self->mag_history_ptr >= self->mag_history_size) + self->mag_history_ptr = 0; - if (x_dBFS > agc->peak) - agc->peak = x_dBFS; - else if (agc->peak == x_dBFS_delayed) { + if (x_dBFS > self->peak) + self->peak = x_dBFS; + else if (self->peak == x_dBFS_delayed) { /* * We've just removed the peak value from the magnitude history, we * need to recalculate the current peak value. */ - agc->peak = SUFLOAT_MIN_REF_DB; + self->peak = SUFLOAT_MIN_REF_DB; - for (i = 0; i < agc->mag_history_size; ++i) { - if (agc->peak < agc->mag_history[i]) - agc->peak = agc->mag_history[i]; + for (i = 0; i < self->mag_history_size; ++i) { + if (self->peak < self->mag_history[i]) + self->peak = self->mag_history[i]; } } /* Update levels for fast averager */ - peak_delta = agc->peak - agc->fast_level; + peak_delta = self->peak - self->fast_level; if (peak_delta > 0) - agc->fast_level += agc->fast_alpha_rise * peak_delta; + self->fast_level += self->fast_alpha_rise * peak_delta; else - agc->fast_level += agc->fast_alpha_fall * peak_delta; + self->fast_level += self->fast_alpha_fall * peak_delta; /* Update levels for slow averager */ - peak_delta = agc->peak - agc->slow_level; + peak_delta = self->peak - self->slow_level; if (peak_delta > 0) { - agc->slow_level += agc->slow_alpha_rise * peak_delta; - agc->hang_n = 0; - } else if (agc->hang_n >= agc->hang_max) - agc->slow_level += agc->slow_alpha_fall * peak_delta; + self->slow_level += self->slow_alpha_rise * peak_delta; + self->hang_n = 0; + } else if (self->hang_n >= self->hang_max) + self->slow_level += self->slow_alpha_fall * peak_delta; else - ++agc->hang_n; + ++self->hang_n; /* Keep biggest magnitude */ - x_dBFS_delayed = SU_MAX(agc->fast_level, agc->slow_level); + x_dBFS_delayed = SU_MAX(self->fast_level, self->slow_level); /* Is AGC on? */ - if (x_dBFS_delayed < agc->knee) - x_delayed *= agc->fixed_gain; + if (x_dBFS_delayed < self->knee) + x_delayed *= self->fixed_gain; else - x_delayed *= SU_MAG_RAW(x_dBFS_delayed * (agc->gain_slope - 1)); + x_delayed *= SU_MAG_RAW(x_dBFS_delayed * (self->gain_slope - 1)); x_delayed *= SU_AGC_RESCALE; } diff --git a/sigutils/agc.h b/sigutils/agc.h index 2bfcd5f..502e305 100644 --- a/sigutils/agc.h +++ b/sigutils/agc.h @@ -20,17 +20,25 @@ #ifndef _SIGUTILS_AGC_H #define _SIGUTILS_AGC_H +#include "defs.h" #include "types.h" +#ifdef __cplusplus +# ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +# endif // __clang__ +extern "C" { +#endif /* __cplusplus */ + /* * This Hang AGC implementation is essentially inspired in GQRX's */ #define SU_AGC_RESCALE 0.7 - struct sigutils_agc { - SUBOOL enabled; + SUBOOL enabled; /* AGC parameters */ SUFLOAT knee; /* AGC Knee in dBs */ @@ -40,16 +48,16 @@ struct sigutils_agc { unsigned int hang_n; /* Hang timer */ /* AGC memory - delay line */ - SUCOMPLEX *delay_line; + SUCOMPLEX *delay_line; unsigned int delay_line_size; unsigned int delay_line_ptr; /* AGC memory - signal magnitude history */ - SUFLOAT *mag_history; + SUFLOAT *mag_history; unsigned int mag_history_size; unsigned int mag_history_ptr; - SUFLOAT peak; /* Current peak value in history */ + SUFLOAT peak; /* Current peak value in history */ /* Used to correct transitional spikes */ SUFLOAT fast_alpha_rise; @@ -64,9 +72,10 @@ struct sigutils_agc { typedef struct sigutils_agc su_agc_t; -#define su_agc_INITIALIZER \ - {0, 0., 0., 0., 0, 0, NULL, 0, 0, NULL, 0, 0, \ - 0., 0., 0., 0., 0., 0., 0.} +#define su_agc_INITIALIZER \ + { \ + 0, 0., 0., 0., 0, 0, NULL, 0, 0, NULL, 0, 0, 0., 0., 0., 0., 0., 0., 0. \ + } struct su_agc_params { SUFLOAT threshold; @@ -84,13 +93,21 @@ struct su_agc_params { SUFLOAT slow_fall_t; }; -#define su_agc_params_INITIALIZER \ - { -100, 6, 100, 20, 20, 2, 4, 20, 40 } +#define su_agc_params_INITIALIZER \ + { \ + -100, 6, 100, 20, 20, 2, 4, 20, 40 \ + } -SUBOOL su_agc_init(su_agc_t *agc, const struct su_agc_params *params); +SU_CONSTRUCTOR(su_agc, const struct su_agc_params *params); +SU_DESTRUCTOR(su_agc); -SUCOMPLEX su_agc_feed(su_agc_t *agc, SUCOMPLEX x); +SU_METHOD(su_agc, SUCOMPLEX, feed, SUCOMPLEX x); -void su_agc_finalize(su_agc_t *agc); +#ifdef __cplusplus +# ifdef __clang__ +# pragma clang diagnostic pop +# endif // __clang__ +} +#endif /* __cplusplus */ #endif /* _SIGUTILS_AGC_H */ diff --git a/sigutils/block.c b/sigutils/block.c index b406b06..c1a3425 100644 --- a/sigutils/block.c +++ b/sigutils/block.c @@ -17,52 +17,45 @@ */ -#include #include +#include #define SU_LOG_LEVEL "block" -#include "log.h" #include "block.h" +#include "log.h" -static su_block_class_t *class_list; -static unsigned int class_storage; -static unsigned int class_count; +static unsigned int class_storage; +static unsigned int class_count; /****************************** su_stream API ********************************/ -SUBOOL -su_stream_init(su_stream_t *stream, SUSCOUNT size) +SU_CONSTRUCTOR(su_stream, SUSCOUNT size) { - SUCOMPLEX *buffer = NULL; - int i = 0; + SUSCOUNT i = 0; - if ((buffer = malloc(size * sizeof (SUCOMPLEX))) == NULL) { - SU_ERROR("buffer allocation failed\n"); - return SU_FALSE; - } + memset(self, 0, sizeof(su_stream_t)); + + SU_ALLOCATE_MANY_CATCH(self->buffer, size, SUCOMPLEX, return SU_FALSE); /* Populate uninitialized buffer with NaNs */ for (i = 0; i < size; ++i) - buffer[i] = nan("uninitialized"); + self->buffer[i] = nan("uninitialized"); - stream->buffer = buffer; - stream->size = size; - stream->ptr = 0; - stream->avail = 0; - stream->pos = 0ull; + self->size = size; + self->ptr = 0; + self->avail = 0; + self->pos = 0ull; return SU_TRUE; } -void -su_stream_finalize(su_stream_t *stream) +SU_DESTRUCTOR(su_stream) { - if (stream->buffer != NULL) - free(stream->buffer); + if (self->buffer != NULL) + free(self->buffer); } -void -su_stream_write(su_stream_t *stream, const SUCOMPLEX *data, SUSCOUNT size) +SU_METHOD(su_stream, void, write, const SUCOMPLEX *data, SUSCOUNT size) { SUSCOUNT skip = 0; SUSCOUNT chunksz; @@ -71,95 +64,91 @@ su_stream_write(su_stream_t *stream, const SUCOMPLEX *data, SUSCOUNT size) * We increment this always. Current reading position is * stream->pos - stream->avail */ - stream->pos += size; + self->pos += size; - if (size > stream->size) { + if (size > self->size) { SU_WARNING("write will overflow stream, keeping latest samples\n"); - skip = size - stream->size; + skip = size - self->size; data += skip; size -= skip; } - if ((chunksz = stream->size - stream->ptr) > size) + if ((chunksz = self->size - self->ptr) > size) chunksz = size; /* This needs to be updated only once */ - if (stream->avail < stream->size) - stream->avail += chunksz; + if (self->avail < self->size) + self->avail += chunksz; - memcpy(stream->buffer + stream->ptr, data, chunksz * sizeof (SUCOMPLEX)); - stream->ptr += chunksz; + memcpy(self->buffer + self->ptr, data, chunksz * sizeof(SUCOMPLEX)); + self->ptr += chunksz; /* Rollover only can happen here */ - if (stream->ptr == stream->size) { - stream->ptr = 0; + if (self->ptr == self->size) { + self->ptr = 0; /* Is there anything left to be written? */ if (size > 0) { size -= chunksz; data += chunksz; - memcpy(stream->buffer + stream->ptr, data, size * sizeof (SUCOMPLEX)); - stream->ptr += size; + memcpy(self->buffer + self->ptr, data, size * sizeof(SUCOMPLEX)); + self->ptr += size; } } } -su_off_t -su_stream_tell(const su_stream_t *stream) +SU_GETTER(su_stream, su_off_t, tell) { - return stream->pos - stream->avail; + return self->pos - self->avail; } - -SUSCOUNT -su_stream_get_contiguous( - const su_stream_t *stream, - SUCOMPLEX **start, - SUSCOUNT size) +SU_GETTER(su_stream, SUSCOUNT, get_contiguous, SUCOMPLEX **start, SUSCOUNT size) { - SUSCOUNT avail = stream->size - stream->ptr; + SUSCOUNT avail = self->size - self->ptr; if (size > avail) { size = avail; } - *start = stream->buffer + stream->ptr; + *start = self->buffer + self->ptr; return size; } -SUSCOUNT -su_stream_advance_contiguous( - su_stream_t *stream, - SUSCOUNT size) +SU_METHOD(su_stream, SUSCOUNT, advance_contiguous, SUSCOUNT size) { - SUSCOUNT avail = stream->size - stream->ptr; + SUSCOUNT avail = self->size - self->ptr; if (size > avail) { size = avail; } - stream->pos += size; - stream->ptr += size; - if (stream->avail < stream->size) { - stream->avail += size; + self->pos += size; + self->ptr += size; + if (self->avail < self->size) { + self->avail += size; } /* Rollover */ - if (stream->ptr == stream->size) { - stream->ptr = 0; + if (self->ptr == self->size) { + self->ptr = 0; } return size; } -SUSDIFF -su_stream_read(const su_stream_t *stream, su_off_t off, SUCOMPLEX *data, SUSCOUNT size) +SU_GETTER( + su_stream, + SUSDIFF, + read, + su_off_t off, + SUCOMPLEX *data, + SUSCOUNT size) { SUSCOUNT avail; - su_off_t readpos = su_stream_tell(stream); + su_off_t readpos = su_stream_tell(self); SUSCOUNT reloff; SUSCOUNT chunksz; SUSDIFF ptr; @@ -169,635 +158,36 @@ su_stream_read(const su_stream_t *stream, su_off_t off, SUCOMPLEX *data, SUSCOUN return -1; /* Greedy reader */ - if (off >= stream->pos) + if (off >= self->pos) return 0; reloff = off - readpos; /* Compute how many samples are available from here */ - avail = stream->avail - reloff; + avail = self->avail - reloff; if (avail < size) { size = avail; } /* Compute position in the stream buffer to read from */ - if ((ptr = stream->ptr - avail) < 0) - ptr += stream->size; + if ((ptr = self->ptr - avail) < 0) + ptr += self->size; /* Adjust in case reloff causes ptr to rollover */ - if (ptr > stream->size) - ptr = ptr - stream->size; + if (ptr > self->size) + ptr = ptr - self->size; - if (ptr + size > stream->size) - chunksz = stream->size - ptr; + if (ptr + size > self->size) + chunksz = self->size - ptr; else chunksz = size; - memcpy(data, stream->buffer + ptr, chunksz * sizeof (SUCOMPLEX)); + memcpy(data, self->buffer + ptr, chunksz * sizeof(SUCOMPLEX)); size -= chunksz; /* Is there anything left to read? */ if (size > 0) - memcpy(data + chunksz, stream->buffer, size * sizeof (SUCOMPLEX)); + memcpy(data + chunksz, self->buffer, size * sizeof(SUCOMPLEX)); return chunksz + size; } - -/************************* su_flow_controller API ****************************/ -void -su_flow_controller_finalize(su_flow_controller_t *fc) -{ - su_stream_finalize(&fc->output); - pthread_mutex_destroy(&fc->acquire_lock); - pthread_cond_destroy(&fc->acquire_cond); -} - -SUBOOL -su_flow_controller_init( - su_flow_controller_t *fc, - enum sigutils_flow_controller_kind kind, - SUSCOUNT size) -{ - SUBOOL result = SU_FALSE; - - memset(fc, 0, sizeof (su_flow_controller_t)); - - if (pthread_mutex_init(&fc->acquire_lock, NULL) == -1) - goto done; - - if (pthread_cond_init(&fc->acquire_cond, NULL) == -1) - goto done; - - if (!su_stream_init(&fc->output, size)) - goto done; - - fc->kind = kind; - fc->consumers = 0; - fc->pending = 0; - - result = SU_TRUE; - -done: - if (!result) - su_flow_controller_finalize(fc); - - return result; -} - -SUPRIVATE void -su_flow_controller_enter(su_flow_controller_t *fc) -{ - pthread_mutex_lock(&fc->acquire_lock); -} - -SUPRIVATE void -su_flow_controller_leave(su_flow_controller_t *fc) -{ - pthread_mutex_unlock(&fc->acquire_lock); -} - -SUPRIVATE void -su_flow_controller_notify_force(su_flow_controller_t *fc) -{ - pthread_cond_broadcast(&fc->acquire_cond); -} - -SUPRIVATE void -su_flow_controller_notify(su_flow_controller_t *fc) -{ - su_flow_controller_notify_force(fc); -} - -SUPRIVATE void -su_flow_controller_force_eos(su_flow_controller_t *fc) -{ - fc->eos = SU_TRUE; - - su_flow_controller_notify(fc); -} - -SUPRIVATE su_off_t -su_flow_controller_tell(const su_flow_controller_t *fc) -{ - return su_stream_tell(&fc->output); -} - -SUPRIVATE su_stream_t * -su_flow_controller_get_stream(su_flow_controller_t *fc) -{ - return &fc->output; -} - -/* TODO: make these functions thread safe */ -SUPRIVATE void -su_flow_controller_add_consumer(su_flow_controller_t *fc) -{ - ++fc->consumers; -} - -SUPRIVATE void -su_flow_controller_remove_consumer(su_flow_controller_t *fc, SUBOOL pend) -{ - --fc->consumers; - - if (fc->kind == SU_FLOW_CONTROL_KIND_BARRIER) { - if (pend) - --fc->pending; - else if (fc->consumers > 0 && fc->consumers == fc->pending) { - /* Wake up all pending threads and try to read again */ - fc->pending = 0; - su_flow_controller_notify_force(fc); - } - } else if (fc->kind == SU_FLOW_CONTROL_KIND_MASTER_SLAVE) { - /* TODO: mark flow control as EOF if master is being unplugged */ - } -} - -SUPRIVATE SUBOOL -su_flow_controller_set_kind( - su_flow_controller_t *fc, - enum sigutils_flow_controller_kind kind) -{ - /* Cannot set flow control twice */ - if (fc->kind != SU_FLOW_CONTROL_KIND_NONE) - return SU_FALSE; - - fc->kind = kind; - - return SU_TRUE; -} - -SUPRIVATE SUSDIFF -su_flow_controller_read_unsafe( - su_flow_controller_t *fc, - struct sigutils_block_port *reader, - su_off_t off, - SUCOMPLEX *data, - SUSCOUNT size) -{ - SUSDIFF result; - - while ((result = su_stream_read(&fc->output, off, data, size)) == 0 - && fc->consumers > 1) { - /* - * We have reached the end of the stream. In the concurrent case, - * we may need to wait to repeat the read operation on the stream - */ - - switch (fc->kind) { - case SU_FLOW_CONTROL_KIND_NONE: - return SU_FLOW_CONTROLLER_ACQUIRE_ALLOWED; - - case SU_FLOW_CONTROL_KIND_BARRIER: - if (++fc->pending < fc->consumers) - /* Greedy reader. Wait for the last one */ - pthread_cond_wait(&fc->acquire_cond, &fc->acquire_lock); - else { - /* Slow reader. Let caller perform acquire() */ - fc->pending = 0; /* Reset pending counter */ - return SU_FLOW_CONTROLLER_ACQUIRE_ALLOWED; - } - - break; - - case SU_FLOW_CONTROL_KIND_MASTER_SLAVE: - if (fc->master != reader) - /* Slave must wait for master to read */ - pthread_cond_wait(&fc->acquire_cond, &fc->acquire_lock); - else - return SU_FLOW_CONTROLLER_ACQUIRE_ALLOWED; - break; - - default: - SU_ERROR("Invalid flow controller kind\n"); - return SU_FLOW_CONTROLLER_INTERNAL_ERROR; - } - - /* Wakeups may be triggered by a forced EOS condition */ - if (fc->eos) - return SU_FLOW_CONTROLLER_END_OF_STREAM; - } - - return result; -} - -/*************************** su_block_class API ******************************/ -su_block_class_t * -su_block_class_lookup(const char *name) -{ - unsigned int i; - - for (i = 0; i < class_count; ++i) { - if (strcmp(class_list[i].name, name) == 0) - return class_list + i; - } - - return NULL; -} - -SUBOOL -su_block_class_register(struct sigutils_block_class *class) -{ - su_block_class_t *tmp = NULL; - unsigned int new_storage = 0; - - if (su_block_class_lookup(class->name) != NULL) { - SU_ERROR("block class `%s' already registered\n", class->name); - return SU_FALSE; - } - - if (class_count + 1 > class_storage) { - if (class_storage == 0) - new_storage = 1; - else - new_storage = class_storage << 1; - - if ((tmp = realloc( - class_list, - new_storage * sizeof (su_block_class_t))) == NULL) { - SU_ERROR("realloc() failed\n"); - return SU_FALSE; - } - - class_list = tmp; - class_storage = new_storage; - } - - memcpy(class_list + class_count++, class, sizeof (su_block_class_t)); - - return SU_TRUE; -} - -/****************************** su_block API *********************************/ -void -su_block_destroy(su_block_t *block) -{ - unsigned int i; - su_property_t *prop; - - if (block->privdata != NULL) - block->classname->dtor(block->privdata); - - if (block->in != NULL) - free(block->in); - - if (block->out != NULL) { - for (i = 0; i < block->classname->out_size; ++i) { - su_flow_controller_finalize(&block->out[i]); - } - - free(block->out); - } - - su_property_set_finalize(&block->properties); - - free(block); -} - -su_property_t * -su_block_lookup_property(const su_block_t *block, const char *name) -{ - return su_property_set_lookup(&block->properties, name); -} - -void * -su_block_get_property_ref( - const su_block_t *block, - su_property_type_t type, - const char *name) { - const su_property_t *prop; - - if ((prop = su_block_lookup_property(block, name)) == NULL) - return NULL; - - if (type != SU_PROPERTY_TYPE_ANY && prop->type != type) - return NULL; - - return prop->generic_ptr; -} - -SUBOOL -su_block_set_property_ref( - su_block_t *block, - su_property_type_t type, - const char *name, - void *ptr) -{ - su_property_t *prop; - - if ((prop = su_property_set_assert_property(&block->properties, name, type)) - == NULL) { - SU_ERROR("Failed to assert property `%s'\n", name); - return SU_FALSE; - } - - prop->generic_ptr = ptr; - - return SU_TRUE; -} - -su_block_t * -su_block_new(const char *class_name, ...) -{ - va_list ap; - su_block_t *new = NULL; - su_block_t *result = NULL; - su_block_class_t *class; - unsigned int i; - - va_start(ap, class_name); - - if ((class = su_block_class_lookup(class_name)) == NULL) { - SU_ERROR("No block class `%s' found\n", class_name); - goto done; - } - - if ((new = calloc(1, sizeof(su_block_t))) == NULL) { - SU_ERROR("Cannot allocate block\n"); - goto done; - } - - new->classname = class; - - if (class->in_size > 0) { - if ((new->in = calloc(class->in_size, sizeof(su_block_port_t))) == NULL) { - SU_ERROR("Cannot allocate block input ports\n"); - goto done; - } - } - - if (class->out_size > 0) { - if ((new->out = calloc(class->out_size, sizeof(su_flow_controller_t))) - == NULL) { - SU_ERROR("Cannot allocate output streams\n"); - goto done; - } - } - - /* Set decimation to 1, this may be changed by block constructor */ - new->decimation = 1; - - /* Initialize object */ - if (!class->ctor(new, &new->privdata, ap)) { - SU_ERROR("Call to `%s' constructor failed\n", class_name); - goto done; - } - - if (new->decimation < 1 || new->decimation > SU_BLOCK_STREAM_BUFFER_SIZE) { - SU_ERROR("Block requested impossible decimation %d\n", new->decimation); - goto done; - } - - /* Initialize all outputs */ - for (i = 0; i < class->out_size; ++i) - if (!su_flow_controller_init( - &new->out[i], - SU_FLOW_CONTROL_KIND_NONE, - SU_BLOCK_STREAM_BUFFER_SIZE / new->decimation)) { - SU_ERROR("Cannot allocate memory for block output #%d\n", i + 1); - goto done; - } - - /* Initialize flow control */ - result = new; - -done: - if (result == NULL && new != NULL) - su_block_destroy(new); - - va_end(ap); - - return result; -} - -su_block_port_t * -su_block_get_port(const su_block_t *block, unsigned int id) -{ - if (id >= block->classname->in_size) { - return NULL; - } - - return block->in + id; -} - -su_flow_controller_t * -su_block_get_flow_controller(const su_block_t *block, unsigned int id) -{ - if (id >= block->classname->out_size) { - return NULL; - } - - return block->out + id; -} - -SUBOOL -su_block_force_eos(const su_block_t *block, unsigned int id) -{ - su_flow_controller_t *fc; - - if ((fc = su_block_get_flow_controller(block, id)) == NULL) - return SU_FALSE; - - su_flow_controller_force_eos(fc); - - return SU_TRUE; -} - -SUBOOL -su_block_set_flow_controller( - su_block_t *block, - unsigned int port_id, - enum sigutils_flow_controller_kind kind) -{ - su_flow_controller_t *fc; - - if ((fc = su_block_get_flow_controller(block, port_id)) == NULL) - return SU_FALSE; - - return su_flow_controller_set_kind(fc, kind); -} - -SUBOOL -su_block_set_master_port( - su_block_t *block, - unsigned int port_id, - const su_block_port_t *port) -{ - su_flow_controller_t *fc; - - if ((fc = su_block_get_flow_controller(block, port_id)) == NULL) - return SU_FALSE; - - if (fc->kind != SU_FLOW_CONTROL_KIND_MASTER_SLAVE) - return SU_FALSE; - - fc->master = port; - - return SU_TRUE; -} - -SUBOOL -su_block_plug( - su_block_t *source, - unsigned int out_id, - unsigned int in_id, - su_block_t *sink) -{ - su_block_port_t *input; - - if ((input = su_block_get_port(sink, in_id)) == NULL) { - SU_ERROR( - "Block `%s' doesn't have input port #%d\n", - sink->classname->name, - in_id); - return SU_FALSE; - } - - return su_block_port_plug(input, source, out_id); -} - -/************************** su_block_port API ********************************/ -SUBOOL -su_block_port_is_plugged(const su_block_port_t *port) -{ - return port->block != NULL; -} - -SUBOOL -su_block_port_plug(su_block_port_t *port, - struct sigutils_block *block, - unsigned int portid) -{ - if (su_block_port_is_plugged(port)) { - SU_ERROR( - "Port already plugged to block `%s'\n", - port->block->classname->name); - return SU_FALSE; - } - - if (portid >= block->classname->out_size) { - SU_ERROR("Block `%s' has no output #%d\n", block->classname->name, portid); - return SU_FALSE; - } - - port->port_id = portid; - port->fc = block->out + portid; - port->block = block; - - su_flow_controller_add_consumer(port->fc); - port->pos = su_flow_controller_tell(port->fc); - - return SU_TRUE; -} - -SUSDIFF -su_block_port_read(su_block_port_t *port, SUCOMPLEX *obuf, SUSCOUNT size) -{ - SUSDIFF got = 0; - SUSDIFF acquired = 0; - - if (!su_block_port_is_plugged(port)) { - SU_ERROR("Port not plugged\n"); - return SU_BLOCK_PORT_READ_ERROR_NOT_INITIALIZED; - } - - do { - su_flow_controller_enter(port->fc); - - if (port->fc->eos) { - /* EOS forced somewhere */ - su_flow_controller_leave(port->fc); - return SU_BLOCK_PORT_READ_END_OF_STREAM; - } - - /* ------8<----- ENTER CONCURRENT FLOW CONTROLLER ACCESS -----8<------ */ - port->reading = SU_TRUE; - got = su_flow_controller_read_unsafe(port->fc, port, port->pos, obuf, size); - port->reading = SU_FALSE; - - switch (got) { - case SU_FLOW_CONTROLLER_DESYNC: - port->pos = su_flow_controller_tell(port->fc); - su_flow_controller_leave(port->fc); - return SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC; - - case SU_FLOW_CONTROLLER_INTERNAL_ERROR: - case SU_FLOW_CONTROLLER_END_OF_STREAM: - su_flow_controller_leave(port->fc); - return SU_BLOCK_PORT_READ_END_OF_STREAM; - - case SU_FLOW_CONTROLLER_ACQUIRE_ALLOWED: - /* - * Stream exhausted, and flow controller allowed this thread - * to call acquire. Since this call is protected, the block - * implementation doesn't have to worry about threads. - */ - if ((acquired = port->block->classname->acquire( - port->block->privdata, - su_flow_controller_get_stream(port->block->out), - port->port_id, - port->block->in)) == -1) { - /* Acquire error */ - SU_ERROR("%s: acquire failed\n", port->block->classname->name); - /* TODO: set error condition in flow control */ - su_flow_controller_leave(port->fc); - return SU_BLOCK_PORT_READ_ERROR_ACQUIRE; - } else if (acquired == 0) { - /* Stream closed */ - /* TODO: set error condition in flow control */ - su_flow_controller_leave(port->fc); - return SU_BLOCK_PORT_READ_END_OF_STREAM; - } else { - /* Acquire succeeded, wake up all threads */ - su_flow_controller_notify(port->fc); - } - break; - - default: - if (got < 0) { - SU_ERROR("Unexpected return value %d\n", got); - su_flow_controller_leave(port->fc); - return SU_BLOCK_PORT_READ_END_OF_STREAM; - } - } - /* ------>8----- LEAVE CONCURRENT FLOW CONTROLLER ACCESS ----->8------ */ - - su_flow_controller_leave(port->fc); - - } while (got == 0); - - port->pos += got; - - return got; -} - -SUBOOL -su_block_port_resync(su_block_port_t *port) -{ - if (!su_block_port_is_plugged(port)) { - SU_ERROR("Port not plugged\n"); - return SU_FALSE; - } - - su_flow_controller_enter(port->fc); - - port->pos = su_flow_controller_tell(port->fc); - - su_flow_controller_leave(port->fc); - - return SU_TRUE; -} - -void -su_block_port_unplug(su_block_port_t *port) -{ - if (su_block_port_is_plugged(port)) { - su_flow_controller_remove_consumer(port->fc, port->reading); - port->block = NULL; - port->fc = NULL; - port->pos = 0; - port->port_id = 0; - port->reading = SU_FALSE; - } -} - diff --git a/sigutils/block.h b/sigutils/block.h index 34f7e84..9e2c488 100644 --- a/sigutils/block.h +++ b/sigutils/block.h @@ -20,12 +20,14 @@ #ifndef _SIGUTILS_BLOCK_H #define _SIGUTILS_BLOCK_H +#include #include #include #include -#include -#include "types.h" + +#include "defs.h" #include "property.h" +#include "types.h" #ifdef __cplusplus extern "C" { @@ -33,15 +35,15 @@ extern "C" { #define SU_BLOCK_STREAM_BUFFER_SIZE 4096 -#define SU_BLOCK_PORT_READ_END_OF_STREAM 0 +#define SU_BLOCK_PORT_READ_END_OF_STREAM 0 #define SU_BLOCK_PORT_READ_ERROR_NOT_INITIALIZED -1 -#define SU_BLOCK_PORT_READ_ERROR_ACQUIRE -2 -#define SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC -3 +#define SU_BLOCK_PORT_READ_ERROR_ACQUIRE -2 +#define SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC -3 -#define SU_FLOW_CONTROLLER_ACQUIRE_ALLOWED 0 -#define SU_FLOW_CONTROLLER_DESYNC -1 -#define SU_FLOW_CONTROLLER_END_OF_STREAM -2 -#define SU_FLOW_CONTROLLER_INTERNAL_ERROR -3 +#define SU_FLOW_CONTROLLER_ACQUIRE_ALLOWED 0 +#define SU_FLOW_CONTROLLER_DESYNC -1 +#define SU_FLOW_CONTROLLER_END_OF_STREAM -2 +#define SU_FLOW_CONTROLLER_INTERNAL_ERROR -3 typedef uint64_t su_off_t; @@ -51,198 +53,41 @@ struct sigutils_stream { unsigned int ptr; /* Buffer pointer */ unsigned int avail; /* Samples available for reading */ - su_off_t pos; /* Stream position */ + su_off_t pos; /* Stream position */ }; typedef struct sigutils_stream su_stream_t; -#define su_stream_INITIALIZER \ -{ \ - NULL, /* buffer */ \ - 0, /* size */ \ - 0, /* ptr */ \ - 0, /* avail */ \ - 0 /* post */ \ -} - -struct sigutils_block; - -enum sigutils_flow_controller_kind { - /* - * Default flow control: this is like having no flow control whatsoever. - * If a port reader is faster than some other, the slower one may lose - * samples as the fastest will call acquire() earlier. - */ - SU_FLOW_CONTROL_KIND_NONE = 0, - - /* - * Barrier flow control: all port users must consume their stream buffers - * before calling acquire() - */ - SU_FLOW_CONTROL_KIND_BARRIER, - - /* - * Master-slave flow control: only one port (the master) can trigger a call - * to acquire(). This is useful if the master is the slowest port, or if - * it's not critical that the slaves lose samples. - */ - SU_FLOW_CONTROL_KIND_MASTER_SLAVE, -}; - -struct sigutils_block_port; - -/* - * Flow controllers ensure safe concurrent access to block output streams. - * However, this model imposes a restriction: if non-null flow controller is - * being used, read operation on the flow controller must be performed from - * one and only one thread, otherwise deadlocks will occur. This happens - * because after the end of the output stream is reached, the read operation - * from the first port will sleep until the next port completes. However, since - * the next port is in the same thread, the next read operation will never - * take place. - */ -struct sigutils_flow_controller { - enum sigutils_flow_controller_kind kind; - SUBOOL eos; - pthread_mutex_t acquire_lock; - pthread_cond_t acquire_cond; - su_stream_t output; /* Output stream */ - unsigned int consumers; /* Number of ports plugged to this flow controller */ - unsigned int pending; /* Number of ports waiting for new data */ - const struct sigutils_block_port *master; /* Master port */ -}; - -typedef struct sigutils_flow_controller su_flow_controller_t; - -/* - * Even though flow controllers are thread-safe by definition, block ports - * are not. Don't attempt to use the same block port in different threads. - */ -struct sigutils_block_port { - su_off_t pos; /* Current reading position in this port */ - su_flow_controller_t *fc; /* Flow controller */ - struct sigutils_block *block; /* Input block */ - unsigned int port_id; - SUBOOL reading; -}; - -typedef struct sigutils_block_port su_block_port_t; - -#define su_block_port_INITIALIZER {0, NULL, NULL, SU_FALSE} - -struct sigutils_block_class { - const char *name; - unsigned int in_size; - unsigned int out_size; - - /* Generic constructor / destructor */ - SUBOOL (*ctor) (struct sigutils_block *block, void **privdata, va_list); - void (*dtor) (void *privdata); - - /* This function gets called when more data is required */ - SUSDIFF (*acquire) (void *, su_stream_t *, unsigned int, su_block_port_t *); -}; - -typedef struct sigutils_block_class su_block_class_t; - -struct sigutils_block { - /* Block overall configuration */ - su_block_class_t *classname; - su_property_set_t properties; - void *privdata; - - /* Architectural properties */ - su_block_port_t *in; /* Input ports */ - su_flow_controller_t *out; /* Output streams */ - SUSCOUNT decimation; /* Block decimation */ -}; - -typedef struct sigutils_block su_block_t; +#define su_stream_INITIALIZER \ + { \ + NULL, /* buffer */ \ + 0, /* size */ \ + 0, /* ptr */ \ + 0, /* avail */ \ + 0 /* post */ \ + } /* su_stream operations */ -SUBOOL su_stream_init(su_stream_t *stream, SUSCOUNT size); - -void su_stream_finalize(su_stream_t *stream); - -void su_stream_write(su_stream_t *stream, const SUCOMPLEX *data, SUSCOUNT size); - -SUSCOUNT su_stream_get_contiguous( - const su_stream_t *stream, +SU_CONSTRUCTOR(su_stream, SUSCOUNT size); +SU_DESTRUCTOR(su_stream); + +SU_METHOD(su_stream, void, write, const SUCOMPLEX *data, SUSCOUNT size); +SU_METHOD(su_stream, SUSCOUNT, advance_contiguous, SUSCOUNT size); +SU_GETTER( + su_stream, + SUSCOUNT, + get_contiguous, SUCOMPLEX **start, SUSCOUNT size); - -SUSCOUNT su_stream_advance_contiguous(su_stream_t *stream, SUSCOUNT size); - -su_off_t su_stream_tell(const su_stream_t *); - -SUSDIFF su_stream_read( - const su_stream_t *stream, +SU_GETTER(su_stream, su_off_t, tell); +SU_GETTER( + su_stream, + SUSDIFF, + read, su_off_t off, SUCOMPLEX *data, SUSCOUNT size); -/* su_block operations */ -su_block_t *su_block_new(const char *, ...); - -su_block_port_t *su_block_get_port(const su_block_t *, unsigned int); - -su_stream_t *su_block_get_stream(const su_block_t *, unsigned int); - -SUBOOL su_block_plug( - su_block_t *source, - unsigned int out_id, - unsigned int in_id, - su_block_t *sink); - -su_property_t *su_block_lookup_property( - const su_block_t *block, - const char *name); - -void *su_block_get_property_ref( - const su_block_t *block, - su_property_type_t type, - const char *name); - -SUBOOL su_block_set_property_ref( - su_block_t *block, - su_property_type_t type, - const char *name, - void *ptr); - -void su_block_destroy(su_block_t *); - -/* su_block_port operations */ -SUBOOL su_block_port_plug( - su_block_port_t *port, - struct sigutils_block *block, - unsigned int portid); /* Position initialized with current stream pos */ - -SUSDIFF su_block_port_read(su_block_port_t *port, SUCOMPLEX *obuf, SUSCOUNT size); - -/* Sometimes, a port connection may go out of sync. This fixes it */ -SUBOOL su_block_port_resync(su_block_port_t *port); - -SUBOOL su_block_port_is_plugged(const su_block_port_t *port); - -void su_block_port_unplug(su_block_port_t *port); - -SUBOOL su_block_force_eos(const su_block_t *block, unsigned int id); - -SUBOOL su_block_set_flow_controller( - su_block_t *block, - unsigned int port_id, - enum sigutils_flow_controller_kind kind); - -SUBOOL su_block_set_master_port( - su_block_t *block, - unsigned int port_id, - const su_block_port_t *port); - -/* su_block_class operations */ -SUBOOL su_block_class_register(struct sigutils_block_class *classname); - -su_block_class_t *su_block_class_lookup(const char *name); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/sigutils/blocks/agc.c b/sigutils/blocks/agc.c deleted file mode 100644 index 42a6841..0000000 --- a/sigutils/blocks/agc.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ -#include - -#define SU_LOG_LEVEL "agc-block" - -#include "log.h" -#include "block.h" -#include "agc.h" - -SUPRIVATE SUBOOL -su_block_agc_ctor(struct sigutils_block *block, void **private, va_list ap) -{ - SUBOOL ok = SU_FALSE; - su_agc_t *agc = NULL; - const struct su_agc_params *agc_params; - - if ((agc = calloc(1, sizeof (su_agc_t))) == NULL) { - SU_ERROR("Cannot allocate AGC state"); - goto done; - } - - agc_params = va_arg(ap, const struct su_agc_params *); - - if (!su_agc_init(agc, agc_params)) { - SU_ERROR("Failed to initialize AGC"); - goto done; - } - - ok = SU_TRUE; - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "peak", - &agc->peak); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_BOOL, - "enabled", - &agc->enabled); - -done: - if (!ok) { - if (agc != NULL) { - su_agc_finalize(agc); - free(agc); - } - } - else - *private = agc; - - return ok; -} - -SUPRIVATE void -su_block_agc_dtor(void *private) -{ - su_agc_t *agc; - - agc = (su_agc_t *) private; - - if (agc != NULL) { - su_agc_finalize(agc); - free(agc); - } -} - -SUPRIVATE SUSDIFF -su_block_agc_acquire( - void *priv, - su_stream_t *out, - unsigned int port_id, - su_block_port_t *in) -{ - su_agc_t *agc; - SUSDIFF size; - SUSDIFF got; - int i = 0; - - SUCOMPLEX *start; - - agc = (su_agc_t *) priv; - - size = su_stream_get_contiguous(out, &start, out->size); - - do { - if ((got = su_block_port_read(in, start, size)) > 0) { - /* Got data, process in place */ - for (i = 0; i < got; ++i) - start[i] = su_agc_feed(agc, start[i]); - - /* Increment position */ - if (su_stream_advance_contiguous(out, got) != got) { - SU_ERROR("Unexpected size after su_stream_advance_contiguous\n"); - return -1; - } - } else if (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC) { - SU_WARNING("AGC slow, samples lost\n"); - if (!su_block_port_resync(in)) { - SU_ERROR("Failed to resync\n"); - return -1; - } - } else if (got < 0) { - SU_ERROR("su_block_port_read: error %d\n", got); - return -1; - } - } while (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC); - - return got; -} - -struct sigutils_block_class su_block_class_AGC = { - "agc", /* name */ - 1, /* in_size */ - 1, /* out_size */ - su_block_agc_ctor, /* constructor */ - su_block_agc_dtor, /* destructor */ - su_block_agc_acquire /* acquire */ -}; diff --git a/sigutils/blocks/clock.c b/sigutils/blocks/clock.c deleted file mode 100644 index 82545f1..0000000 --- a/sigutils/blocks/clock.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ -#include - -#define SU_LOG_DOMAIN "clock-block" - -#include "log.h" - -#include "block.h" -#include "clock.h" - -SUPRIVATE SUBOOL -su_block_cdr_ctor(struct sigutils_block *block, void **private, va_list ap) -{ - SUBOOL ok = SU_FALSE; - su_clock_detector_t *clock_detector = NULL; - /* Constructor params */ - SUFLOAT loop_gain = 0; - SUFLOAT bhint = 0; - SUSCOUNT bufsiz = 0; - - if ((clock_detector = calloc(1, sizeof (su_clock_detector_t))) == NULL) { - SU_ERROR("Cannot allocate clock detector state"); - goto done; - } - - /* Variadic function calls promote floats to doubles */ - loop_gain = va_arg(ap, double); - bhint = va_arg(ap, double); - bufsiz = va_arg(ap, SUSCOUNT); - - if (!su_clock_detector_init(clock_detector, loop_gain, bhint, bufsiz)) { - SU_ERROR("Failed to initialize Costas loop"); - goto done; - } - - ok = SU_TRUE; - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "bnor", - &clock_detector->bnor); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "bmax", - &clock_detector->bmax); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "bmin", - &clock_detector->bmin); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "alpha", - &clock_detector->alpha); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "beta", - &clock_detector->beta); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "gain", - &clock_detector->gain); - -done: - if (!ok) { - if (clock_detector != NULL) { - su_clock_detector_finalize(clock_detector); - free(clock_detector); - } - } - else - *private = clock_detector; - - return ok; -} - -SUPRIVATE void -su_block_cdr_dtor(void *private) -{ - su_clock_detector_t *clock_detector; - - clock_detector = (su_clock_detector_t *) private; - - if (clock_detector != NULL) { - su_clock_detector_finalize(clock_detector); - free(clock_detector); - } -} - -SUPRIVATE SUSDIFF -su_block_cdr_acquire( - void *priv, - su_stream_t *out, - unsigned int port_id, - su_block_port_t *in) -{ - su_clock_detector_t *clock_detector; - SUSDIFF size; - SUSDIFF got; - int i = 0; - int p = 0; - SUCOMPLEX *start; - - clock_detector = (su_clock_detector_t *) priv; - - size = su_stream_get_contiguous(out, &start, out->size); - - do { - if ((got = su_block_port_read(in, start, size)) > 0) { - /* Got data, process in place */ - p = 0; - for (i = 0; i < got; ++i) { - su_clock_detector_feed(clock_detector, start[i]); - p += su_clock_detector_read(clock_detector, start + p, 1); - } - - /* Increment position */ - if (su_stream_advance_contiguous(out, p) != p) { - SU_ERROR("Unexpected size after su_stream_advance_contiguous\n"); - return -1; - } - } else if (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC) { - SU_WARNING("Clock detector slow, samples lost\n"); - if (!su_block_port_resync(in)) { - SU_ERROR("Failed to resync\n"); - return -1; - } - } else if (got < 0) { - SU_ERROR("su_block_port_read: error %d\n", got); - return -1; - } - } while (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC - || (p == 0 && got > 0)); - - return p; -} - -struct sigutils_block_class su_block_class_CDR = { - "cdr", /* name */ - 1, /* in_size */ - 1, /* out_size */ - su_block_cdr_ctor, /* constructor */ - su_block_cdr_dtor, /* destructor */ - su_block_cdr_acquire /* acquire */ -}; diff --git a/sigutils/blocks/filt.c b/sigutils/blocks/filt.c deleted file mode 100644 index ef764aa..0000000 --- a/sigutils/blocks/filt.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ -#include - -#define SU_LOG_DOMAIN "block" - -#include "log.h" - -#include "block.h" -#include "iir.h" -#include "taps.h" - -SUPRIVATE SUBOOL -su_block_rrc_ctor(struct sigutils_block *block, void **private, va_list ap) -{ - SUBOOL ok = SU_FALSE; - su_iir_filt_t *filt = NULL; - unsigned int order = 0; - SUFLOAT T = 0; - SUFLOAT beta = 0; - - if ((filt = calloc(1, sizeof (su_iir_filt_t))) == NULL) { - SU_ERROR("Cannot allocate RRC filter state\n"); - goto done; - } - - order = va_arg(ap, unsigned int); - T = va_arg(ap, double); - beta = va_arg(ap, double); - - if (!su_iir_rrc_init(filt, order, T, beta)) { - SU_ERROR("Failed to initialize RRC filter\n"); - goto done; - } - - ok = su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "gain", - &filt->gain); - -done: - if (!ok) { - if (filt != NULL) { - su_iir_filt_finalize(filt); - free(filt); - } - } - else - *private = filt; - - return ok; -} - -SUPRIVATE void -su_block_rrc_dtor(void *private) -{ - su_iir_filt_t *filt; - - filt = (su_iir_filt_t *) private; - - if (filt != NULL) { - su_iir_filt_finalize(filt); - free(filt); - } -} - -SUPRIVATE SUSDIFF -su_block_rrc_acquire( - void *priv, - su_stream_t *out, - unsigned int port_id, - su_block_port_t *in) -{ - su_iir_filt_t *filt; - SUSDIFF size; - SUSDIFF got; - int i = 0; - - SUCOMPLEX *start; - - filt = (su_iir_filt_t *) priv; - - size = su_stream_get_contiguous(out, &start, out->size); - - do { - if ((got = su_block_port_read(in, start, size)) > 0) { - /* Got data, process in place */ - for (i = 0; i < got; ++i) - start[i] = su_iir_filt_feed(filt, start[i]); - - /* Increment position */ - if (su_stream_advance_contiguous(out, got) != got) { - SU_ERROR("Unexpected size after su_stream_advance_contiguous\n"); - return -1; - } - } else if (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC) { - SU_WARNING("RRC filter slow, samples lost\n"); - if (!su_block_port_resync(in)) { - SU_ERROR("Failed to resync\n"); - return -1; - } - } else if (got < 0) { - SU_ERROR("su_block_port_read: error %d\n", got); - return -1; - } - } while (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC); - - return got; -} - -struct sigutils_block_class su_block_class_RRC = { - "rrc", /* name */ - 1, /* in_size */ - 1, /* out_size */ - su_block_rrc_ctor, /* constructor */ - su_block_rrc_dtor, /* destructor */ - su_block_rrc_acquire /* acquire */ -}; diff --git a/sigutils/blocks/pll.c b/sigutils/blocks/pll.c deleted file mode 100644 index 71c9a35..0000000 --- a/sigutils/blocks/pll.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ -#include - -#define SU_LOG_LEVEL "pll-block" - -#include "log.h" -#include "block.h" -#include "pll.h" - -SUPRIVATE SUBOOL -su_block_costas_ctor(struct sigutils_block *block, void **private, va_list ap) -{ - SUBOOL ok = SU_FALSE; - su_costas_t *costas = NULL; - /* Constructor params */ - enum sigutils_costas_kind kind; - SUFLOAT fhint = 0; - SUFLOAT arm_bw = 0; - unsigned int arm_order = 0; - SUFLOAT loop_bw = 0; - - if ((costas = calloc(1, sizeof (su_costas_t))) == NULL) { - SU_ERROR("Cannot allocate Costas loop state"); - goto done; - } - - /* Variadic function calls promote floats to doubles */ - kind = va_arg(ap, enum sigutils_costas_kind); - fhint = va_arg(ap, double); - arm_bw = va_arg(ap, double); - arm_order = va_arg(ap, unsigned int); - loop_bw = va_arg(ap, double); - - if (!su_costas_init(costas, kind, fhint, arm_bw, arm_order, loop_bw)) { - SU_ERROR("Failed to initialize Costas loop"); - goto done; - } - - ok = SU_TRUE; - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "f", - &costas->ncqo.fnor); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "lock", - &costas->lock); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "beta", - &costas->b); - -done: - if (!ok) { - if (costas != NULL) { - su_costas_finalize(costas); - free(costas); - } - } - else - *private = costas; - - return ok; -} - -SUPRIVATE void -su_block_costas_dtor(void *private) -{ - su_costas_t *costas; - - costas = (su_costas_t *) private; - - if (costas != NULL) { - su_costas_finalize(costas); - free(costas); - } -} - -SUPRIVATE SUSDIFF -su_block_costas_acquire( - void *priv, - su_stream_t *out, - unsigned int port_id, - su_block_port_t *in) -{ - su_costas_t *costas; - SUSDIFF size; - SUSDIFF got; - int i = 0; - - SUCOMPLEX *start; - - costas = (su_costas_t *) priv; - - size = su_stream_get_contiguous(out, &start, out->size); - - do { - if ((got = su_block_port_read(in, start, size)) > 0) { - /* Got data, process in place */ - for (i = 0; i < got; ++i) { - su_costas_feed(costas, start[i]); - start[i] = costas->y; - } - - /* Increment position */ - if (su_stream_advance_contiguous(out, got) != got) { - SU_ERROR("Unexpected size after su_stream_advance_contiguous\n"); - return -1; - } - } else if (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC) { - SU_WARNING("AGC slow, samples lost\n"); - if (!su_block_port_resync(in)) { - SU_ERROR("Failed to resync\n"); - return -1; - } - } else if (got < 0) { - SU_ERROR("su_block_port_read: error %d\n", got); - return -1; - } - } while (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC); - - return got; -} - -struct sigutils_block_class su_block_class_COSTAS = { - "costas", /* name */ - 1, /* in_size */ - 1, /* out_size */ - su_block_costas_ctor, /* constructor */ - su_block_costas_dtor, /* destructor */ - su_block_costas_acquire /* acquire */ -}; diff --git a/sigutils/blocks/siggen.c b/sigutils/blocks/siggen.c deleted file mode 100644 index 9c53299..0000000 --- a/sigutils/blocks/siggen.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - - Copyright (C) 2017 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ - -#include -#include - -#define SU_LOG_LEVEL "siggen-block" - -#include "log.h" -#include "block.h" - -enum su_sig_type { - SU_SIGNAL_TYPE_NULL, - SU_SIGNAL_TYPE_SINE, - SU_SIGNAL_TYPE_COSINE, - SU_SIGNAL_TYPE_SQUARE, - SU_SIGNAL_TYPE_SAWTOOTH, - SU_SIGNAL_TYPE_NOISE -}; - -struct su_sig_desc { - enum su_sig_type type; - SUFLOAT A; /* Amplitude */ - SUSCOUNT T; /* Period */ - SUSCOUNT n; /* Phase */ -}; - -struct su_siggen_state { - struct su_sig_desc i_desc; - struct su_sig_desc q_desc; -}; - -SUPRIVATE SUFLOAT -su_sig_desc_eval(const struct su_sig_desc *desc) -{ - SUFLOAT y = nan("error"); - - switch (desc->type) { - case SU_SIGNAL_TYPE_NULL: - y = 0.0; - break; - - case SU_SIGNAL_TYPE_SINE: - y = sin(2. * M_PI * (SUFLOAT) (desc->n % desc->T) / (SUFLOAT) desc->T); - break; - - case SU_SIGNAL_TYPE_COSINE: - y = cos(2. * M_PI * (SUFLOAT) (desc->n % desc->T) / (SUFLOAT) desc->T); - break; - - case SU_SIGNAL_TYPE_SQUARE: - y = desc->n >= (desc->T >> 1); - break; - - case SU_SIGNAL_TYPE_SAWTOOTH: - y = (SUFLOAT) (desc->n % desc->T) / (SUFLOAT) desc->T; - break; - - case SU_SIGNAL_TYPE_NOISE: - y = SU_C_REAL(su_c_awgn()); - break; - } - - return desc->A * y; -} - -SUPRIVATE void -su_sig_desc_advance(struct su_sig_desc *desc) -{ - ++desc->n; -} - -SUPRIVATE SUCOMPLEX -su_siggen_read(struct su_siggen_state *state) -{ - SUCOMPLEX y; - - y = su_sig_desc_eval(&state->i_desc) + I * su_sig_desc_eval(&state->q_desc); - - su_sig_desc_advance(&state->i_desc); - su_sig_desc_advance(&state->q_desc); - - return y; -} - -SUPRIVATE SUBOOL -su_block_siggen_string_to_sig_type(const char *str, enum su_sig_type *type) -{ - if (strcmp(str, "null") == 0) - *type = SU_SIGNAL_TYPE_NULL; - else if (strcmp(str, "sin") == 0) - *type = SU_SIGNAL_TYPE_SINE; - else if (strcmp(str, "cos") == 0) - *type = SU_SIGNAL_TYPE_COSINE; - else if (strcmp(str, "square") == 0) - *type = SU_SIGNAL_TYPE_SQUARE; - else if (strcmp(str, "sawtooth") == 0) - *type = SU_SIGNAL_TYPE_SAWTOOTH; - else if (strcmp(str, "noise") == 0) - *type = SU_SIGNAL_TYPE_NOISE; - else - return SU_FALSE; - - return SU_TRUE; -} - -SUPRIVATE SUBOOL -su_block_siggen_ctor(struct sigutils_block *block, void **private, va_list ap) -{ - struct su_siggen_state *state = NULL; - const char *typestr; - SUBOOL result = SU_FALSE; - - if ((state = calloc(1, sizeof (struct su_siggen_state))) == NULL) - goto done; - - typestr = va_arg(ap, const char *); - if (!su_block_siggen_string_to_sig_type(typestr, &state->i_desc.type)) { - SU_ERROR("invalid signal type `%s' for I channel\n", typestr); - goto done; - } - - state->i_desc.A = va_arg(ap, double); - state->i_desc.T = va_arg(ap, SUSCOUNT); - state->i_desc.n = va_arg(ap, SUSCOUNT); - - typestr = va_arg(ap, const char *); - if (!su_block_siggen_string_to_sig_type(typestr, &state->q_desc.type)) { - SU_ERROR("invalid signal type `%s' for Q channel\n", typestr); - goto done; - } - - state->q_desc.A = va_arg(ap, double); - state->q_desc.T = va_arg(ap, SUSCOUNT); - state->q_desc.n = va_arg(ap, SUSCOUNT); - - result = SU_TRUE; - -done: - if (result) - *private = state; - else if (state != NULL) - free(state); - - return result; -} - -SUPRIVATE void -su_block_siggen_dtor(void *private) -{ - free(private); -} - -SUPRIVATE SUSDIFF -su_block_siggen_acquire( - void *priv, - su_stream_t *out, - unsigned int port_id, - su_block_port_t *in) -{ - struct su_siggen_state *state = (struct su_siggen_state *) priv; - SUSDIFF size; - unsigned int i; - SUCOMPLEX *start; - - /* Get the number of complex samples to write */ - size = su_stream_get_contiguous(out, &start, out->size); - - for (i = 0; i < size; ++i) - start[i] = su_siggen_read(state); - - su_stream_advance_contiguous(out, size); - - return size; -} - -struct sigutils_block_class su_block_class_SIGGEN = { - "siggen", /* name */ - 0, /* in_size */ - 1, /* out_size */ - su_block_siggen_ctor, /* constructor */ - su_block_siggen_dtor, /* destructor */ - su_block_siggen_acquire, /* acquire */ -}; diff --git a/sigutils/blocks/tuner.c b/sigutils/blocks/tuner.c deleted file mode 100644 index e5d0840..0000000 --- a/sigutils/blocks/tuner.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ -#include -#include - -#define SU_LOG_LEVEL "tuner-block" - -#include "log.h" -#include "block.h" -#include "ncqo.h" -#include "iir.h" -#include "taps.h" - -/* A tuner is just a NCQO + Low pass filter */ -struct sigutils_tuner { - su_iir_filt_t bpf; /* Bandpass filter */ - su_ncqo_t lo; /* Local oscillator */ - SUFLOAT if_off; /* Intermediate frequency offset */ - - /* Filter params */ - SUFLOAT bw; /* Bandwidth */ - unsigned int h_size; /* Filter size */ - - /* Configurable params */ - SUFLOAT rq_bw; - unsigned int rq_h_size; - SUFLOAT rq_if_off; - SUFLOAT rq_fc; /* Center frequency (1 ~ fs/2), hcps */ -}; - -typedef struct sigutils_tuner su_tuner_t; - -SUPRIVATE SUBOOL -su_tuner_filter_has_changed(su_tuner_t *tu) -{ - return - tu->rq_bw != tu->bw || - tu->rq_if_off != tu->if_off || - tu->rq_h_size != tu->h_size; -} - -SUPRIVATE SUBOOL -su_tuner_lo_has_changed(su_tuner_t *tu) -{ - return su_ncqo_get_freq(&tu->lo) != tu->if_off - tu->rq_fc; -} - -SUPRIVATE SUCOMPLEX -su_tuner_feed(su_tuner_t *tu, SUCOMPLEX samp) -{ - return su_iir_filt_feed(&tu->bpf, samp * su_ncqo_read(&tu->lo)); -} - -SUPRIVATE SUCOMPLEX -su_tuner_get(const su_tuner_t *tu) -{ - return su_iir_filt_get(&tu->bpf); -} - -SUPRIVATE SUBOOL -su_tuner_update_filter(su_tuner_t *tu) -{ - su_iir_filt_t bpf_new = su_iir_filt_INITIALIZER; - - /* If baudrate has changed, we must change the LPF */ - if (!su_iir_brickwall_bp_init( - &bpf_new, - tu->rq_h_size, - tu->rq_bw, - tu->rq_if_off)) - goto fail; - - tu->bw = tu->rq_bw; - tu->h_size = tu->rq_h_size; - tu->if_off = tu->rq_if_off; - - su_iir_filt_finalize(&tu->bpf); - tu->bpf = bpf_new; - - return SU_TRUE; - -fail: - su_iir_filt_finalize(&bpf_new); - - return SU_FALSE; -} - -SUPRIVATE void -su_tuner_update_lo(su_tuner_t *tu) -{ - su_ncqo_set_freq(&tu->lo, tu->if_off - tu->rq_fc); -} - -void -su_tuner_destroy(su_tuner_t *tu) -{ - su_iir_filt_finalize(&tu->bpf); - free(tu); -} - -su_tuner_t * -su_tuner_new(SUFLOAT fc, SUFLOAT bw, SUFLOAT if_off, SUSCOUNT size) -{ - su_tuner_t *new; - - if ((new = calloc(1, sizeof (su_tuner_t))) == NULL) - goto fail; - - new->rq_fc = fc; - new->rq_bw = bw; - new->rq_if_off = if_off; - new->rq_h_size = size; - - if (!su_tuner_update_filter(new)) - goto fail; - - su_ncqo_init(&new->lo, new->rq_if_off - new->rq_fc); - - return new; - -fail: - if (new != NULL) - su_tuner_destroy(new); - - return NULL; -} - -/* Tuner constructor */ -SUPRIVATE SUBOOL -su_block_tuner_ctor(struct sigutils_block *block, void **private, va_list ap) -{ - su_tuner_t *tu = NULL; - SUBOOL ok = SU_FALSE; - SUFLOAT fc; - SUFLOAT bw; - SUFLOAT if_off; - unsigned int size; - unsigned int d; - - fc = va_arg(ap, double); - bw = va_arg(ap, double); - if_off = va_arg(ap, double); - size = va_arg(ap, SUSCOUNT); - - if ((tu = su_tuner_new(fc, bw, if_off, size)) == NULL) - goto done; - - ok = SU_TRUE; - - /* Set configurable properties */ - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "bw", - &tu->rq_bw); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "fc", - &tu->rq_fc); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "if", - &tu->rq_if_off); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_INTEGER, - "size", - &tu->rq_h_size); - - ok = ok && su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_FLOAT, - "taps", - tu->bpf.b); - -done: - if (!ok) { - if (tu != NULL) - su_tuner_destroy(tu); - } - else - *private = tu; - - return ok; -} - -/* Tuner destructor */ -SUPRIVATE void -su_block_tuner_dtor(void *private) -{ - su_tuner_t *tu = (su_tuner_t *) private; - - if (tu != NULL) { - su_tuner_destroy(tu); - } -} - -/* Acquire */ -SUPRIVATE SUSDIFF -su_block_tuner_acquire( - void *priv, - su_stream_t *out, - unsigned int port_id, - su_block_port_t *in) -{ - su_tuner_t *tu; - SUSDIFF size; - SUSDIFF got; - int i = 0; - - SUCOMPLEX *start; - - tu = (su_tuner_t *) priv; - - size = su_stream_get_contiguous(out, &start, out->size); - - do { - if ((got = su_block_port_read(in, start, size)) > 0) { - /* Got data, process in place */ - for (i = 0; i < got; ++i) - start[i] = su_tuner_feed(tu, start[i]); - - /* Increment position */ - if (su_stream_advance_contiguous(out, got) != got) { - SU_ERROR("Unexpected size after su_stream_advance_contiguous\n"); - return -1; - } - } else if (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC) { - SU_WARNING("Tuner slow, samples lost\n"); - if (!su_block_port_resync(in)) { - SU_ERROR("Failed to resync\n"); - return -1; - } - } else if (got < 0) { - SU_ERROR("su_block_port_read: error %d\n", got); - return -1; - } - } while (got == SU_BLOCK_PORT_READ_ERROR_PORT_DESYNC); - - return got; -} - -struct sigutils_block_class su_block_class_TUNER = { - "tuner", /* name */ - 1, /* in_size */ - 1, /* out_size */ - su_block_tuner_ctor, /* constructor */ - su_block_tuner_dtor, /* destructor */ - su_block_tuner_acquire /* acquire */ -}; - diff --git a/sigutils/blocks/wavfile.c b/sigutils/blocks/wavfile.c deleted file mode 100644 index bf60078..0000000 --- a/sigutils/blocks/wavfile.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ -#include -#include - -#define SU_LOG_LEVEL "wavfile-block" - -#include "log.h" -#include "block.h" - -#ifdef _SU_SINGLE_PRECISION -# define sf_read sf_read_float -#else -# define sf_read sf_read_double -#endif - -struct su_wavfile { - SF_INFO info; - SNDFILE *sf; - uint64_t samp_rate; - SUFLOAT *buffer; - SUSCOUNT size; /* Number of samples PER CHANNEL, buffer size is size * chans */ -}; - -SUPRIVATE void -su_wavfile_close(struct su_wavfile *wav) -{ - if (wav->sf != NULL) - sf_close(wav->sf); - - if (wav->buffer != NULL) - free(wav->buffer); - - free(wav); -} - -SUPRIVATE struct su_wavfile * -su_wavfile_open(const char *path) -{ - struct su_wavfile *wav = NULL; - SUBOOL ok = SU_FALSE; - - if ((wav = calloc(1, sizeof (struct su_wavfile))) == NULL) { - SU_ERROR("Cannot allocate su_wav\n"); - goto done; - } - - if ((wav->sf = sf_open(path, SFM_READ, &wav->info)) == NULL) { - SU_ERROR("Cannot open `%s': %s\n", path, sf_strerror(wav->sf)); - goto done; - } - - if (wav->info.channels > 2) { - SU_ERROR( - "Cannot open `%s': too many channels (%d)\n", - path, - wav->info.channels); - goto done; - } - - wav->size = SU_BLOCK_STREAM_BUFFER_SIZE; - if ((wav->buffer = malloc(wav->size * wav->info.channels * sizeof (SUFLOAT))) - == NULL) { - SU_ERROR("Cannot allocate sample buffer\n"); - goto done; - } - - ok = SU_TRUE; - -done: - if (!ok && wav != NULL) { - su_wavfile_close(wav); - wav = NULL; - } - - return wav; -} - -SUPRIVATE SUBOOL -su_block_wavfile_ctor(struct sigutils_block *block, void **private, va_list ap) -{ - struct su_wavfile *wav = NULL; - const char *path = NULL; - - path = va_arg(ap, const char *); - - if ((wav = su_wavfile_open(path)) == NULL) { - SU_ERROR("Constructor failed\n"); - return SU_FALSE; - } - - wav->samp_rate = wav->info.samplerate; - - if (!su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_INTEGER, - "samp_rate", - &wav->samp_rate) || - !su_block_set_property_ref( - block, - SU_PROPERTY_TYPE_INTEGER, - "channels", - &wav->info.channels)) { - su_wavfile_close(wav); - return SU_FALSE; - } - - *private = (void *) wav; - - return SU_TRUE; -} - -SUPRIVATE void -su_block_wavfile_dtor(void *private) -{ - su_wavfile_close((struct su_wavfile *) private); -} - -/* - * We process wav files as I/Q data. Left channel contains I data and - * right channel contains Q data. - */ -SUPRIVATE SUSDIFF -su_block_wavfile_acquire( - void *priv, - su_stream_t *out, - unsigned int port_id, - su_block_port_t *in) -{ - struct su_wavfile *wav = (struct su_wavfile *) priv; - SUSDIFF size; - SUSDIFF got; - unsigned int i; - SUCOMPLEX *start; - SUCOMPLEX samp; - - /* Get the number of complex samples to write */ - size = su_stream_get_contiguous(out, &start, SU_MIN(wav->size, out->size)); - - if ((got = sf_read( - wav->sf, - wav->buffer, - size * wav->info.channels)) > 0) { - if (wav->info.channels == 1) { - /* One channel: assume real data */ - for (i = 0; i < got; ++i) - start[i] = wav->buffer[i]; - } else { - /* - * Stereo: assume complex. Divide got by two, that is the number of - * complex samples to write. - */ - got >>= 1; - - for (i = 0; i < got; ++i) - start[i] = wav->buffer[i << 1] + I * wav->buffer[(i << 1) + 1]; - } - - /* Increment position */ - if (su_stream_advance_contiguous(out, got) != got) { - SU_ERROR("Unexpected size after su_stream_advance_contiguous\n"); - return -1; - } - } else if (got < 0) { - SU_ERROR("Error while reading wav file: %s\n", sf_error(wav->sf)); - return -1; - } - - return got; -} - -struct sigutils_block_class su_block_class_WAVFILE = { - "wavfile", /* name */ - 0, /* in_size */ - 1, /* out_size */ - su_block_wavfile_ctor, /* constructor */ - su_block_wavfile_dtor, /* destructor */ - su_block_wavfile_acquire, /* acquire */ -}; diff --git a/sigutils/clock.c b/sigutils/clock.c index 8a2ab2c..23c6679 100644 --- a/sigutils/clock.c +++ b/sigutils/clock.c @@ -21,22 +21,20 @@ #define SU_LOG_LEVEL "clock" -#include "log.h" #include "clock.h" - +#include "log.h" /* * Fixed sampler */ -SUBOOL -su_sampler_init(su_sampler_t *self, SUFLOAT bnor) +SU_CONSTRUCTOR(su_sampler, SUFLOAT bnor) { SU_TRYCATCH(bnor >= 0, return SU_FALSE); self->bnor = bnor; if (bnor > 0) - self->period = 1./ bnor; + self->period = 1. / bnor; else self->period = 0; @@ -47,14 +45,13 @@ su_sampler_init(su_sampler_t *self, SUFLOAT bnor) return SU_TRUE; } -SUBOOL -su_sampler_set_rate(su_sampler_t *self, SUFLOAT bnor) +SU_METHOD(su_sampler, SUBOOL, set_rate, SUFLOAT bnor) { SU_TRYCATCH(bnor >= 0, return SU_FALSE); self->bnor = bnor; if (bnor > 0) { - self->period = 1./ bnor; + self->period = 1. / bnor; if (self->phase > self->period) self->phase -= self->period * SU_FLOOR(self->phase / self->period); @@ -67,8 +64,7 @@ su_sampler_set_rate(su_sampler_t *self, SUFLOAT bnor) } /* Phase is always set in a relative fashion */ -void -su_sampler_set_phase(su_sampler_t *self, SUFLOAT phase) +SU_METHOD(su_sampler, void, set_phase, SUFLOAT phase) { if (phase > 1) phase -= SU_FLOOR(phase); @@ -76,128 +72,116 @@ su_sampler_set_phase(su_sampler_t *self, SUFLOAT phase) self->phase = self->period * phase; } -void -su_sampler_finalize(su_sampler_t *self) -{ - /* No-op */ +SU_DESTRUCTOR(su_sampler) +{ /* No-op */ } /* * Clock detector */ -void -su_clock_detector_finalize(su_clock_detector_t *cd) +SU_DESTRUCTOR(su_clock_detector) { - su_stream_finalize(&cd->sym_stream); + su_stream_finalize(&self->sym_stream); } -SUBOOL -su_clock_detector_init( - su_clock_detector_t *cd, +SU_CONSTRUCTOR( + su_clock_detector, SUFLOAT loop_gain, SUFLOAT bhint, SUSCOUNT bufsiz) { - memset(cd, 0, sizeof(su_clock_detector_t)); + memset(self, 0, sizeof(su_clock_detector_t)); - if (!su_stream_init(&cd->sym_stream, bufsiz)) { - SU_ERROR("Failed to initialize output stream\n"); - goto fail; - } + SU_CONSTRUCT_FAIL(su_stream, &self->sym_stream, bufsiz); - cd->alpha = SU_PREFERED_CLOCK_ALPHA; - cd->beta = SU_PREFERED_CLOCK_BETA; - cd->algo = SU_CLOCK_DETECTOR_ALGORITHM_GARDNER; - cd->phi = .25; - cd->bnor = bhint; - cd->bmin = 0; - cd->bmax = 1; - cd->gain = loop_gain; /* Somehow this parameter is critical */ + self->alpha = SU_PREFERED_CLOCK_ALPHA; + self->beta = SU_PREFERED_CLOCK_BETA; + self->algo = SU_CLOCK_DETECTOR_ALGORITHM_GARDNER; + self->phi = .25; + self->bnor = bhint; + self->bmin = 0; + self->bmax = 1; + self->gain = loop_gain; /* Somehow this parameter is critical */ return SU_TRUE; fail: - su_clock_detector_finalize(cd); + SU_DESTRUCT(su_clock_detector, self); return SU_FALSE; } -void -su_clock_detector_set_baud(su_clock_detector_t *cd, SUFLOAT bnor) +SU_METHOD(su_clock_detector, void, set_baud, SUFLOAT bnor) { - cd->bnor = bnor; - cd->phi = 0; - memset(cd->x, 0, sizeof(cd->x)); + self->bnor = bnor; + self->phi = 0; + memset(self->x, 0, sizeof(self->x)); } -SUBOOL -su_clock_detector_set_bnor_limits( - su_clock_detector_t *cd, - SUFLOAT lo, - SUFLOAT hi) +SU_METHOD(su_clock_detector, SUBOOL, set_bnor_limits, SUFLOAT lo, SUFLOAT hi) { if (lo > hi) { SU_ERROR("Invalid baud rate limits\n"); return SU_FALSE; } - if (cd->bnor < cd->bmin) { - cd->bnor = cd->bmin; - } else if (cd->bnor > cd->bmax) { - cd->bnor = cd->bmax; + if (self->bnor < self->bmin) { + self->bnor = self->bmin; + } else if (self->bnor > self->bmax) { + self->bnor = self->bmax; } return SU_TRUE; } -void -su_clock_detector_feed(su_clock_detector_t *cd, SUCOMPLEX val) +SU_METHOD(su_clock_detector, void, feed, SUCOMPLEX val) { SUFLOAT alpha; SUFLOAT e; SUCOMPLEX p; - if (cd->algo == SU_CLOCK_DETECTOR_ALGORITHM_NONE) { + if (self->algo == SU_CLOCK_DETECTOR_ALGORITHM_NONE) { SU_ERROR("Invalid clock detector\n"); return; } /* Increment phase */ - cd->phi += cd->bnor; + self->phi += self->bnor; - switch (cd->algo) { + switch (self->algo) { case SU_CLOCK_DETECTOR_ALGORITHM_GARDNER: - if (cd->phi >= .5) { + if (self->phi >= .5) { /* Toggle halfcycle flag */ - cd->halfcycle = !cd->halfcycle; + self->halfcycle = !self->halfcycle; /* Interpolate between this and previous sample */ - alpha = cd->bnor * (cd->phi - .5); + alpha = self->bnor * (self->phi - .5); - p = (1 - alpha) * val + alpha * cd->prev; + p = (1 - alpha) * val + alpha * self->prev; - cd->phi -= .5; - if (!cd->halfcycle) { - cd->x[2] = cd->x[0]; - cd->x[0] = p; + self->phi -= .5; + if (!self->halfcycle) { + self->x[2] = self->x[0]; + self->x[0] = p; /* Compute error signal */ - e = cd->gain * SU_C_REAL(SU_C_CONJ(cd->x[1]) * (cd->x[0] - cd->x[2])); - cd->e = e; + e = self->gain + * SU_C_REAL(SU_C_CONJ(self->x[1]) * (self->x[0] - self->x[2])); + self->e = e; /* Adjust phase and frequency */ - cd->phi += cd->alpha * e; - cd->bnor += cd->beta * e; + self->phi += self->alpha * e; + self->bnor += self->beta * e; /* Check that current baudrate is within some reasonable limits */ - if (cd->bnor > cd->bmax) - cd->bnor = cd->bmax; - if (cd->bnor < cd->bmin) - cd->bnor = cd->bmin; + if (self->bnor > self->bmax) + self->bnor = self->bmax; + if (self->bnor < self->bmin) + self->bnor = self->bmin; - su_stream_write(&cd->sym_stream, &p, 1); + su_stream_write(&self->sym_stream, &p, 1); } else { - cd->x[1] = p; + self->x[1] = p; } } break; @@ -206,23 +190,22 @@ su_clock_detector_feed(su_clock_detector_t *cd, SUCOMPLEX val) SU_ERROR("Unsupported clock detection algorithm\n"); } - cd->prev = val; + self->prev = val; } -SUSDIFF -su_clock_detector_read(su_clock_detector_t *cd, SUCOMPLEX *buf, size_t size) +SU_METHOD(su_clock_detector, SUSDIFF, read, SUCOMPLEX *buf, size_t size) { SUSDIFF result = 0; - result = su_stream_read(&cd->sym_stream, cd->sym_stream_pos, buf, size); + result = su_stream_read(&self->sym_stream, self->sym_stream_pos, buf, size); if (result < 0) { SU_WARNING("Symbols lost, resync requested\n"); - cd->sym_stream_pos = su_stream_tell(&cd->sym_stream); + self->sym_stream_pos = su_stream_tell(&self->sym_stream); result = 0; } - cd->sym_stream_pos += result; + self->sym_stream_pos += result; return result; } diff --git a/sigutils/clock.h b/sigutils/clock.h index 90538a0..741adcb 100644 --- a/sigutils/clock.h +++ b/sigutils/clock.h @@ -20,8 +20,8 @@ #ifndef _SIGUTILS_CLOCK_H #define _SIGUTILS_CLOCK_H -#include "types.h" #include "block.h" +#include "types.h" #ifdef __cplusplus extern "C" { @@ -38,23 +38,21 @@ struct sigutils_sampler { typedef struct sigutils_sampler su_sampler_t; -SUBOOL su_sampler_init(su_sampler_t *self, SUFLOAT bnor); - -SUINLINE SUFLOAT -su_sampler_get_period(const su_sampler_t *self) +SUINLINE +SU_GETTER(su_sampler, SUFLOAT, get_period) { return self->period; } -SUINLINE void -su_sampler_set_phase_addend(su_sampler_t *self, SUFLOAT addend) +SUINLINE +SU_METHOD(su_sampler, void, set_phase_addend, SUFLOAT addend) { self->phase0_rel = SU_FLOOR(addend); self->phase = self->period * self->phase0_rel; } -SUINLINE SUBOOL -su_sampler_feed(su_sampler_t *self, SUCOMPLEX *sample) +SUINLINE +SU_METHOD(su_sampler, SUBOOL, feed, SUCOMPLEX *sample) { SUBOOL sampled = SU_FALSE; SUFLOAT alpha; @@ -67,8 +65,8 @@ su_sampler_feed(su_sampler_t *self, SUCOMPLEX *sample) /* Interpolate with previous sample for improved accuracy */ if (SU_FLOOR(self->phase) == 0) { - alpha = self->phase - SU_FLOOR(self->phase); - result = (1 - alpha) * self->prev + alpha * output; + alpha = self->phase - SU_FLOOR(self->phase); + result = (1 - alpha) * self->prev + alpha * output; *sample = result; sampled = SU_TRUE; } @@ -80,9 +78,11 @@ su_sampler_feed(su_sampler_t *self, SUCOMPLEX *sample) return sampled; } -SUBOOL su_sampler_set_rate(su_sampler_t *self, SUFLOAT bnor); -void su_sampler_set_phase(su_sampler_t *self, SUFLOAT phase); -void su_sampler_finalize(su_sampler_t *self); +SU_CONSTRUCTOR(su_sampler, SUFLOAT bnor); +SU_DESTRUCTOR(su_sampler); + +SU_METHOD(su_sampler, SUBOOL, set_rate, SUFLOAT bnor); +SU_METHOD(su_sampler, void, set_phase, SUFLOAT phase); /* * The implementation of the Gardner clock recovery algorithm computes the @@ -213,9 +213,8 @@ void su_sampler_finalize(su_sampler_t *self); * Oscillation amplitude (approximate: +/-0.00001) */ - #define SU_PREFERED_CLOCK_ALPHA (2e-1) -#define SU_PREFERED_CLOCK_BETA (6e-4 * SU_PREFERED_CLOCK_ALPHA) +#define SU_PREFERED_CLOCK_BETA (6e-4 * SU_PREFERED_CLOCK_ALPHA) enum sigutils_clock_detector_algorithm { SU_CLOCK_DETECTOR_ALGORITHM_NONE, @@ -224,17 +223,17 @@ enum sigutils_clock_detector_algorithm { struct sigutils_clock_detector { enum sigutils_clock_detector_algorithm algo; - SUFLOAT alpha; /* Damping factor for phase */ - SUFLOAT beta; /* Damping factor for frequency */ - SUFLOAT bnor; /* Normalized baud rate */ - SUFLOAT bmin; /* Minimum baud rate */ - SUFLOAT bmax; /* Maximum baud rate */ - SUFLOAT phi; /* Symbol phase [0, 1/2) */ - SUFLOAT gain; /* Loop gain */ - SUFLOAT e; /* Current error signal (debugging) */ - su_stream_t sym_stream; /* Resampled signal */ - su_off_t sym_stream_pos; /* Read position in the symbol stream */ - SUBOOL halfcycle; /* True if setting halfcycle */ + SUFLOAT alpha; /* Damping factor for phase */ + SUFLOAT beta; /* Damping factor for frequency */ + SUFLOAT bnor; /* Normalized baud rate */ + SUFLOAT bmin; /* Minimum baud rate */ + SUFLOAT bmax; /* Maximum baud rate */ + SUFLOAT phi; /* Symbol phase [0, 1/2) */ + SUFLOAT gain; /* Loop gain */ + SUFLOAT e; /* Current error signal (debugging) */ + su_stream_t sym_stream; /* Resampled signal */ + su_off_t sym_stream_pos; /* Read position in the symbol stream */ + SUBOOL halfcycle; /* True if setting halfcycle */ SUCOMPLEX x[3]; /* Previous symbol */ SUCOMPLEX prev; /* Previous sample, for interpolation */ @@ -242,45 +241,35 @@ struct sigutils_clock_detector { typedef struct sigutils_clock_detector su_clock_detector_t; -#define su_clock_detector_INITIALIZER \ -{ \ - SU_CLOCK_DETECTOR_ALGORITHM_NONE, /* algo */ \ - SU_PREFERED_CLOCK_ALPHA, /* alpha */ \ - SU_PREFERED_CLOCK_BETA, /* beta */ \ - 0.0, /* bnor */ \ - 0.0, /* bmin */ \ - 1.0, /* bmax */ \ - 0.0, /* phi */ \ - 1.0, /* loop gain */ \ - 0.0, /* error signal */ \ - su_stream_INITIALIZER, /* sym_stream */ \ - 0, /* sym_stream_pos */ \ - SU_FALSE, /* halfcycle */ \ - {0, 0, 0}, /* x */ \ - 0, /* prev */ \ -} +#define su_clock_detector_INITIALIZER \ + { \ + SU_CLOCK_DETECTOR_ALGORITHM_NONE, /* algo */ \ + SU_PREFERED_CLOCK_ALPHA, /* alpha */ \ + SU_PREFERED_CLOCK_BETA, /* beta */ \ + 0.0, /* bnor */ \ + 0.0, /* bmin */ \ + 1.0, /* bmax */ \ + 0.0, /* phi */ \ + 1.0, /* loop gain */ \ + 0.0, /* error signal */ \ + su_stream_INITIALIZER, /* sym_stream */ \ + 0, /* sym_stream_pos */ \ + SU_FALSE, /* halfcycle */ \ + {0, 0, 0}, /* x */ \ + 0, /* prev */ \ + } -SUBOOL su_clock_detector_init( - su_clock_detector_t *cd, +SU_CONSTRUCTOR( + su_clock_detector, SUFLOAT loop_gain, SUFLOAT bhint, SUSCOUNT bufsiz); +SU_DESTRUCTOR(su_clock_detector); -void su_clock_detector_set_baud(su_clock_detector_t *cd, SUFLOAT bnor); - -void su_clock_detector_finalize(su_clock_detector_t *cd); - -void su_clock_detector_feed(su_clock_detector_t *cd, SUCOMPLEX val); - -SUBOOL su_clock_detector_set_bnor_limits( - su_clock_detector_t *cd, - SUFLOAT lo, - SUFLOAT hi); - -SUSDIFF su_clock_detector_read( - su_clock_detector_t *cd, - SUCOMPLEX *buf, - size_t size); +SU_METHOD(su_clock_detector, void, set_baud, SUFLOAT bnor); +SU_METHOD(su_clock_detector, void, feed, SUCOMPLEX val); +SU_METHOD(su_clock_detector, SUBOOL, set_bnor_limits, SUFLOAT lo, SUFLOAT hi); +SU_METHOD(su_clock_detector, SUSDIFF, read, SUCOMPLEX *buf, size_t size); #ifdef __cplusplus } diff --git a/sigutils/codec.c b/sigutils/codec.c deleted file mode 100644 index 937f402..0000000 --- a/sigutils/codec.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ - -#define SU_LOG_DOMAIN "codec" - -#include -#include "log.h" -#include "codec.h" - -PTR_LIST_CONST(SUPRIVATE struct sigutils_codec_class, class); - -const struct sigutils_codec_class * -su_codec_class_lookup(const char *name) -{ - unsigned int i; - - for (i = 0; i < class_count; ++i) - if (strcmp(class_list[i]->name, name) == 0) - return class_list[i]; - - return NULL; -} - -SUBOOL -su_codec_class_register(const struct sigutils_codec_class *class) -{ - SU_TRYCATCH(class->name != NULL, return SU_FALSE); - SU_TRYCATCH(class->ctor != NULL, return SU_FALSE); - SU_TRYCATCH(class->encode != NULL, return SU_FALSE); - SU_TRYCATCH(class->decode != NULL, return SU_FALSE); - SU_TRYCATCH(class->dtor != NULL, return SU_FALSE); - - SU_TRYCATCH(su_codec_class_lookup(class->name) == NULL, return SU_FALSE); - SU_TRYCATCH( - PTR_LIST_APPEND_CHECK(class, (void *) class) != -1, - return SU_FALSE); - - return SU_TRUE; -} - -void -su_codec_destroy(su_codec_t *codec) -{ - if (codec->classptr != NULL) - (codec->classptr->dtor)(codec->privdata); - - free(codec); -} - -void -su_codec_set_direction(su_codec_t *codec, enum su_codec_direction dir) -{ - codec->direction = dir; -} - -SUSYMBOL -su_codec_feed(su_codec_t *codec, SUSYMBOL x) -{ - switch (codec->direction) { - case SU_CODEC_DIRECTION_FORWARDS: - return (codec->classptr->encode) (codec, codec->privdata, x); - case SU_CODEC_DIRECTION_BACKWARDS: - return (codec->classptr->decode) (codec, codec->privdata, x); - } - - return SU_NOSYMBOL; -} - -unsigned int -su_codec_get_output_bits(const su_codec_t *codec) -{ - return codec->output_bits; -} - -su_codec_t * -su_codec_new(const char *classname, unsigned int bits, ...) -{ - su_codec_t *new = NULL; - va_list ap; - - va_start(ap, bits); - - SU_TRYCATCH(new = calloc(1, sizeof(su_codec_t)), goto fail); - - new->direction = SU_CODEC_DIRECTION_FORWARDS; - new->bits = bits; - new->output_bits = bits; /* Can be modified by ctor */ - - if ((new->classptr = su_codec_class_lookup(classname)) == NULL) { - SU_ERROR("No such codec class `%s'\n", classname); - goto fail; - } - - if (!(new->classptr->ctor) (new, &new->privdata, ap)) { - SU_ERROR("Failed to construct `%s'\n", classname); - goto fail; - } - - va_end(ap); - - return new; - -fail: - if (new != NULL) - su_codec_destroy(new); - - return NULL; -} diff --git a/sigutils/codec.h b/sigutils/codec.h deleted file mode 100644 index aab42b8..0000000 --- a/sigutils/codec.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ - -#ifndef _SIGUTILS_CODEC_H -#define _SIGUTILS_CODEC_H - -#include - -#include "types.h" - -struct sigutils_codec; - -struct sigutils_codec_class { - const char *name; - SUBOOL (*ctor) (struct sigutils_codec *, void **, va_list); - SUSYMBOL (*encode) (struct sigutils_codec *, void *, SUSYMBOL); - SUSYMBOL (*decode) (struct sigutils_codec *, void *, SUSYMBOL); - void (*dtor) (void *); -}; - -enum su_codec_direction { - SU_CODEC_DIRECTION_FORWARDS, - SU_CODEC_DIRECTION_BACKWARDS -}; - -struct sigutils_codec { - enum su_codec_direction direction; - const struct sigutils_codec_class *classptr; - unsigned int bits; - unsigned int output_bits; - void *privdata; -}; - -typedef struct sigutils_codec su_codec_t; - -SUBOOL su_codec_class_register(const struct sigutils_codec_class *classdef); - -su_codec_t *su_codec_new(const char *classname, unsigned int bits, ...); - -unsigned int su_codec_get_output_bits(const su_codec_t *codec); - -void su_codec_set_direction( - su_codec_t *codec, - enum su_codec_direction dir); - -SUSYMBOL su_codec_feed(su_codec_t *codec, SUSYMBOL x); - -void su_codec_destroy(su_codec_t *codec); - -/* Built-in codecs */ -SUBOOL su_diff_codec_register(void); - -#endif /* _SIGUTILS_CODEC_H */ diff --git a/sigutils/codecs/diff.c b/sigutils/codecs/diff.c deleted file mode 100644 index 76848a6..0000000 --- a/sigutils/codecs/diff.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ - -#include -#include - -#define SU_LOG_LEVEL "diff-codec" - -#include "log.h" -#include "../codec.h" - -struct su_diff_codec_state { - SUSYMBOL prev; - SUBOOL sign; - SUBITS mask; -}; - -SUPRIVATE SUBOOL -su_diff_codec_ctor(su_codec_t *codec, void **private, va_list ap) -{ - struct su_diff_codec_state *new; - - SU_TRYCATCH( - new = malloc(sizeof (struct su_diff_codec_state)), - return SU_FALSE); - - new->sign = va_arg(ap, SUBOOL); - new->prev = SU_NOSYMBOL; - new->mask = (1 << codec->bits) - 1; - - *private = new; - - return SU_TRUE; -} - -SUINLINE SUBITS -su_diff_codec_int(const struct su_diff_codec_state *s, SUBITS a, SUBITS b) -{ - if (s->sign) - return s->mask & (a + b); - else - return s->mask & (a - b); -} - -SUINLINE SUBITS -su_diff_codec_diff(const struct su_diff_codec_state *s, SUBITS a, SUBITS b) -{ - if (s->sign) - return s->mask & (b - a); - else - return s->mask & (a - b); -} - -SUPRIVATE SUSYMBOL -su_diff_codec_encode(su_codec_t *codec, void *private, SUSYMBOL x) -{ - struct su_diff_codec_state *state = - (struct su_diff_codec_state *) private; - SUSYMBOL y; - - if (SU_ISSYM(x)) { - if (state->prev != SU_NOSYMBOL) { - y = SU_TOSYM( - su_diff_codec_int( - state, /* Encode == Ambiguously integrate */ - SU_FROMSYM(state->prev), - SU_FROMSYM(x))); - - } else { - y = x; - } - state->prev = y; - } else { - /* When we don't receive a symbol, we must reset the stream */ - y = x; - state->prev = SU_NOSYMBOL; - } - - return y; -} - -SUPRIVATE SUSYMBOL -su_diff_codec_decode(su_codec_t *codec, void *private, SUSYMBOL x) -{ - struct su_diff_codec_state *state = - (struct su_diff_codec_state *) private; - SUSYMBOL y; - - if (SU_ISSYM(x)) { - if (state->prev != SU_NOSYMBOL) { - y = SU_TOSYM( - su_diff_codec_diff( - state, /* Decode == Unambiguously differentiate */ - SU_FROMSYM(state->prev), - SU_FROMSYM(x))); - } else { - y = SU_NOSYMBOL; - } - - state->prev = x; - } else { - /* When we don't receive a symbol, we must reset the stream */ - y = x; - state->prev = SU_NOSYMBOL; - } - - return y; -} - -SUPRIVATE void -su_diff_codec_dtor(void *private) -{ - free(private); -} - -struct sigutils_codec_class su_codec_class_DIFF = { - .name = "diff", - .ctor = su_diff_codec_ctor, - .dtor = su_diff_codec_dtor, - .encode = su_diff_codec_encode, - .decode = su_diff_codec_decode, -}; diff --git a/sigutils/coef.c b/sigutils/coef.c index fab8c22..e848f8a 100644 --- a/sigutils/coef.c +++ b/sigutils/coef.c @@ -36,11 +36,15 @@ * */ -#include +#define SU_LOG_DOMAIN "coef" + +#include #include +#include #include -#include + #include "iir.h" +#include "log.h" /********************************************************************** binomial_mult - multiplies a series of binomials together and returns @@ -82,9 +86,10 @@ su_binomial_mult(int n, const SUFLOAT *p) return NULL; for (i = 0; i < n; ++i) { - for(j = i; j > 0; --j) { + for (j = i; j > 0; --j) { a[2 * j] += p[2 * i] * a[2 * (j - 1)] - p[2 * i + 1] * a[2 * (j - 1) + 1]; - a[2 *j + 1] += p[2 * i] * a[2 * (j - 1) + 1] + p[2 * i + 1] * a[2 * (j - 1)]; + a[2 * j + 1] += + p[2 * i] * a[2 * (j - 1) + 1] + p[2 * i + 1] * a[2 * (j - 1)]; } a[0] += p[2 * i]; @@ -94,7 +99,6 @@ su_binomial_mult(int n, const SUFLOAT *p) return a; } - /********************************************************************** trinomial_mult - multiplies a series of trinomials together and returns the coefficients of the resulting polynomial. @@ -141,22 +145,20 @@ su_trinomial_mult(int n, const SUFLOAT *b, const SUFLOAT *c) a[1] = b[1]; for (i = 1; i < n; ++i) { - a[2 * (2 * i + 1)] += c[2 * i] * a[2 * (2 * i - 1)] - - c[2 * i + 1] * a[2 * (2 * i - 1) + 1]; + a[2 * (2 * i + 1)] += + c[2 * i] * a[2 * (2 * i - 1)] - c[2 * i + 1] * a[2 * (2 * i - 1) + 1]; - a[2 * (2 * i + 1) + 1] += c[2 * i] * a[2 * (2 * i - 1) + 1] - + c[2 * i + 1] * a[2 * (2 * i - 1)]; + a[2 * (2 * i + 1) + 1] += + c[2 * i] * a[2 * (2 * i - 1) + 1] + c[2 * i + 1] * a[2 * (2 * i - 1)]; for (j = 2 * i; j > 1; --j) { - a[2 * j] += b[2 * i] * a[2 * (j - 1)] - - b[2 * i + 1] * a[2 * (j - 1) + 1] - + c[2 * i] * a[2 * (j - 2)] - - c[2 * i + 1] * a[2 * (j - 2) + 1]; - - a[2 * j + 1] += b[2 * i] * a[2 * (j - 1) + 1] - + b[2 * i + 1] * a[2 * (j - 1)] - + c[2 * i] * a[2 * (j - 2) + 1] - + c[2 * i + 1] * a[2 * (j - 2)]; + a[2 * j] += b[2 * i] * a[2 * (j - 1)] - b[2 * i + 1] * a[2 * (j - 1) + 1] + + c[2 * i] * a[2 * (j - 2)] + - c[2 * i + 1] * a[2 * (j - 2) + 1]; + + a[2 * j + 1] += + b[2 * i] * a[2 * (j - 1) + 1] + b[2 * i + 1] * a[2 * (j - 1)] + + c[2 * i] * a[2 * (j - 2) + 1] + c[2 * i + 1] * a[2 * (j - 2)]; } a[2] += b[2 * i] * a[0] - b[2 * i + 1] * a[1] + c[2 * i]; @@ -168,7 +170,6 @@ su_trinomial_mult(int n, const SUFLOAT *b, const SUFLOAT *c) return a; } - /********************************************************************** dcof_bwlp - calculates the d coefficients for a butterworth lowpass filter. The coefficients are returned as an array of SUFLOATs. @@ -176,31 +177,31 @@ su_trinomial_mult(int n, const SUFLOAT *b, const SUFLOAT *c) */ SUFLOAT * -su_dcof_bwlp(int n, SUFLOAT fcf) { - int k; - SUFLOAT theta; - SUFLOAT st; - SUFLOAT ct; - SUFLOAT parg; +su_dcof_bwlp(int n, SUFLOAT fcf) +{ + int k; + SUFLOAT theta; + SUFLOAT st; + SUFLOAT ct; + SUFLOAT parg; SUFLOAT sparg; SUFLOAT cparg; - SUFLOAT a; - SUFLOAT *rcof = NULL; - SUFLOAT *dcof = NULL; + SUFLOAT a; + SUFLOAT *rcof = NULL; + SUFLOAT *dcof = NULL; - if ((rcof = malloc(2 * n * sizeof(SUFLOAT))) == NULL) - goto done; + SU_ALLOCATE_MANY(rcof, 2 * n, SUFLOAT); theta = M_PI * fcf; st = SU_SIN(theta); ct = SU_COS(theta); for (k = 0; k < n; ++k) { - parg = M_PI * (SUFLOAT) (2 * k + 1) / (SUFLOAT) (2 * n); + parg = M_PI * (SUFLOAT)(2 * k + 1) / (SUFLOAT)(2 * n); sparg = SU_SIN(parg); cparg = SU_COS(parg); - a = 1.0 + st * sparg; - rcof[2 * k] = -ct / a; + a = 1.0 + st * sparg; + rcof[2 * k] = -ct / a; rcof[2 * k + 1] = -st * cparg / a; } @@ -232,7 +233,6 @@ su_dcof_bwhp(int n, SUFLOAT fcf) return su_dcof_bwlp(n, fcf); } - /********************************************************************** dcof_bwbp - calculates the d coefficients for a butterworth bandpass filter. The coefficients are returned as an array of SUFLOATs. @@ -242,37 +242,33 @@ su_dcof_bwhp(int n, SUFLOAT fcf) SUFLOAT * su_dcof_bwbp(int n, SUFLOAT f1f, SUFLOAT f2f) { - int k; + int k; SUFLOAT theta; - SUFLOAT cp; - SUFLOAT st; - SUFLOAT ct; - SUFLOAT s2t; - SUFLOAT c2t; - SUFLOAT *rcof = NULL; - SUFLOAT *tcof = NULL; - SUFLOAT *dcof = NULL; - SUFLOAT parg; - SUFLOAT sparg; - SUFLOAT cparg; - SUFLOAT a; - - cp = SU_COS(M_PI * (f2f + f1f) / 2.0); - theta = M_PI * (f2f - f1f) / 2.0; - st = SU_SIN(theta); - ct = SU_COS(theta); - s2t = 2.0 * st * ct; - c2t = 2.0 * ct * ct - 1.0; + SUFLOAT cp; + SUFLOAT st; + SUFLOAT ct; + SUFLOAT s2t; + SUFLOAT c2t; + SUFLOAT *rcof = NULL; + SUFLOAT *tcof = NULL; + SUFLOAT *dcof = NULL; + SUFLOAT parg; + SUFLOAT sparg; + SUFLOAT cparg; + SUFLOAT a; - if ((rcof = malloc(2 * n * sizeof (SUFLOAT))) == NULL) - goto done; + cp = SU_COS(M_PI * (f2f + f1f) / 2.0); + theta = M_PI * (f2f - f1f) / 2.0; + st = SU_SIN(theta); + ct = SU_COS(theta); + s2t = 2.0 * st * ct; + c2t = 2.0 * ct * ct - 1.0; - if ((tcof = malloc(2 * n * sizeof (SUFLOAT))) == NULL) - goto done; + SU_ALLOCATE_MANY(rcof, 2 * n, SUFLOAT); + SU_ALLOCATE_MANY(tcof, 2 * n, SUFLOAT); - for (k = 0; k < n; ++k) - { - parg = M_PI * (SUFLOAT) (2 * k + 1) / (SUFLOAT) (2 * n); + for (k = 0; k < n; ++k) { + parg = M_PI * (SUFLOAT)(2 * k + 1) / (SUFLOAT)(2 * n); sparg = SU_SIN(parg); cparg = SU_COS(parg); a = 1.0 + s2t * sparg; @@ -310,36 +306,33 @@ su_dcof_bwbp(int n, SUFLOAT f1f, SUFLOAT f2f) SUFLOAT * su_dcof_bwbs(int n, SUFLOAT f1f, SUFLOAT f2f) { - int k; - SUFLOAT theta; - SUFLOAT cp; - SUFLOAT st; - SUFLOAT ct; - SUFLOAT s2t; - SUFLOAT c2t; - SUFLOAT *rcof = NULL; - SUFLOAT *tcof = NULL; - SUFLOAT *dcof = NULL; - SUFLOAT parg; - SUFLOAT sparg; - SUFLOAT cparg; - SUFLOAT a; + int k; + SUFLOAT theta; + SUFLOAT cp; + SUFLOAT st; + SUFLOAT ct; + SUFLOAT s2t; + SUFLOAT c2t; + SUFLOAT *rcof = NULL; + SUFLOAT *tcof = NULL; + SUFLOAT *dcof = NULL; + SUFLOAT parg; + SUFLOAT sparg; + SUFLOAT cparg; + SUFLOAT a; cp = SU_COS(M_PI * (f2f + f1f) / 2.0); theta = M_PI * (f2f - f1f) / 2.0; st = SU_SIN(theta); ct = SU_COS(theta); - s2t = 2.0 * st * ct; - c2t = 2.0 * ct * ct - 1.0; + s2t = 2.0 * st * ct; + c2t = 2.0 * ct * ct - 1.0; - if ((rcof = malloc(2 * n * sizeof(SUFLOAT))) == NULL) - goto done; - - if ((tcof = malloc(2 * n * sizeof(SUFLOAT))) == NULL) - goto done; + SU_ALLOCATE_MANY(rcof, 2 * n, SUFLOAT); + SU_ALLOCATE_MANY(tcof, 2 * n, SUFLOAT); for (k = 0; k < n; ++k) { - parg = M_PI * (SUFLOAT) (2 * k + 1) / (SUFLOAT) (2 * n); + parg = M_PI * (SUFLOAT)(2 * k + 1) / (SUFLOAT)(2 * n); sparg = SU_SIN(parg); cparg = SU_COS(parg); a = 1.0 + s2t * sparg; @@ -380,20 +373,19 @@ su_ccof_bwlp(int n) int m; int i; - if ((ccof = malloc((n + 1) * sizeof (SUFLOAT))) == NULL) - return NULL; + SU_ALLOCATE_MANY_CATCH(ccof, n + 1, SUFLOAT, return NULL); ccof[0] = 1; ccof[1] = n; m = n / 2; - for(i = 2; i <= m; ++i) { - ccof[i] = (n - i + 1) * (int) ccof[i - 1] / i; + for (i = 2; i <= m; ++i) { + ccof[i] = (n - i + 1) * (int)ccof[i - 1] / i; ccof[n - i] = ccof[i]; } ccof[n - 1] = n; - ccof[n] = 1; + ccof[n] = 1; return ccof; } @@ -405,7 +397,8 @@ su_ccof_bwlp(int n) */ SUFLOAT * -su_ccof_bwhp(int n) { +su_ccof_bwhp(int n) +{ SUFLOAT *ccof; int i; @@ -435,8 +428,7 @@ su_ccof_bwbp(int n) if ((tcof = su_ccof_bwhp(n)) == NULL) goto done; - if ((ccof = malloc((2 * n + 1) * sizeof (SUFLOAT))) == NULL) - goto done; + SU_ALLOCATE_MANY(ccof, 2 * n + 1, SUFLOAT); for (i = 0; i < n; ++i) { ccof[2 * i] = tcof[i]; @@ -465,10 +457,10 @@ su_ccof_bwbs(int n, SUFLOAT f1f, SUFLOAT f2f) SUFLOAT *ccof; int i, j; - alpha = -2.0 * SU_COS(M_PI * (f2f + f1f) / 2.0) / SU_COS(M_PI * (f2f - f1f) / 2.0); + alpha = -2.0 * SU_COS(M_PI * (f2f + f1f) / 2.0) + / SU_COS(M_PI * (f2f - f1f) / 2.0); - if ((ccof = malloc((2 * n + 1) * sizeof (SUFLOAT))) == NULL) - return NULL; + SU_ALLOCATE_MANY_CATCH(ccof, 2 * n + 1, SUFLOAT, return NULL); ccof[0] = 1.0; @@ -497,20 +489,19 @@ su_ccof_bwbs(int n, SUFLOAT f1f, SUFLOAT f2f) SUFLOAT su_sf_bwlp(int n, SUFLOAT fcf) { - int m, k; - SUFLOAT omega; - SUFLOAT fomega; - SUFLOAT parg0; - SUFLOAT sf; + int k; + SUFLOAT omega; + SUFLOAT fomega; + SUFLOAT parg0; + SUFLOAT sf; omega = M_PI * fcf; fomega = SU_SIN(omega); - parg0 = M_PI / (SUFLOAT) (2 * n); + parg0 = M_PI / (SUFLOAT)(2 * n); - m = n / 2; sf = 1.0; for (k = 0; k < n / 2; ++k) - sf *= 1.0 + fomega * SU_SIN((SUFLOAT) (2 * k + 1) * parg0); + sf *= 1.0 + fomega * SU_SIN((SUFLOAT)(2 * k + 1) * parg0); fomega = SU_SIN(omega / 2.0); @@ -532,21 +523,20 @@ su_sf_bwlp(int n, SUFLOAT fcf) SUFLOAT su_sf_bwhp(int n, SUFLOAT fcf) { - int m, k; - SUFLOAT omega; - SUFLOAT fomega; - SUFLOAT parg0; - SUFLOAT sf; + int k; + SUFLOAT omega; + SUFLOAT fomega; + SUFLOAT parg0; + SUFLOAT sf; omega = M_PI * fcf; fomega = SU_SIN(omega); - parg0 = M_PI / (SUFLOAT) (2 * n); + parg0 = M_PI / (SUFLOAT)(2 * n); - m = n / 2; sf = 1.0; for (k = 0; k < n / 2; ++k) - sf *= 1.0 + fomega * SU_SIN((SUFLOAT) (2 * k + 1) * parg0); + sf *= 1.0 + fomega * SU_SIN((SUFLOAT)(2 * k + 1) * parg0); fomega = SU_COS(omega / 2.0); @@ -568,27 +558,27 @@ su_sf_bwhp(int n, SUFLOAT fcf) SUFLOAT su_sf_bwbp(int n, SUFLOAT f1f, SUFLOAT f2f) { - int k; - SUFLOAT ctt; - SUFLOAT sfr, sfi; - SUFLOAT parg; - SUFLOAT sparg; - SUFLOAT cparg; - SUFLOAT a, b, c; + int k; + SUFLOAT ctt; + SUFLOAT sfr, sfi; + SUFLOAT parg; + SUFLOAT sparg; + SUFLOAT cparg; + SUFLOAT a, b, c; ctt = 1.0 / SU_TAN(M_PI * (f2f - f1f) / 2.0); sfr = 1.0; sfi = 0.0; for (k = 0; k < n; ++k) { - parg = M_PI * (SUFLOAT) (2 * k + 1) / (SUFLOAT) (2 * n); + parg = M_PI * (SUFLOAT)(2 * k + 1) / (SUFLOAT)(2 * n); sparg = ctt + SU_SIN(parg); cparg = SU_COS(parg); - a = (sfr + sfi) * (sparg - cparg); - b = sfr * sparg; - c = -sfi * cparg; - sfr = b - c; - sfi = a - b - c; + a = (sfr + sfi) * (sparg - cparg); + b = sfr * sparg; + c = -sfi * cparg; + sfr = b - c; + sfi = a - b - c; } return 1.0 / sfr; @@ -604,27 +594,27 @@ su_sf_bwbp(int n, SUFLOAT f1f, SUFLOAT f2f) SUFLOAT su_sf_bwbs(int n, SUFLOAT f1f, SUFLOAT f2f) { - int k; - SUFLOAT tt; - SUFLOAT sfr, sfi; - SUFLOAT parg; - SUFLOAT sparg; - SUFLOAT cparg; - SUFLOAT a, b, c; + int k; + SUFLOAT tt; + SUFLOAT sfr, sfi; + SUFLOAT parg; + SUFLOAT sparg; + SUFLOAT cparg; + SUFLOAT a, b, c; tt = SU_TAN(M_PI * (f2f - f1f) / 2.0); sfr = 1.0; sfi = 0.0; for (k = 0; k < n; ++k) { - parg = M_PI * (SUFLOAT)(2 * k + 1)/(SUFLOAT)(2 * n); + parg = M_PI * (SUFLOAT)(2 * k + 1) / (SUFLOAT)(2 * n); sparg = tt + SU_SIN(parg); cparg = SU_COS(parg); - a = (sfr + sfi) * (sparg - cparg); - b = sfr * sparg; - c = -sfi * cparg; - sfr = b - c; - sfi = a - b - c; + a = (sfr + sfi) * (sparg - cparg); + b = sfr * sparg; + c = -sfi * cparg; + sfr = b - c; + sfi = a - b - c; } return 1.0 / sfr; diff --git a/sigutils/decider.h b/sigutils/decider.h index 077d6cd..9e9b24f 100644 --- a/sigutils/decider.h +++ b/sigutils/decider.h @@ -20,6 +20,7 @@ #ifndef _DECIDER_H #define _DECIDER_H +#include "defs.h" #include "types.h" struct sigutils_decider_params { @@ -28,26 +29,28 @@ struct sigutils_decider_params { unsigned int bits; }; -#define sigutils_decider_params_INITIALIZER \ -{ \ - -PI, /* min_val */ \ - PI, /* max_val */ \ - 1, /* bits */ \ -} +#define sigutils_decider_params_INITIALIZER \ + { \ + -PI, /* min_val */ \ + PI, /* max_val */ \ + 1, /* bits */ \ + } struct sigutils_decider { struct sigutils_decider_params params; SUFLOAT width; SUFLOAT h_inv; /* 2 ^ bits / width */ - SUBITS mask; + SUBITS mask; }; typedef struct sigutils_decider su_decider_t; +SU_GETTER(su_decider, const struct sigutils_decider_params *, get_params); + const struct sigutils_decider_params * -su_decider_get_params(const su_decider_t *decider) +su_decider_get_params(const su_decider_t *self) { - return &decider->params; + return &self->params; } SUBOOL @@ -79,7 +82,7 @@ su_decider_decide(const su_decider_t *decider, SUFLOAT x) else if (x >= decider->width) return decider->mask; else - return (SUBITS) SU_FLOOR(x * decider->h_inv); + return (SUBITS)SU_FLOOR(x * decider->h_inv); } SUINLINE SUBITS @@ -87,7 +90,7 @@ su_decider_decide_cyclic(const su_decider_t *decider, SUFLOAT x) { x -= decider->params.min_val; - return decider->mask & (SUBITS) SU_FLOOR(x * decider->h_inv); + return decider->mask & (SUBITS)SU_FLOOR(x * decider->h_inv); } #endif /* _DECIDER_H */ diff --git a/sigutils/defs.h b/sigutils/defs.h new file mode 100644 index 0000000..a3a9241 --- /dev/null +++ b/sigutils/defs.h @@ -0,0 +1,143 @@ +/* + + Copyright (C) 2021 Gonzalo José Carracedo Carballal + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + + +*/ + +#ifndef _SIGUTILS_DEFS_H +#define _SIGUTILS_DEFS_H + +#include + +#ifndef su_calloc +# define su_calloc(len, size) calloc(len, size) +#endif /* su_calloc */ + +#ifndef su_free +# define su_free(ptr) free(ptr) +#endif /* su_free */ + +#ifndef su_malloc +# define su_malloc(size) malloc(size) +#endif /* su_malloc */ + +#define SU_TYPENAME(class) JOIN(class, _t) +#define SU_METHOD_NAME(class, name) JOIN(class, JOIN(_, name)) +#define SU_METHOD(class, ret, name, ...) \ + ret SU_METHOD_NAME(class, name)(SU_TYPENAME(class) * self, ##__VA_ARGS__) + +#define SU_METHOD_CONST(class, ret, name, ...) \ + ret SU_METHOD_NAME(class, name)( \ + const SU_TYPENAME(class) * self, \ + ##__VA_ARGS__) + +#define SU_GETTER SU_METHOD_CONST + +#define SU_CONSTRUCTOR_TYPED(ret, class, ...) \ + ret SU_METHOD_NAME(class, init)(SU_TYPENAME(class) * self, ##__VA_ARGS__) + +#define SU_CONSTRUCTOR(class, ...) \ + SU_CONSTRUCTOR_TYPED(SUBOOL, class, ##__VA_ARGS__) + +#define SU_DESTRUCTOR(class) \ + void SU_METHOD_NAME(class, finalize)(SU_TYPENAME(class) * self) + +#define SU_INSTANCER(class, ...) \ + SU_TYPENAME(class) * SU_METHOD_NAME(class, new)(__VA_ARGS__) + +#define SU_COPY_INSTANCER(class, ...) \ + SU_METHOD_CONST(class, SU_TYPENAME(class) *, dup, ##__VA_ARGS__) + +#define SU_COLLECTOR(class) \ + void SU_METHOD_NAME(class, destroy)(SU_TYPENAME(class) * self) + +#define SU_ALLOCATE_MANY_CATCH(dest, len, type, action) \ + if ((dest = su_calloc(len, sizeof(type))) == NULL) { \ + SU_ERROR( \ + "failed to allocate %d objects of type \"%s\"\n", \ + len, \ + STRINGIFY(type)); \ + action; \ + } + +#define SU_ALLOCATE_CATCH(dest, type, action) \ + if ((dest = su_calloc(1, sizeof(type))) == NULL) { \ + SU_ERROR( \ + "failed to allocate one object of type \"%s\"\n", \ + STRINGIFY(type)); \ + action; \ + } + +#define SU_MAKE_CATCH(dest, class, action, ...) \ + if ((dest = JOIN(class, _new)(__VA_ARGS__)) == NULL) { \ + SU_ERROR("failed to create instance of class \"%s\"\n", STRINGIFY(class)); \ + action; \ + } + +#define SU_CONSTRUCT_CATCH(class, dest, action, arg...) \ + if (!JOIN(class, _init)(dest, ##arg)) { \ + SU_ERROR( \ + "failed to call constructor of class \"%s\"\n", \ + STRINGIFY(class)); \ + action; \ + } + +#define SU_DESTRUCT(class, dest) JOIN(class, _finalize)(dest) +#define SU_DISPOSE(class, dest) JOIN(class, _destroy)(dest) + +#define SU_TRYCATCH(expr, action) \ + if (!(expr)) { \ + SU_ERROR( \ + "exception in \"%s\" (%s:%d)\n", \ + STRINGIFY(expr), \ + __FILENAME__, \ + __LINE__); \ + action; \ + } + +/* Macros for "goto done" style error recovery */ +#define SU_TRY(expr) SU_TRYCATCH(expr, goto done) +#define SU_TRYC(expr) SU_TRY((expr) != -1) +#define SU_TRYZ(expr) SU_TRY((expr) == 0) + +#define SU_ALLOCATE_MANY(dest, len, type) \ + SU_ALLOCATE_MANY_CATCH(dest, len, type, goto done) + +#define SU_ALLOCATE(dest, type) SU_ALLOCATE_CATCH(dest, type, goto done) + +#define SU_MAKE(dest, class, ...) \ + SU_MAKE_CATCH(dest, class, goto done, __VA_ARGS__) + +#define SU_CONSTRUCT(class, dest, arg...) \ + SU_CONSTRUCT_CATCH(class, dest, goto done, ##arg) + +/* Macros for "goto fail" style error recovery */ +#define SU_TRY_FAIL(expr) SU_TRYCATCH(expr, goto fail) +#define SU_TRYC_FAIL(expr) SU_TRY_FAIL((expr) != -1) +#define SU_TRYZ_FAIL(expr) SU_TRY_FAIL((expr) == 0) + +#define SU_ALLOCATE_MANY_FAIL(dest, len, type) \ + SU_ALLOCATE_MANY_CATCH(dest, len, type, goto fail) + +#define SU_ALLOCATE_FAIL(dest, type) SU_ALLOCATE_CATCH(dest, type, goto fail) + +#define SU_MAKE_FAIL(dest, class, ...) \ + SU_MAKE_CATCH(dest, class, goto fail, __VA_ARGS__) + +#define SU_CONSTRUCT_FAIL(class, dest, arg...) \ + SU_CONSTRUCT_CATCH(class, dest, goto fail, ##arg) + +#endif /* _SIGUTILS_DEFS_H */ diff --git a/sigutils/detect.c b/sigutils/detect.c index 0791e0c..88f7f13 100644 --- a/sigutils/detect.c +++ b/sigutils/detect.c @@ -17,38 +17,35 @@ */ -#include - #include "detect.h" +#include + +#include "assert.h" #include "sampling.h" #include "taps.h" -#include "assert.h" -SUBOOL -su_peak_detector_init(su_peak_detector_t *pd, unsigned int size, SUFLOAT thres) +SU_CONSTRUCTOR(su_peak_detector, unsigned int size, SUFLOAT thres) { SUFLOAT *history; - assert(pd != NULL); + assert(self != NULL); assert(size > 0); - if ((history = malloc(size * sizeof (SUFLOAT))) == NULL) - return SU_FALSE; + SU_ALLOCATE_MANY_CATCH(history, size, SUFLOAT, return SU_FALSE); - pd->size = size; - pd->thr2 = thres * thres; - pd->history = history; - pd->p = 0; - pd->count = 0; - pd->accum = 0.0; - pd->inv_size = 1. / size; + self->size = size; + self->thr2 = thres * thres; + self->history = history; + self->p = 0; + self->count = 0; + self->accum = 0.0; + self->inv_size = 1. / size; return SU_TRUE; } -int -su_peak_detector_feed(su_peak_detector_t *pd, SUFLOAT x) +SU_METHOD(su_peak_detector, int, feed, SUFLOAT x) { SUFLOAT mean; SUFLOAT variance = .0; @@ -67,47 +64,45 @@ su_peak_detector_feed(su_peak_detector_t *pd, SUFLOAT x) * 0, 1 or -1 accordingly. */ - if (pd->count < pd->size) { + if (self->count < self->size) { /* Populate */ - pd->history[pd->count++] = x; + self->history[self->count++] = x; } else { - mean = pd->inv_size * pd->accum; + mean = self->inv_size * self->accum; /* Compute variance */ - for (i = 0; i < pd->size; ++i) { - d = pd->history[i] - mean; + for (i = 0; i < self->size; ++i) { + d = self->history[i] - mean; variance += d * d; } - variance *= pd->inv_size; + variance *= self->inv_size; x2 = x - mean; x2 *= x2; - threshold = pd->thr2 * variance; + threshold = self->thr2 * variance; if (x2 > threshold) { peak = x > mean ? 1 : -1; } - /* Remove last sample from accumulator */ - pd->accum -= pd->history[pd->p]; - pd->history[pd->p++] = x; + self->accum -= self->history[self->p]; + self->history[self->p++] = x; - if (pd->p == pd->size) - pd->p = 0; /* Rollover */ + if (self->p == self->size) + self->p = 0; /* Rollover */ } - pd->accum += x; + self->accum += x; return peak; } -void -su_peak_detector_finalize(su_peak_detector_t *pd) +SU_DESTRUCTOR(su_peak_detector) { - if (pd->history != NULL) - free(pd->history); + if (self->history != NULL) + free(self->history); } /* @@ -142,181 +137,181 @@ su_peak_detector_finalize(su_peak_detector_t *pd) * be reset and start again. */ -struct sigutils_channel * -su_channel_dup(const struct sigutils_channel *channel) +SU_COPY_INSTANCER(su_channel) { - struct sigutils_channel *new = NULL; + su_channel_t *new = NULL; - if ((new = malloc(sizeof(struct sigutils_channel))) == NULL) - return NULL; + SU_ALLOCATE_FAIL(new, su_channel_t); - memcpy(new, channel, sizeof(struct sigutils_channel)); + memcpy(new, self, sizeof(su_channel_t)); return new; + +fail: + if (new != NULL) + SU_DISPOSE(su_channel, new); + return NULL; } -void -su_channel_destroy(struct sigutils_channel *channel) +SU_COLLECTOR(su_channel) { - free(channel); + free(self); } -SUPRIVATE void -su_channel_detector_channel_list_clear(su_channel_detector_t *detector) +SUPRIVATE +SU_METHOD(su_channel_detector, void, channel_list_clear) { struct sigutils_channel *chan; - FOR_EACH_PTR(chan, detector, channel) - su_channel_destroy(chan); + FOR_EACH_PTR(chan, self, channel) + SU_DISPOSE(su_channel, chan); - if (detector->channel_list != NULL) - free(detector->channel_list); + if (self->channel_list != NULL) + free(self->channel_list); - detector->channel_count = 0; - detector->channel_list = NULL; + self->channel_count = 0; + self->channel_list = NULL; } -SUPRIVATE void -su_channel_detector_channel_collect(su_channel_detector_t *detector) +SUPRIVATE +SU_METHOD(su_channel_detector, void, channel_collect) { unsigned int i; - for (i = 0; i < detector->channel_count; ++i) - if (detector->channel_list[i] != NULL) - if (detector->channel_list[i]->age++ - > 2 * detector->channel_list[i]->present) { - su_channel_destroy(detector->channel_list[i]); - detector->channel_list[i] = NULL; + for (i = 0; i < self->channel_count; ++i) + if (self->channel_list[i] != NULL) + if (self->channel_list[i]->age++ > 2 * self->channel_list[i]->present) { + su_channel_destroy(self->channel_list[i]); + self->channel_list[i] = NULL; } } -struct sigutils_channel * -su_channel_detector_lookup_channel( - const su_channel_detector_t *detector, - SUFLOAT fc) +SU_GETTER(su_channel_detector, su_channel_t *, lookup_channel, SUFLOAT fc) { - struct sigutils_channel *chan; + su_channel_t *chan; - FOR_EACH_PTR(chan, detector, channel) - if (fc >= chan->fc - chan->bw * .5 && - fc <= chan->fc + chan->bw * .5) - return chan; + FOR_EACH_PTR(chan, self, channel) + if (fc >= chan->fc - chan->bw * .5 && fc <= chan->fc + chan->bw * .5) + return chan; return NULL; } -struct sigutils_channel * -su_channel_detector_lookup_valid_channel( - const su_channel_detector_t *detector, - SUFLOAT fc) +SU_GETTER(su_channel_detector, su_channel_t *, lookup_valid_channel, SUFLOAT fc) { - struct sigutils_channel *chan; + su_channel_t *chan; - FOR_EACH_PTR(chan, detector, channel) - if (SU_CHANNEL_IS_VALID(chan)) - if (fc >= chan->fc - chan->bw * .5 && - fc <= chan->fc + chan->bw * .5) - return chan; + FOR_EACH_PTR(chan, self, channel) + if (SU_CHANNEL_IS_VALID(chan)) + if (fc >= chan->fc - chan->bw * .5 && fc <= chan->fc + chan->bw * .5) + return chan; return NULL; } SUPRIVATE SUBOOL su_channel_detector_assert_channel( - su_channel_detector_t *detector, + su_channel_detector_t *self, const struct sigutils_channel *new) { - struct sigutils_channel *chan = NULL; + su_channel_t *chan = NULL, *owned = NULL; SUFLOAT k = .5; + SUBOOL ok = SU_FALSE; - if ((chan = su_channel_detector_lookup_channel(detector, new->fc)) == NULL) { - if ((chan = calloc(1, sizeof (struct sigutils_channel))) == NULL) - return SU_FALSE; + if ((chan = su_channel_detector_lookup_channel(self, new->fc)) == NULL) { + SU_ALLOCATE(owned, su_channel_t); - chan->bw = new->bw; - chan->fc = new->fc; - chan->f_lo = new->f_lo; - chan->f_hi = new->f_hi; + owned->bw = new->bw; + owned->fc = new->fc; + owned->f_lo = new->f_lo; + owned->f_hi = new->f_hi; - if (PTR_LIST_APPEND_CHECK(detector->channel, chan) == -1) { - su_channel_destroy(chan); - return SU_FALSE; - } + SU_TRYC(PTR_LIST_APPEND_CHECK(self->channel, owned)); + + chan = owned; + owned = NULL; } else { chan->present++; if (chan->age > 20) - k /= (chan->age - 20); + k /= (chan->age - 20); /* The older the channel is, the harder it must be to change its params */ - chan->bw += 1. / (chan->age + 1) * (new->bw - chan->bw); + chan->bw += 1. / (chan->age + 1) * (new->bw - chan->bw); chan->f_lo += 1. / (chan->age + 1) * (new->f_lo - chan->f_lo); chan->f_hi += 1. / (chan->age + 1) * (new->f_hi - chan->f_hi); - chan->fc += 1. / (chan->age + 1) * (new->fc - chan->fc); + chan->fc += 1. / (chan->age + 1) * (new->fc - chan->fc); } /* Signal levels are instantaneous values. Cannot average */ - chan->S0 = new->S0; - chan->N0 = new->N0; - chan->snr = new->S0 - new->N0; + chan->S0 = new->S0; + chan->N0 = new->N0; + chan->snr = new->S0 - new->N0; - return SU_TRUE; + ok = SU_TRUE; + +done: + if (owned != NULL) + SU_DISPOSE(su_channel, owned); + + return ok; } -void -su_channel_detector_destroy(su_channel_detector_t *detector) +SU_COLLECTOR(su_channel_detector) { - if (detector->fft_plan != NULL) - SU_FFTW(_destroy_plan)(detector->fft_plan); + if (self->fft_plan != NULL) + SU_FFTW(_destroy_plan)(self->fft_plan); - if (detector->fft_plan_rev != NULL) - SU_FFTW(_destroy_plan)(detector->fft_plan_rev); + if (self->fft_plan_rev != NULL) + SU_FFTW(_destroy_plan)(self->fft_plan_rev); - if (detector->window != NULL) - SU_FFTW(_free)(detector->window); + if (self->window != NULL) + SU_FFTW(_free)(self->window); - if (detector->window_func != NULL) - SU_FFTW(_free)(detector->window_func); + if (self->window_func != NULL) + SU_FFTW(_free)(self->window_func); - if (detector->fft != NULL) - SU_FFTW(_free)(detector->fft); + if (self->fft != NULL) + SU_FFTW(_free)(self->fft); - if (detector->ifft != NULL) - SU_FFTW(_free)(detector->ifft); + if (self->ifft != NULL) + SU_FFTW(_free)(self->ifft); - if (detector->_r_alloc != NULL) - free(detector->_r_alloc); + if (self->_r_alloc != NULL) + free(self->_r_alloc); - if (detector->spmax != NULL) - free(detector->spmax); + if (self->spmax != NULL) + free(self->spmax); - if (detector->spmin != NULL) - free(detector->spmin); + if (self->spmin != NULL) + free(self->spmin); - su_channel_detector_channel_list_clear(detector); + su_channel_detector_channel_list_clear(self); - su_softtuner_finalize(&detector->tuner); + SU_DESTRUCT(su_softtuner, &self->tuner); - if (detector->tuner_buf != NULL) - free(detector->tuner_buf); + if (self->tuner_buf != NULL) + free(self->tuner_buf); - su_peak_detector_finalize(&detector->pd); + SU_DESTRUCT(su_peak_detector, &self->pd); - free(detector); + free(self); } -void -su_channel_detector_get_channel_list( - const su_channel_detector_t *detector, +SU_GETTER( + su_channel_detector, + void, + get_channel_list, struct sigutils_channel ***channel_list, unsigned int *channel_count) { - *channel_list = detector->channel_list; - *channel_count = detector->channel_count; + *channel_list = self->channel_list; + *channel_count = self->channel_count; } -SUBOOL -su_channel_detector_set_params( - su_channel_detector_t *detector, +SU_METHOD( + su_channel_detector, + SUBOOL, + set_params, const struct sigutils_channel_detector_params *params) { SU_TRYCATCH(params->alpha > .0, return SU_FALSE); @@ -327,72 +322,70 @@ su_channel_detector_set_params( * New window_size settings requires re-allocating all FFTW objects. It's * better off if we just create a new detector object */ - if (params->window_size != detector->params.window_size) + if (params->window_size != self->params.window_size) return SU_FALSE; /* * Different window functions also require different preallocated * buffers. */ - if (params->window != detector->params.window) + if (params->window != self->params.window) return SU_FALSE; /* Changing the detector bandwidth implies recreating the antialias filter */ - if (params->bw != detector->params.bw) + if (params->bw != self->params.bw) return SU_FALSE; /* * Changing the sample rate if an antialias filter has been set also * requires re-allocation. */ - if (params->bw > 0.0 && params->samp_rate != detector->params.samp_rate) + if (params->bw > 0.0 && params->samp_rate != self->params.samp_rate) return SU_FALSE; /* It's okay to change the parameters now */ - detector->params = *params; + self->params = *params; /* Initialize local oscillator */ if (params->tune) - su_channel_detector_set_fc(&detector->tuner, params->fc); + su_channel_detector_set_fc(&self->tuner, params->fc); return SU_TRUE; } -SUINLINE SUBOOL -su_channel_detector_init_window_func(su_channel_detector_t *detector) +SUINLINE +SU_METHOD(su_channel_detector, SUBOOL, init_window_func) { unsigned int i; - for (i = 0; i < detector->params.window_size; ++i) - detector->window_func[i] = 1; + for (i = 0; i < self->params.window_size; ++i) + self->window_func[i] = 1; - switch (detector->params.window) { + switch (self->params.window) { case SU_CHANNEL_DETECTOR_WINDOW_NONE: /* Do nothing. */ break; case SU_CHANNEL_DETECTOR_WINDOW_HAMMING: su_taps_apply_hamming_complex( - detector->window_func, - detector->params.window_size); + self->window_func, + self->params.window_size); break; case SU_CHANNEL_DETECTOR_WINDOW_HANN: - su_taps_apply_hann_complex( - detector->window_func, - detector->params.window_size); + su_taps_apply_hann_complex(self->window_func, self->params.window_size); break; case SU_CHANNEL_DETECTOR_WINDOW_FLAT_TOP: su_taps_apply_flat_top_complex( - detector->window_func, - detector->params.window_size); + self->window_func, + self->params.window_size); break; case SU_CHANNEL_DETECTOR_WINDOW_BLACKMANN_HARRIS: su_taps_apply_blackmann_harris_complex( - detector->window_func, - detector->params.window_size); + self->window_func, + self->params.window_size); break; default: @@ -400,51 +393,51 @@ su_channel_detector_init_window_func(su_channel_detector_t *detector) * This surely will generate thousands of messages, but it should * never happen either */ - SU_WARNING("Unsupported window function %d\n", detector->params.window); + SU_WARNING("Unsupported window function %d\n", self->params.window); return SU_FALSE; } return SU_TRUE; } -su_channel_detector_t * -su_channel_detector_new(const struct sigutils_channel_detector_params *params) +SU_INSTANCER( + su_channel_detector, + const struct sigutils_channel_detector_params *params) { su_channel_detector_t *new = NULL; - struct sigutils_softtuner_params tuner_params - = sigutils_softtuner_params_INITIALIZER; + struct sigutils_softtuner_params tuner_params = + sigutils_softtuner_params_INITIALIZER; assert(params->alpha > .0); assert(params->samp_rate > 0); assert(params->window_size > 0); assert(params->decimation > 0); - if ((new = calloc(1, sizeof (su_channel_detector_t))) == NULL) - goto fail; + SU_ALLOCATE_FAIL(new, su_channel_detector_t); new->params = *params; - if ((new->window - = SU_FFTW(_malloc)( - params->window_size * sizeof(SU_FFTW(_complex)))) == NULL) { + if ((new->window = + SU_FFTW(_malloc)(params->window_size * sizeof(SU_FFTW(_complex)))) + == NULL) { SU_ERROR("cannot allocate memory for window\n"); goto fail; } memset(new->window, 0, params->window_size * sizeof(SU_FFTW(_complex))); - if ((new->window_func - = SU_FFTW(_malloc)( - params->window_size * sizeof(SU_FFTW(_complex)))) == NULL) { + if ((new->window_func = + SU_FFTW(_malloc)(params->window_size * sizeof(SU_FFTW(_complex)))) + == NULL) { SU_ERROR("cannot allocate memory for window function\n"); goto fail; } SU_TRYCATCH(su_channel_detector_init_window_func(new), goto fail); - if ((new->fft - = SU_FFTW(_malloc)( - params->window_size * sizeof(SU_FFTW(_complex)))) == NULL) { + if ((new->fft = + SU_FFTW(_malloc)(params->window_size * sizeof(SU_FFTW(_complex)))) + == NULL) { SU_ERROR("cannot allocate memory for FFT\n"); goto fail; } @@ -455,19 +448,16 @@ su_channel_detector_new(const struct sigutils_channel_detector_params *params) * Generic result allocation: the same buffer is used differently depending * on the detector mode */ - if ((new->_r_alloc - = calloc(params->window_size, sizeof(SUFLOAT))) == NULL) { - SU_ERROR("cannot allocate memory for averaged FFT\n"); - goto fail; - } + SU_ALLOCATE_MANY_FAIL(new->_r_alloc, params->window_size, SUFLOAT); /* Direct FFT plan */ if ((new->fft_plan = SU_FFTW(_plan_dft_1d)( - params->window_size, - new->window, - new->fft, - FFTW_FORWARD, - FFTW_ESTIMATE)) == NULL) { + params->window_size, + new->window, + new->fft, + FFTW_FORWARD, + FFTW_ESTIMATE)) + == NULL) { SU_ERROR("failed to create FFT plan\n"); goto fail; } @@ -480,14 +470,12 @@ su_channel_detector_new(const struct sigutils_channel_detector_params *params) case SU_CHANNEL_DETECTOR_MODE_DISCOVERY: /* Discovery mode requires these max/min levels */ - if ((new->spmax - = calloc(params->window_size, sizeof(SUFLOAT))) == NULL) { + if ((new->spmax = calloc(params->window_size, sizeof(SUFLOAT))) == NULL) { SU_ERROR("cannot allocate memory for max\n"); goto fail; } - if ((new->spmin - = calloc(params->window_size, sizeof(SUFLOAT))) == NULL) { + if ((new->spmin = calloc(params->window_size, sizeof(SUFLOAT))) == NULL) { SU_ERROR("cannot allocate memory for min\n"); goto fail; } @@ -495,9 +483,9 @@ su_channel_detector_new(const struct sigutils_channel_detector_params *params) case SU_CHANNEL_DETECTOR_MODE_AUTOCORRELATION: /* For inverse FFT */ - if ((new->ifft - = SU_FFTW(_malloc)( - params->window_size * sizeof(SU_FFTW(_complex)))) == NULL) { + if ((new->ifft = SU_FFTW(_malloc)( + params->window_size * sizeof(SU_FFTW(_complex)))) + == NULL) { SU_ERROR("cannot allocate memory for IFFT\n"); goto fail; } @@ -505,11 +493,12 @@ su_channel_detector_new(const struct sigutils_channel_detector_params *params) memset(new->ifft, 0, params->window_size * sizeof(SU_FFTW(_complex))); if ((new->fft_plan_rev = SU_FFTW(_plan_dft_1d)( - params->window_size, - new->fft, - new->ifft, - FFTW_BACKWARD, - FFTW_ESTIMATE)) == NULL) { + params->window_size, + new->fft, + new->ifft, + FFTW_BACKWARD, + FFTW_ESTIMATE)) + == NULL) { SU_ERROR("failed to create FFT plan\n"); goto fail; } @@ -527,22 +516,19 @@ su_channel_detector_new(const struct sigutils_channel_detector_params *params) /* Initialize tuner (if enabled) */ if (params->tune) { - SU_TRYCATCH( - new->tuner_buf = malloc( - SU_BLOCK_STREAM_BUFFER_SIZE * sizeof (SUCOMPLEX)), - goto fail); - - memset( + SU_ALLOCATE_MANY_FAIL( new->tuner_buf, - 0, - SU_BLOCK_STREAM_BUFFER_SIZE * sizeof (SUCOMPLEX)); + SU_BLOCK_STREAM_BUFFER_SIZE, + SUCOMPLEX); + + memset(new->tuner_buf, 0, SU_BLOCK_STREAM_BUFFER_SIZE * sizeof(SUCOMPLEX)); tuner_params.fc = params->fc; tuner_params.bw = params->bw; tuner_params.samp_rate = params->samp_rate; tuner_params.decimation = params->decimation; - SU_TRYCATCH(su_softtuner_init(&new->tuner, &tuner_params), goto fail); + SU_CONSTRUCT_FAIL(su_softtuner, &new->tuner, &tuner_params); } /* Calculate the required number of samples to perform detection */ @@ -552,20 +538,19 @@ su_channel_detector_new(const struct sigutils_channel_detector_params *params) fail: if (new != NULL) - su_channel_detector_destroy(new); + SU_DISPOSE(su_channel_detector, new); return NULL; } -SUSCOUNT -su_channel_detector_get_req_samples(const su_channel_detector_t *detector) +SU_GETTER(su_channel_detector, SUSCOUNT, get_req_samples) { - return detector->req_samples; + return self->req_samples; } -SUPRIVATE SUBOOL -su_channel_detector_find_channels( - su_channel_detector_t *detector) { +SUPRIVATE +SU_METHOD(su_channel_detector, SUBOOL, find_channels) +{ unsigned int i; unsigned int N; unsigned int fs; @@ -576,17 +561,16 @@ su_channel_detector_find_channels( SUFLOAT power; SUFLOAT squelch; struct sigutils_channel new_channel = sigutils_channel_INITIALIZER; - SUBOOL c = SU_FALSE; /* Channel flag */ - SUBOOL ok = SU_FALSE; + SUBOOL c = SU_FALSE; /* Channel flag */ - squelch = detector->params.snr * detector->N0; + squelch = self->params.snr * self->N0; - N = detector->params.window_size; - fs = detector->params.samp_rate; + N = self->params.window_size; + fs = self->params.samp_rate; for (i = 0; i < N; ++i) { - psd = detector->spect[i]; - nfreq = 2 * i / (SUFLOAT) N; + psd = self->spect[i]; + nfreq = 2 * i / (SUFLOAT)N; /* Below threshold */ if (!c) { @@ -611,22 +595,20 @@ su_channel_detector_find_channels( power += psd; if (psd > peak_S0) - peak_S0 += detector->params.gamma * (psd - peak_S0); + peak_S0 += self->params.gamma * (psd - peak_S0); } else { /* End of channel? */ c = SU_FALSE; /* Populate channel information */ new_channel.f_hi = SU_NORM2ABS_FREQ(fs, nfreq); - new_channel.S0 = SU_POWER_DB(peak_S0); - new_channel.N0 = SU_POWER_DB(detector->N0); - new_channel.bw = SU_NORM2ABS_FREQ(fs, 2. * power / (peak_S0 * N)); - new_channel.fc = SU_NORM2ABS_FREQ( - fs, - SU_ANG2NORM_FREQ(SU_C_ARG(acc))); + new_channel.S0 = SU_POWER_DB(peak_S0); + new_channel.N0 = SU_POWER_DB(self->N0); + new_channel.bw = SU_NORM2ABS_FREQ(fs, 2. * power / (peak_S0 * N)); + new_channel.fc = SU_NORM2ABS_FREQ(fs, SU_ANG2NORM_FREQ(SU_C_ARG(acc))); /* Assert it */ - if (!su_channel_detector_assert_channel(detector, &new_channel)) { + if (!su_channel_detector_assert_channel(self, &new_channel)) { SU_ERROR("Failed to register a channel\n"); return SU_FALSE; } @@ -634,10 +616,7 @@ su_channel_detector_find_channels( } } - ok = SU_TRUE; - -done: - return ok; + return SU_TRUE; } void @@ -677,9 +656,9 @@ su_channel_params_adjust(struct sigutils_channel_detector_params *params) * detect that case and set alpha to 1. */ - equiv_fs = (SUFLOAT) params->samp_rate / params->decimation; - alpha = (SUFLOAT) params->window_size / - (equiv_fs * SU_CHANNEL_DETECTOR_AVG_TIME_WINDOW); + equiv_fs = (SUFLOAT)params->samp_rate / params->decimation; + alpha = (SUFLOAT)params->window_size + / (equiv_fs * SU_CHANNEL_DETECTOR_AVG_TIME_WINDOW); params->alpha = MIN(alpha, 1.); } @@ -702,70 +681,65 @@ su_channel_params_adjust_to_channel( su_channel_params_adjust(params); } -SUPRIVATE SUBOOL -su_channel_perform_discovery(su_channel_detector_t *detector) +SUPRIVATE +SU_METHOD(su_channel_detector, SUBOOL, perform_discovery) { unsigned int i; - unsigned int N; /* FFT size */ - unsigned int valid; /* valid FFT bins */ + unsigned int N; /* FFT size */ + unsigned int valid; /* valid FFT bins */ unsigned int min_pwr_bin; /* bin of the stpectrogram where the min power is */ - SUFLOAT alpha; SUFLOAT beta; - SUFLOAT gamma; SUFLOAT min_pwr; /* minimum power density */ - SUFLOAT psd; /* current power density */ - SUFLOAT N0; /* Noise level */ + SUFLOAT psd; /* current power density */ + SUFLOAT N0; /* Noise level */ - SUBOOL detector_enabled; /* whether we can detect channels */ + SUBOOL detector_enabled; /* whether we can detect channels */ - N = detector->params.window_size; + N = self->params.window_size; - if (detector->iters++ == 0) { + if (self->iters++ == 0) { /* First run */ - memcpy(detector->spmax, detector->spect, N * sizeof(SUFLOAT)); - memcpy(detector->spmin, detector->spect, N * sizeof(SUFLOAT)); + memcpy(self->spmax, self->spect, N * sizeof(SUFLOAT)); + memcpy(self->spmin, self->spect, N * sizeof(SUFLOAT)); /* First estimation of the noise floor */ - if (detector->N0 == 0) { + if (self->N0 == 0) { N0 = INFINITY; for (i = 0; i < N; ++i) - if (detector->spect[i] < N0) - N0 = detector->spect[i]; + if (self->spect[i] < N0) + N0 = self->spect[i]; - detector->N0 = N0; + self->N0 = N0; } } else { /* Next runs */ - alpha = detector->params.alpha; - beta = detector->params.beta; - gamma = detector->params.gamma; + beta = self->params.beta; - detector_enabled = detector->req_samples == 0; + detector_enabled = self->req_samples == 0; N0 = 0; valid = 0; min_pwr = INFINITY; min_pwr_bin = -1; for (i = 0; i < N; ++i) { - psd = detector->spect[i]; + psd = self->spect[i]; /* Update minimum */ - if (psd < detector->spmin[i]) - detector->spmin[i] = psd; + if (psd < self->spmin[i]) + self->spmin[i] = psd; else - detector->spmin[i] += beta * (psd - detector->spmin[i]); + self->spmin[i] += beta * (psd - self->spmin[i]); /* Update maximum */ - if (psd > detector->spmax[i]) - detector->spmax[i] = psd; + if (psd > self->spmax[i]) + self->spmax[i] = psd; else - detector->spmax[i] += beta * (psd - detector->spmax[i]); + self->spmax[i] += beta * (psd - self->spmax[i]); if (detector_enabled) { /* Use previous N0 estimation to detect outliers */ - if (detector->spmin[i] < detector->N0 - && detector->N0 < detector->spmax[i]) { + if (self->spmin[i] < self->N0 && self->N0 < self->spmax[i]) { N0 += psd; ++valid; } @@ -780,30 +754,29 @@ su_channel_perform_discovery(su_channel_detector_t *detector) if (detector_enabled) { if (valid != 0) - detector->N0 = N0 / valid; + self->N0 = N0 / valid; else if (min_pwr_bin != -1) - detector->N0 = .5 - * (detector->spmin[min_pwr_bin] + detector->spmax[min_pwr_bin]); + self->N0 = .5 * (self->spmin[min_pwr_bin] + self->spmax[min_pwr_bin]); } /* Check whether max age has been reached and clear channel list */ - if (detector->iters >= detector->params.max_age) { - detector->iters = 0; - su_channel_detector_channel_list_clear(detector); + if (self->iters >= self->params.max_age) { + self->iters = 0; + su_channel_detector_channel_list_clear(self); } /* New threshold calculated, find channels */ - if (!su_channel_detector_find_channels(detector)) + if (!su_channel_detector_find_channels(self)) return SU_FALSE; - su_channel_detector_channel_collect(detector); + su_channel_detector_channel_collect(self); } return SU_TRUE; } -SUPRIVATE SUBOOL -su_channel_detect_baudrate_from_acorr(su_channel_detector_t *detector) +SUPRIVATE +SU_METHOD(su_channel_detector, SUBOOL, find_baudrate_from_acorr) { int i; int N; @@ -812,17 +785,16 @@ su_channel_detect_baudrate_from_acorr(su_channel_detector_t *detector) SUFLOAT dtau; SUFLOAT tau; - N = detector->params.window_size; - dtau = (SUFLOAT) detector->params.decimation - / (SUFLOAT) detector->params.samp_rate; + N = self->params.window_size; + dtau = (SUFLOAT)self->params.decimation / (SUFLOAT)self->params.samp_rate; - prev = detector->acorr[0]; + prev = self->acorr[0]; /* Find first valley */ for (i = 1; i < N - 1; ++i) { - next = detector->acorr[i + 1]; - this = detector->acorr[i]; - prev = detector->acorr[i - 1]; + next = self->acorr[i + 1]; + this = self->acorr[i]; + prev = self->acorr[i - 1]; if (this < next && this < prev) break; /* Valley found */ @@ -830,7 +802,7 @@ su_channel_detect_baudrate_from_acorr(su_channel_detector_t *detector) /* No valley found */ if (i == N - 1) { - detector->baud = 0; + self->baud = 0; } else { /* If prev < next, the null is between (prev, this] */ if (prev < next) { @@ -841,15 +813,17 @@ su_channel_detect_baudrate_from_acorr(su_channel_detector_t *detector) tau = norm * dtau * (next * i + this * (i + 1)); } - detector->baud = 1. / tau; + self->baud = 1. / tau; } return SU_TRUE; } -SUPRIVATE SUBOOL -su_channel_detector_guess_baudrate( - su_channel_detector_t *detector, +SUPRIVATE +SU_METHOD( + su_channel_detector, + SUBOOL, + guess_baudrate, SUFLOAT equiv_fs, int bin, SUFLOAT signif) @@ -860,29 +834,29 @@ su_channel_detector_guess_baudrate( SUCOMPLEX acc = 0; SUFLOAT floor = 0; - N = detector->params.window_size; + N = self->params.window_size; /* Measure significance w.r.t the surrounding noise floor */ hi = lo = -1; /* Find channel limits */ for (j = bin + 1; j < N; ++j) - if (detector->spect[j] > detector->spect[j - 1]) { + if (self->spect[j] > self->spect[j - 1]) { hi = j; break; } for (j = bin - 1; j >= 0; --j) - if (detector->spect[j] > detector->spect[j + 1]) { + if (self->spect[j] > self->spect[j + 1]) { lo = j; break; } if (hi != -1 && lo != -1) { - floor = .5 * (detector->spect[hi] + detector->spect[lo]); + floor = .5 * (self->spect[hi] + self->spect[lo]); /* Is significance high enough? */ - if (SU_DB(detector->spect[bin] / floor) > signif) { + if (SU_DB(self->spect[bin] / floor) > signif) { acc = 0; /* @@ -890,9 +864,8 @@ su_channel_detector_guess_baudrate( * autocorrelation technique */ for (j = lo + 1; j < hi; ++j) - acc += SU_C_EXP(2 * I * M_PI * j / (SUFLOAT) N) * detector->spect[j]; - detector->baud = - SU_NORM2ABS_FREQ(equiv_fs, SU_ANG2NORM_FREQ(SU_C_ARG(acc))); + acc += SU_C_EXP(2 * I * M_PI * j / (SUFLOAT)N) * self->spect[j]; + self->baud = SU_NORM2ABS_FREQ(equiv_fs, SU_ANG2NORM_FREQ(SU_C_ARG(acc))); return SU_TRUE; } } @@ -900,8 +873,8 @@ su_channel_detector_guess_baudrate( return SU_FALSE; } -SUPRIVATE SUBOOL -su_channel_detect_baudrate_from_nonlinear_diff(su_channel_detector_t *detector) +SUPRIVATE +SU_METHOD(su_channel_detector, SUBOOL, find_baudrate_nonlinear) { int i, N; int max_idx; @@ -911,17 +884,15 @@ su_channel_detect_baudrate_from_nonlinear_diff(su_channel_detector_t *detector) SUFLOAT max; SUFLOAT equiv_fs; - N = detector->params.window_size; - equiv_fs = - (SUFLOAT) detector->params.samp_rate - / (SUFLOAT) detector->params.decimation; + N = self->params.window_size; + equiv_fs = (SUFLOAT)self->params.samp_rate / (SUFLOAT)self->params.decimation; dbaud = equiv_fs / N; /* * We always reset the baudrate. We prefer to fail here instead of * giving a non-accurate estimation. */ - detector->baud = 0; + self->baud = 0; /* * We implement two ways to get the baudrate. We look first for the @@ -932,16 +903,17 @@ su_channel_detect_baudrate_from_nonlinear_diff(su_channel_detector_t *detector) /* * First step: find where the DC ends */ - for (i = 1; i < N / 2 && (detector->spect[i] < detector->spect[i - 1]); ++i); + for (i = 1; i < N / 2 && (self->spect[i] < self->spect[i - 1]); ++i) + ; /* Second step: look for the second largest peak */ max_idx = -1; max = .0; while (i < N / 2) { - if (detector->spect[i] > max) { + if (self->spect[i] > max) { max_idx = i; - max = detector->spect[i]; + max = self->spect[i]; } ++i; } @@ -949,16 +921,15 @@ su_channel_detect_baudrate_from_nonlinear_diff(su_channel_detector_t *detector) /* Peak found. Verify if its significance is big enough */ if (max_idx != -1) if (su_channel_detector_guess_baudrate( - detector, - equiv_fs, - max_idx, - detector->params.pd_signif)) + self, + equiv_fs, + max_idx, + self->params.pd_signif)) return SU_TRUE; /* Previous method failed. Fall back to the old way */ - if (detector->params.bw != 0.0) { - startbin = - SU_CEIL(.5 * detector->params.bw / dbaud) - detector->params.pd_size; + if (self->params.bw != 0.0) { + startbin = SU_CEIL(.5 * self->params.bw / dbaud) - self->params.pd_size; if (startbin < 0) { /* * Fail silently here. The current configuration of the @@ -972,12 +943,12 @@ su_channel_detect_baudrate_from_nonlinear_diff(su_channel_detector_t *detector) } while (i < N / 2) { - if (su_peak_detector_feed(&detector->pd, SU_DB(detector->spect[i])) > 0) + if (su_peak_detector_feed(&self->pd, SU_DB(self->spect[i])) > 0) if (su_channel_detector_guess_baudrate( - detector, - equiv_fs, - i, - detector->params.pd_signif)) + self, + equiv_fs, + i, + self->params.pd_signif)) break; ++i; } @@ -985,39 +956,39 @@ su_channel_detect_baudrate_from_nonlinear_diff(su_channel_detector_t *detector) return SU_TRUE; } -SUINLINE void -su_channel_detector_apply_window(su_channel_detector_t *detector) +SUINLINE +SU_METHOD(su_channel_detector, void, apply_window) { unsigned int i; - for (i = detector->next_to_window; i < detector->ptr; ++i) - detector->window[i] *= detector->window_func[i]; + for (i = self->next_to_window; i < self->ptr; ++i) + self->window[i] *= self->window_func[i]; - detector->next_to_window = detector->ptr; + self->next_to_window = self->ptr; } -SUBOOL -su_channel_detector_exec_fft(su_channel_detector_t *detector) +SU_METHOD(su_channel_detector, SUBOOL, exec_fft) { unsigned int i; SUFLOAT psd; - SUFLOAT wsizeinv = 1. / detector->params.window_size; + SUFLOAT wsizeinv = 1. / self->params.window_size; SUFLOAT ac; - if (detector->fft_issued) + if (self->fft_issued) return SU_TRUE; - detector->fft_issued = SU_TRUE; + self->fft_issued = SU_TRUE; - switch (detector->params.mode) { + switch (self->params.mode) { case SU_CHANNEL_DETECTOR_MODE_SPECTRUM: /* Spectrum mode only */ - ++detector->iters; - su_channel_detector_apply_window(detector); - SU_FFTW(_execute(detector->fft_plan)); + ++self->iters; + su_channel_detector_apply_window(self); + SU_FFTW(_execute(self->fft_plan)); - for (i = 0; i < detector->params.window_size; ++i) - detector->spect[i] = wsizeinv * SU_C_REAL(detector->fft[i] * SU_C_CONJ(detector->fft[i])); + for (i = 0; i < self->params.window_size; ++i) + self->spect[i] = + wsizeinv * SU_C_REAL(self->fft[i] * SU_C_CONJ(self->fft[i])); return SU_TRUE; @@ -1025,21 +996,20 @@ su_channel_detector_exec_fft(su_channel_detector_t *detector) /* * Channel detection is based on the analysis of the power spectrum */ - su_channel_detector_apply_window(detector); + su_channel_detector_apply_window(self); - SU_FFTW(_execute(detector->fft_plan)); + SU_FFTW(_execute(self->fft_plan)); - detector->dc += - SU_CHANNEL_DETECTOR_DC_ALPHA * - (detector->fft[0] / detector->params.window_size - detector->dc); + self->dc += SU_CHANNEL_DETECTOR_DC_ALPHA + * (self->fft[0] / self->params.window_size - self->dc); /* Update DC component */ - for (i = 0; i < detector->params.window_size; ++i) { - psd = wsizeinv * SU_C_REAL(detector->fft[i] * SU_C_CONJ(detector->fft[i])); - detector->spect[i] += detector->params.alpha * (psd - detector->spect[i]); + for (i = 0; i < self->params.window_size; ++i) { + psd = wsizeinv * SU_C_REAL(self->fft[i] * SU_C_CONJ(self->fft[i])); + self->spect[i] += self->params.alpha * (psd - self->spect[i]); } - return su_channel_perform_discovery(detector); + return su_channel_detector_perform_discovery(self); case SU_CHANNEL_DETECTOR_MODE_AUTOCORRELATION: /* @@ -1049,20 +1019,19 @@ su_channel_detector_exec_fft(su_channel_detector_t *detector) */ /* Don't apply *any* window function */ - SU_FFTW(_execute(detector->fft_plan)); - for (i = 0; i < detector->params.window_size; ++i) - detector->fft[i] *= SU_C_CONJ(detector->fft[i]); - SU_FFTW(_execute(detector->fft_plan_rev)); + SU_FFTW(_execute(self->fft_plan)); + for (i = 0; i < self->params.window_size; ++i) + self->fft[i] *= SU_C_CONJ(self->fft[i]); + SU_FFTW(_execute(self->fft_plan_rev)); /* Average result */ - for (i = 0; i < detector->params.window_size; ++i) { - ac = SU_C_REAL(detector->ifft[i] * SU_C_CONJ(detector->ifft[i])); - detector->acorr[i] += - detector->params.alpha * (ac - detector->acorr[i]); + for (i = 0; i < self->params.window_size; ++i) { + ac = SU_C_REAL(self->ifft[i] * SU_C_CONJ(self->ifft[i])); + self->acorr[i] += self->params.alpha * (ac - self->acorr[i]); } /* Update baudrate estimation */ - return su_channel_detect_baudrate_from_acorr(detector); + return su_channel_detector_find_baudrate_from_acorr(self); case SU_CHANNEL_DETECTOR_MODE_NONLINEAR_DIFF: /* @@ -1071,19 +1040,19 @@ su_channel_detector_exec_fft(su_channel_detector_t *detector) * non-equal symbol transition. */ su_taps_apply_blackmann_harris_complex( - detector->window, - detector->params.window_size); + self->window, + self->params.window_size); - SU_FFTW(_execute(detector->fft_plan)); + SU_FFTW(_execute(self->fft_plan)); - for (i = 0; i < detector->params.window_size; ++i) { - psd = SU_C_REAL(detector->fft[i] * SU_C_CONJ(detector->fft[i])); - psd /= detector->params.window_size; - detector->spect[i] += detector->params.alpha * (psd - detector->spect[i]); + for (i = 0; i < self->params.window_size; ++i) { + psd = SU_C_REAL(self->fft[i] * SU_C_CONJ(self->fft[i])); + psd /= self->params.window_size; + self->spect[i] += self->params.alpha * (psd - self->spect[i]); } /* Update baudrate estimation */ - return su_channel_detect_baudrate_from_nonlinear_diff(detector); + return su_channel_detector_find_baudrate_nonlinear(self); break; @@ -1095,37 +1064,36 @@ su_channel_detector_exec_fft(su_channel_detector_t *detector) return SU_TRUE; } -SUINLINE SUBOOL -su_channel_detector_feed_internal(su_channel_detector_t *detector, SUCOMPLEX x) +SUINLINE +SU_METHOD(su_channel_detector, SUBOOL, feed_internal, SUCOMPLEX x) { SUCOMPLEX diff; /* In nonlinear diff mode, we store something else in the window */ - if (detector->params.mode == SU_CHANNEL_DETECTOR_MODE_NONLINEAR_DIFF) { - diff = (x - detector->prev) * detector->params.samp_rate; - detector->prev = x; - x = diff * SU_C_CONJ(diff); + if (self->params.mode == SU_CHANNEL_DETECTOR_MODE_NONLINEAR_DIFF) { + diff = (x - self->prev) * self->params.samp_rate; + self->prev = x; + x = diff * SU_C_CONJ(diff); } - detector->window[detector->ptr++] = x - detector->dc; - detector->fft_issued = SU_FALSE; + self->window[self->ptr++] = x - self->dc; + self->fft_issued = SU_FALSE; - if (detector->ptr == detector->params.window_size) { + if (self->ptr == self->params.window_size) { /* Window is full, perform FFT */ - SU_TRYCATCH( - su_channel_detector_exec_fft(detector), - return SU_FALSE); + SU_TRYCATCH(su_channel_detector_exec_fft(self), return SU_FALSE); - detector->ptr = 0; - detector->next_to_window = 0; + self->ptr = 0; + self->next_to_window = 0; } return SU_TRUE; } -SUSCOUNT -su_channel_detector_feed_bulk( - su_channel_detector_t *detector, +SU_METHOD( + su_channel_detector, + SUSCOUNT, + feed_bulk, const SUCOMPLEX *signal, SUSCOUNT size) { @@ -1134,30 +1102,29 @@ su_channel_detector_feed_bulk( SUSCOUNT tuned_size; SUSDIFF result; - if (detector->params.tune) { - su_softtuner_feed(&detector->tuner, signal, size); + if (self->params.tune) { + su_softtuner_feed(&self->tuner, signal, size); result = su_softtuner_read( - &detector->tuner, - detector->tuner_buf, + &self->tuner, + self->tuner_buf, SU_BLOCK_STREAM_BUFFER_SIZE); - tuned_signal = detector->tuner_buf; - tuned_size = result; + tuned_signal = self->tuner_buf; + tuned_size = result; } else { tuned_signal = signal; - tuned_size = size; + tuned_size = size; } for (i = 0; i < tuned_size; ++i) - if (!su_channel_detector_feed_internal(detector, tuned_signal[i])) + if (!su_channel_detector_feed_internal(self, tuned_signal[i])) break; return i; } -SUBOOL -su_channel_detector_feed(su_channel_detector_t *detector, SUCOMPLEX x) +SU_METHOD(su_channel_detector, SUBOOL, feed, SUCOMPLEX x) { - return su_channel_detector_feed_bulk(detector, &x, 1) >= 0; + return su_channel_detector_feed_bulk(self, &x, 1) >= 0; } diff --git a/sigutils/detect.h b/sigutils/detect.h index 2827c6d..1e7fc18 100644 --- a/sigutils/detect.h +++ b/sigutils/detect.h @@ -20,40 +20,40 @@ #ifndef _SIGUTILS_DETECT_H #define _SIGUTILS_DETECT_H -#include "sigutils.h" -#include "ncqo.h" #include "iir.h" +#include "ncqo.h" +#include "sigutils.h" #include "softtune.h" #ifdef __cplusplus # ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wreturn-type-c-linkage" -# endif // __clang__ +# endif // __clang__ extern "C" { #endif /* __cplusplus */ -#define SU_CHANNEL_DETECTOR_MIN_MAJORITY_AGE 0 /* in FFT runs */ -#define SU_CHANNEL_DETECTOR_MIN_SNR SU_ADDSFX(6.) /* in DBs */ -#define SU_CHANNEL_DETECTOR_MIN_BW SU_ADDSFX(10.) /* in Hz */ +#define SU_CHANNEL_DETECTOR_MIN_MAJORITY_AGE 0 /* in FFT runs */ +#define SU_CHANNEL_DETECTOR_MIN_SNR SU_ADDSFX(6.) /* in DBs */ +#define SU_CHANNEL_DETECTOR_MIN_BW SU_ADDSFX(10.) /* in Hz */ -#define SU_CHANNEL_DETECTOR_ALPHA SU_ADDSFX(1e-2) -#define SU_CHANNEL_DETECTOR_BETA SU_ADDSFX(1e-3) -#define SU_CHANNEL_DETECTOR_GAMMA SU_ADDSFX(.5) -#define SU_CHANNEL_MAX_AGE 40 /* In FFT runs */ -#define SU_CHANNEL_DETECTOR_PEAK_PSD_ALPHA SU_ADDSFX(.25) -#define SU_CHANNEL_DETECTOR_DC_ALPHA SU_ADDSFX(.1) -#define SU_CHANNEL_DETECTOR_AVG_TIME_WINDOW SU_ADDSFX(10.) /* In seconds */ +#define SU_CHANNEL_DETECTOR_ALPHA SU_ADDSFX(1e-2) +#define SU_CHANNEL_DETECTOR_BETA SU_ADDSFX(1e-3) +#define SU_CHANNEL_DETECTOR_GAMMA SU_ADDSFX(0.5) +#define SU_CHANNEL_MAX_AGE 40 /* In FFT runs */ +#define SU_CHANNEL_DETECTOR_PEAK_PSD_ALPHA SU_ADDSFX(.25) +#define SU_CHANNEL_DETECTOR_DC_ALPHA SU_ADDSFX(0.1) +#define SU_CHANNEL_DETECTOR_AVG_TIME_WINDOW SU_ADDSFX(10.) /* In seconds */ -#define SU_CHANNEL_IS_VALID(cp) \ - ((cp)->age > SU_CHANNEL_DETECTOR_MIN_MAJORITY_AGE \ - && (cp)->snr > SU_CHANNEL_DETECTOR_MIN_SNR \ - && (cp)->bw > SU_CHANNEL_DETECTOR_MIN_BW) +#define SU_CHANNEL_IS_VALID(cp) \ + ((cp)->age > SU_CHANNEL_DETECTOR_MIN_MAJORITY_AGE \ + && (cp)->snr > SU_CHANNEL_DETECTOR_MIN_SNR \ + && (cp)->bw > SU_CHANNEL_DETECTOR_MIN_BW) -#define SU_CHANNEL_DETECTOR_IDX2ABS_FREQ(detector, i) \ - SU_NORM2ABS_FREQ( \ - (detector)->params.samp_rate * (detector)->params.decimation, \ - 2 * (SUFLOAT) (i) / (SUFLOAT) (detector)->params.window_size) +#define SU_CHANNEL_DETECTOR_IDX2ABS_FREQ(detector, i) \ + SU_NORM2ABS_FREQ( \ + (detector)->params.samp_rate *(detector)->params.decimation, \ + 2 * (SUFLOAT)(i) / (SUFLOAT)(detector)->params.window_size) struct sigutils_peak_detector { unsigned int size; @@ -63,22 +63,22 @@ struct sigutils_peak_detector { SUFLOAT *history; unsigned int p; unsigned int count; - SUFLOAT accum; /* Scaled mean */ + SUFLOAT accum; /* Scaled mean */ SUFLOAT inv_size; /* 1. / size */ }; typedef struct sigutils_peak_detector su_peak_detector_t; -#define su_peak_detector_INITIALIZER \ -{ \ - 0, /* size */ \ - 0, /* thr2 */ \ - NULL, /* history */ \ - 0, /* p */ \ - 0, /* count */ \ - 0, /* accum */ \ - 0, /* inv_size */ \ -} +#define su_peak_detector_INITIALIZER \ + { \ + 0, /* size */ \ + 0, /* thr2 */ \ + NULL, /* history */ \ + 0, /* p */ \ + 0, /* count */ \ + 0, /* accum */ \ + 0, /* inv_size */ \ + } enum sigutils_channel_detector_mode { SU_CHANNEL_DETECTOR_MODE_SPECTRUM, /* Spectrum only mode */ @@ -100,60 +100,60 @@ struct sigutils_channel_detector_params { enum sigutils_channel_detector_mode mode; SUSCOUNT samp_rate; /* Sample rate */ SUSCOUNT window_size; /* Window size == FFT bins */ - SUFLOAT fc; /* Center frequency */ + SUFLOAT fc; /* Center frequency */ SUSCOUNT decimation; /* Decimation */ - SUFLOAT bw; /* Low-pass filter bandwidth (in Hz) */ + SUFLOAT bw; /* Low-pass filter bandwidth (in Hz) */ SUSCOUNT max_order; /* Max constellation order */ - SUBOOL tune; /* Signal needs to be tuned to a channel */ + SUBOOL tune; /* Signal needs to be tuned to a channel */ /* Detector parameters */ enum sigutils_channel_detector_window window; /* Window function */ - SUFLOAT alpha; /* PSD averaging ratio */ - SUFLOAT beta; /* PSD upper and lower levels averaging ratio */ - SUFLOAT gamma; /* Noise level update ratio */ - SUFLOAT snr; /* Minimum SNR to detect channels (linear) */ - SUSCOUNT max_age; /* Max channel age */ + SUFLOAT alpha; /* PSD averaging ratio */ + SUFLOAT beta; /* PSD upper and lower levels averaging ratio */ + SUFLOAT gamma; /* Noise level update ratio */ + SUFLOAT snr; /* Minimum SNR to detect channels (linear) */ + SUSCOUNT max_age; /* Max channel age */ /* Peak detector parameters */ - SUSCOUNT pd_size; /* PD samples */ - SUFLOAT pd_thres; /* PD threshold, in sigmas */ - SUFLOAT pd_signif; /* Minimum significance, in dB */ + SUSCOUNT pd_size; /* PD samples */ + SUFLOAT pd_thres; /* PD threshold, in sigmas */ + SUFLOAT pd_signif; /* Minimum significance, in dB */ }; -#define sigutils_channel_detector_params_INITIALIZER \ -{ \ - SU_CHANNEL_DETECTOR_MODE_SPECTRUM, /* Mode */ \ - 8000, /* samp_rate */ \ - 8192, /* window_size */ \ - SU_ADDSFX(0.0), /* fc */ \ - 1, /* decimation */ \ - SU_ADDSFX(0.0), /* bw */ \ - 8, /* max_order */ \ - SU_FALSE, /* tune */ \ - SU_CHANNEL_DETECTOR_WINDOW_BLACKMANN_HARRIS, /* window */ \ - SU_CHANNEL_DETECTOR_ALPHA, /* alpha */ \ - SU_CHANNEL_DETECTOR_BETA, /* beta */ \ - SU_CHANNEL_DETECTOR_GAMMA, /* gamma */ \ - SU_ADDSFX(2.), /* snr */ \ - SU_CHANNEL_MAX_AGE, /* max_age */ \ - 10, /* pd_samples */ \ - SU_ADDSFX(2.), /* pd_thres */ \ - SU_ADDSFX(10.) /* pd_signif */ \ -} - -#define sigutils_channel_INITIALIZER \ -{ \ - 0, /* fc */ \ - 0, /* f_lo */ \ - 0, /* f_li */ \ - 0, /* bw */ \ - 0, /* snr */ \ - 0, /* S0 */ \ - 0, /* N0 */ \ - 0, /* ft */ \ - 0, /* age */ \ - 0, /* present */ \ -} +#define sigutils_channel_detector_params_INITIALIZER \ + { \ + SU_CHANNEL_DETECTOR_MODE_SPECTRUM, /* Mode */ \ + 8000, /* samp_rate */ \ + 8192, /* window_size */ \ + SU_ADDSFX(0.0), /* fc */ \ + 1, /* decimation */ \ + SU_ADDSFX(0.0), /* bw */ \ + 8, /* max_order */ \ + SU_FALSE, /* tune */ \ + SU_CHANNEL_DETECTOR_WINDOW_BLACKMANN_HARRIS, /* window */ \ + SU_CHANNEL_DETECTOR_ALPHA, /* alpha */ \ + SU_CHANNEL_DETECTOR_BETA, /* beta */ \ + SU_CHANNEL_DETECTOR_GAMMA, /* gamma */ \ + SU_ADDSFX(2.), /* snr */ \ + SU_CHANNEL_MAX_AGE, /* max_age */ \ + 10, /* pd_samples */ \ + SU_ADDSFX(2.), /* pd_thres */ \ + SU_ADDSFX(10.) /* pd_signif */ \ + } + +#define sigutils_channel_INITIALIZER \ + { \ + 0, /* fc */ \ + 0, /* f_lo */ \ + 0, /* f_li */ \ + 0, /* bw */ \ + 0, /* snr */ \ + 0, /* S0 */ \ + 0, /* N0 */ \ + 0, /* ft */ \ + 0, /* age */ \ + 0, /* present */ \ + } struct sigutils_channel_detector { /* Common members */ @@ -165,10 +165,10 @@ struct sigutils_channel_detector { SUSCOUNT next_to_window; unsigned int iters; unsigned int chan_age; - SU_FFTW(_complex) *window_func; - SU_FFTW(_complex) *window; + SU_FFTW(_complex) * window_func; + SU_FFTW(_complex) * window; SU_FFTW(_plan) fft_plan; - SU_FFTW(_complex) *fft; + SU_FFTW(_complex) * fft; SUSCOUNT req_samples; /* Number of required samples for detection */ union { @@ -179,100 +179,99 @@ struct sigutils_channel_detector { /* Channel detector members */ SU_FFTW(_plan) fft_plan_rev; - SU_FFTW(_complex) *ifft; + SU_FFTW(_complex) * ifft; SUFLOAT *spmax; SUFLOAT *spmin; - SUFLOAT N0; /* Detected noise floor */ + SUFLOAT N0; /* Detected noise floor */ SUCOMPLEX dc; /* Detected DC component */ PTR_LIST(struct sigutils_channel, channel); /* Baudrate estimator members */ - SUFLOAT baud; /* Detected baudrate */ - SUCOMPLEX prev; /* Used by nonlinear diff */ + SUFLOAT baud; /* Detected baudrate */ + SUCOMPLEX prev; /* Used by nonlinear diff */ su_peak_detector_t pd; /* Peak detector used by nonlinear diff */ }; typedef struct sigutils_channel_detector su_channel_detector_t; -SUINLINE void -su_channel_detector_rewind(su_channel_detector_t *cd) +SUINLINE +SU_METHOD(su_channel_detector, void, rewind) { - cd->ptr = 0; - cd->iters = 0; + self->ptr = 0; + self->iters = 0; } -SUINLINE unsigned int -su_channel_detector_get_iters(const su_channel_detector_t *cd) +SUINLINE +SU_GETTER(su_channel_detector, unsigned int, get_iters) { - return cd->iters; + return self->iters; } -SUINLINE SUCOMPLEX -su_channel_detector_get_dc(const su_channel_detector_t *cd) +SUINLINE +SU_GETTER(su_channel_detector, SUCOMPLEX, get_dc) { - return cd->dc; + return self->dc; } -SUINLINE SUSCOUNT -su_channel_detector_get_fs(const su_channel_detector_t *cd) +SUINLINE +SU_GETTER(su_channel_detector, SUSCOUNT, get_fs) { - return cd->params.samp_rate; + return self->params.samp_rate; } -SUINLINE SUBOOL -su_channel_detector_get_window_ptr(const su_channel_detector_t *cd) +SUINLINE +SU_GETTER(su_channel_detector, SUSCOUNT, get_window_ptr) { - return cd->ptr; + return self->ptr; } -SUINLINE SUFLOAT -su_channel_detector_get_baud(const su_channel_detector_t *cd) +SUINLINE +SU_GETTER(su_channel_detector, SUFLOAT, get_baud) { - return cd->baud; + return self->baud; } -SUINLINE SUFLOAT -su_channel_detector_get_window_size(const su_channel_detector_t *cd) +SUINLINE +SU_GETTER(su_channel_detector, SUSCOUNT, get_window_size) { - return cd->params.window_size; + return self->params.window_size; } /**************************** Peak detector API *****************************/ -SUBOOL su_peak_detector_init( - su_peak_detector_t *pd, - unsigned int size, - SUFLOAT thres); +SU_CONSTRUCTOR(su_peak_detector, unsigned int size, SUFLOAT thres); +SU_DESTRUCTOR(su_peak_detector); -int su_peak_detector_feed(su_peak_detector_t *pd, SUFLOAT x); - -void su_peak_detector_finalize(su_peak_detector_t *pd); +SU_METHOD(su_peak_detector, int, feed, SUFLOAT x); /************************** Channel detector API ****************************/ -su_channel_detector_t *su_channel_detector_new( +SU_INSTANCER( + su_channel_detector, const struct sigutils_channel_detector_params *params); +SU_COLLECTOR(su_channel_detector); -SUBOOL su_channel_detector_set_params( - su_channel_detector_t *detector, +SU_METHOD( + su_channel_detector, + SUBOOL, + set_params, const struct sigutils_channel_detector_params *params); -SUSCOUNT su_channel_detector_get_req_samples( - const su_channel_detector_t *detector); - -void su_channel_detector_destroy(su_channel_detector_t *detector); +SU_GETTER(su_channel_detector, SUSCOUNT, get_req_samples); -SUBOOL su_channel_detector_feed( - su_channel_detector_t *detector, - SUCOMPLEX x); +SU_METHOD(su_channel_detector, SUBOOL, feed, SUCOMPLEX x); -SUBOOL su_channel_detector_exec_fft(su_channel_detector_t *detector); - -SUSCOUNT su_channel_detector_feed_bulk( - su_channel_detector_t *detector, +SU_METHOD( + su_channel_detector, + SUSCOUNT, + feed_bulk, const SUCOMPLEX *signal, SUSCOUNT size); -void su_channel_detector_get_channel_list( - const su_channel_detector_t *detector, +SU_METHOD(su_channel_detector, SUBOOL, exec_fft); + +SU_GETTER( + su_channel_detector, + void, + get_channel_list, struct sigutils_channel ***channel_list, unsigned int *channel_count); @@ -282,24 +281,21 @@ void su_channel_params_adjust_to_channel( struct sigutils_channel_detector_params *params, const struct sigutils_channel *channel); -struct sigutils_channel *su_channel_dup(const struct sigutils_channel *channel); - -void su_channel_destroy(struct sigutils_channel *channel); - -struct sigutils_channel *su_channel_detector_lookup_channel( - const su_channel_detector_t *detector, +SU_GETTER(su_channel_detector, su_channel_t *, lookup_channel, SUFLOAT fc); +SU_GETTER( + su_channel_detector, + su_channel_t *, + lookup_valid_channel, SUFLOAT fc); -struct sigutils_channel *su_channel_detector_lookup_valid_channel( - const su_channel_detector_t *detector, - SUFLOAT fc); +SU_COPY_INSTANCER(su_channel); +SU_COLLECTOR(su_channel); #ifdef __cplusplus # ifdef __clang__ # pragma clang diagnostic pop -# endif // __clang__ +# endif // __clang__ } #endif /* __cplusplus */ #endif /* _SIGUTILS_DETECT_H */ - diff --git a/sigutils/equalizer.c b/sigutils/equalizer.c index dd84a3d..f4629f0 100644 --- a/sigutils/equalizer.c +++ b/sigutils/equalizer.c @@ -17,11 +17,12 @@ */ +#include "equalizer.h" + #include #include #include "log.h" -#include "equalizer.h" SUPRIVATE void su_equalizer_push_x(su_equalizer_t *eq, SUCOMPLEX x) @@ -57,7 +58,6 @@ su_equalizer_update_weights(su_equalizer_t *eq, SUCOMPLEX y) int p; SUCOMPLEX y2; SUCOMPLEX err; - SUFLOAT err_i, err_q; y2 = y * SU_C_CONJ(y); err = y * (y2 - 1.); @@ -114,7 +114,8 @@ su_equalizer_feed(su_equalizer_t *eq, SUCOMPLEX x) return y; } -void su_equalizer_finalize(su_equalizer_t *eq) +void +su_equalizer_finalize(su_equalizer_t *eq) { if (eq->x != NULL) free(eq->x); diff --git a/sigutils/equalizer.h b/sigutils/equalizer.h index 50ca854..efebfd6 100644 --- a/sigutils/equalizer.h +++ b/sigutils/equalizer.h @@ -20,8 +20,10 @@ #ifndef _SIGUTILS_EQUALIZER_H #define _SIGUTILS_EQUALIZER_H +#include "types.h" + enum sigutils_equalizer_algorithm { - SU_EQUALIZER_ALGORITHM_CMA /* Default */ + SU_EQUALIZER_ALGORITHM_CMA, /* Default */ }; struct sigutils_equalizer_params { @@ -31,11 +33,11 @@ struct sigutils_equalizer_params { }; #define sigutils_equalizer_params_INITIALIZER \ -{ \ - SU_EQUALIZER_ALGORITHM_CMA, /* algorithm */ \ - 10, /* length */ \ - 0.2, /* mu */ \ -} + { \ + SU_EQUALIZER_ALGORITHM_CMA, /* algorithm */ \ + 10, /* length */ \ + 0.2, /* mu */ \ + } /* * A signal equalizer is basically an adaptive filter, so we can leverage @@ -52,12 +54,12 @@ struct sigutils_equalizer { typedef struct sigutils_equalizer su_equalizer_t; #define su_equalizer_INITIALIZER \ -{ \ - sigutils_equalizer_params_INITIALIZER, /* params */ \ - NULL, /* w */ \ - NULL, /* x */ \ - 0, /* ptr */ \ -} + { \ + sigutils_equalizer_params_INITIALIZER, /* params */ \ + NULL, /* w */ \ + NULL, /* x */ \ + 0, /* ptr */ \ + } SUBOOL su_equalizer_init( su_equalizer_t *eq, diff --git a/sigutils/iir.c b/sigutils/iir.c index b71d4d8..4ff112e 100644 --- a/sigutils/iir.c +++ b/sigutils/iir.c @@ -17,20 +17,51 @@ */ +#include "iir.h" + +#include #include #include -#include -#include "sampling.h" -#include "iir.h" #include "coef.h" +#include "sampling.h" #include "taps.h" -#if defined(_SU_SINGLE_PRECISION) && HAVE_VOLK +/* + Somehow the Volk enhancement of IIR filters corrupts the + heap in Win32 systems. The reason is not well understood. + + We temptatively disable it in these targets until we figure + out what the heck is going on. +*/ + +#if !defined(_WIN32) && defined(_SU_SINGLE_PRECISION) && HAVE_VOLK # define SU_USE_VOLK # include #endif +#ifdef SU_USE_VOLK +# define calloc su_volk_calloc +# define malloc su_volk_malloc +# define free volk_free +SUINLINE void * +su_volk_malloc(size_t size) +{ + return volk_malloc(size, volk_get_alignment()); +} + +SUINLINE void * +su_volk_calloc(size_t nmemb, size_t size) +{ + void *result = su_volk_malloc(nmemb * size); + + if (result != NULL) + memset(result, 0, nmemb * size); + + return result; +} +#endif /* SU_USE_VOLK */ + SUINLINE void __su_iir_filt_push_x(su_iir_filt_t *filt, SUCOMPLEX x) { @@ -129,7 +160,7 @@ su_iir_filt_finalize(su_iir_filt_t *filt) free(filt->b); if (filt->x != NULL) - free(filt->x); + free(filt->x); if (filt->y != NULL) free(filt->y); @@ -152,11 +183,11 @@ su_iir_filt_feed(su_iir_filt_t *filt, SUCOMPLEX x) void su_iir_filt_feed_bulk( su_iir_filt_t *filt, - const SUCOMPLEX *x, - SUCOMPLEX *y, + const SUCOMPLEX *__restrict x, + SUCOMPLEX *__restrict y, SUSCOUNT len) { - SUCOMPLEX tmp_y; + SUCOMPLEX tmp_y = 0; while (len-- != 0) { __su_iir_filt_push_x(filt, *x++); @@ -177,9 +208,11 @@ su_iir_filt_get(const su_iir_filt_t *filt) void su_iir_filt_reset(su_iir_filt_t *filt) { - memset(filt->x, 0, sizeof(SUCOMPLEX) * filt->x_size); - memset(filt->y, 0, sizeof(SUCOMPLEX) * filt->y_size); + memset(filt->x, 0, sizeof(SUCOMPLEX) * filt->x_alloc); + memset(filt->y, 0, sizeof(SUCOMPLEX) * filt->y_alloc); filt->curr_y = 0; + filt->x_ptr = 0; + filt->y_ptr = 0; } void @@ -192,9 +225,9 @@ SUBOOL __su_iir_filt_init( su_iir_filt_t *filt, SUSCOUNT y_size, - SUFLOAT *a, + SUFLOAT *__restrict a, SUSCOUNT x_size, - SUFLOAT *b, + SUFLOAT *__restrict b, SUBOOL copy_coef) { SUCOMPLEX *x = NULL; @@ -206,7 +239,7 @@ __su_iir_filt_init( assert(x_size > 0); - memset(filt, 0, sizeof (su_iir_filt_t)); + memset(filt, 0, sizeof(su_iir_filt_t)); filt->gain = 1; @@ -221,25 +254,25 @@ __su_iir_filt_init( y_alloc = 2 * y_alloc - 1; #endif /* SU_USE_VOLK */ - if ((x = calloc(x_alloc, sizeof (SUCOMPLEX))) == NULL) + if ((x = calloc(x_alloc, sizeof(SUCOMPLEX))) == NULL) goto fail; if (y_size > 0) - if ((y = calloc(y_alloc, sizeof (SUCOMPLEX))) == NULL) + if ((y = calloc(y_alloc, sizeof(SUCOMPLEX))) == NULL) goto fail; if (copy_coef) { if (y_size > 0) { - if ((a_copy = malloc(y_size * sizeof (SUFLOAT))) == NULL) + if ((a_copy = malloc(y_size * sizeof(SUFLOAT))) == NULL) goto fail; - memcpy(a_copy, a, y_size * sizeof (SUFLOAT)); + memcpy(a_copy, a, y_size * sizeof(SUFLOAT)); } - if ((b_copy = malloc(x_size * sizeof (SUFLOAT))) == NULL) + if ((b_copy = malloc(x_size * sizeof(SUFLOAT))) == NULL) goto fail; - memcpy(b_copy, b, x_size * sizeof (SUFLOAT)); + memcpy(b_copy, b, x_size * sizeof(SUFLOAT)); } else { a_copy = a; b_copy = b; @@ -284,16 +317,16 @@ SUBOOL su_iir_filt_init( su_iir_filt_t *filt, SUSCOUNT y_size, - const SUFLOAT *a, + const SUFLOAT *__restrict a, SUSCOUNT x_size, - const SUFLOAT *b) + const SUFLOAT *__restrict b) { return __su_iir_filt_init( filt, y_size, - (SUFLOAT *) a, + (SUFLOAT *)a, x_size, - (SUFLOAT *) b, + (SUFLOAT *)b, SU_TRUE); } @@ -407,12 +440,11 @@ SUBOOL su_iir_rrc_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT T, SUFLOAT beta) { SUFLOAT *b = NULL; - unsigned int i; if (n < 1) goto fail; - if ((b = malloc(n * sizeof (SUFLOAT))) == NULL) + if ((b = malloc(n * sizeof(SUFLOAT))) == NULL) goto fail; su_taps_rrc_init(b, T, beta, n); @@ -433,12 +465,11 @@ SUBOOL su_iir_hilbert_init(su_iir_filt_t *filt, SUSCOUNT n) { SUFLOAT *b = NULL; - unsigned int i; if (n < 1) goto fail; - if ((b = malloc(n * sizeof (SUFLOAT))) == NULL) + if ((b = malloc(n * sizeof(SUFLOAT))) == NULL) goto fail; su_taps_hilbert_init(b, n); @@ -463,12 +494,11 @@ su_iir_brickwall_bp_init( SUFLOAT ifnor) { SUFLOAT *b = NULL; - unsigned int i; if (n < 1) goto fail; - if ((b = malloc(n * sizeof (SUFLOAT))) == NULL) + if ((b = malloc(n * sizeof(SUFLOAT))) == NULL) goto fail; su_taps_brickwall_bp_init(b, bw, ifnor, n); @@ -489,12 +519,11 @@ SUBOOL su_iir_brickwall_lp_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc) { SUFLOAT *b = NULL; - unsigned int i; if (n < 1) goto fail; - if ((b = malloc(n * sizeof (SUFLOAT))) == NULL) + if ((b = malloc(n * sizeof(SUFLOAT))) == NULL) goto fail; su_taps_brickwall_lp_init(b, fc, n); diff --git a/sigutils/iir.h b/sigutils/iir.h index bf649b3..6cc5074 100644 --- a/sigutils/iir.h +++ b/sigutils/iir.h @@ -21,6 +21,7 @@ #define _SIGUTILS_IIR_H #include + #include "types.h" #define SU_FLOAT_GUARD INFINITY @@ -29,7 +30,7 @@ # ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wreturn-type-c-linkage" -# endif // __clang__ +# endif // __clang__ extern "C" { #endif /* __cplusplus */ @@ -44,7 +45,7 @@ struct sigutils_iir_filt { int x_ptr; int y_ptr; - SUCOMPLEX curr_y; + SUCOMPLEX curr_y; SUCOMPLEX *y; SUCOMPLEX *x; @@ -57,7 +58,10 @@ struct sigutils_iir_filt { typedef struct sigutils_iir_filt su_iir_filt_t; -#define su_iir_filt_INITIALIZER {0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 1} +#define su_iir_filt_INITIALIZER \ + { \ + 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 1 \ + } /* Push sample to filter */ SUCOMPLEX su_iir_filt_feed(su_iir_filt_t *filt, SUCOMPLEX x); @@ -65,8 +69,8 @@ SUCOMPLEX su_iir_filt_feed(su_iir_filt_t *filt, SUCOMPLEX x); /* Push a bunch of samples to filter */ void su_iir_filt_feed_bulk( su_iir_filt_t *filt, - const SUCOMPLEX *x, - SUCOMPLEX *y, + const SUCOMPLEX *__restrict x, + SUCOMPLEX *__restrict y, SUSCOUNT len); /* Get last output */ @@ -78,17 +82,17 @@ void su_iir_filt_reset(su_iir_filt_t *filt); SUBOOL su_iir_filt_init( su_iir_filt_t *filt, SUSCOUNT y_size, - const SUFLOAT *a, + const SUFLOAT *__restrict a, SUSCOUNT x_size, - const SUFLOAT *b); + const SUFLOAT *__restrict b); /* Initialize filter (internal) */ SUBOOL __su_iir_filt_init( su_iir_filt_t *filt, SUSCOUNT y_size, - SUFLOAT *a, + SUFLOAT *__restrict a, SUSCOUNT x_size, - SUFLOAT *b, + SUFLOAT *__restrict b, SUBOOL copy_coef); /* Set output gain */ @@ -98,13 +102,15 @@ void su_iir_filt_set_gain(su_iir_filt_t *filt, SUFLOAT gain); SUBOOL su_iir_bwlpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc); /* Initialize Butterworth band-pass filter of order N */ -SUBOOL su_iir_bwbpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT f1, SUFLOAT f2); +SUBOOL +su_iir_bwbpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT f1, SUFLOAT f2); /* Initialize Butterworh high-pass filter of order N */ SUBOOL su_iir_bwhpf_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc); /* Initialize Root Raised Cosine filter */ -SUBOOL su_iir_rrc_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT T, SUFLOAT beta); +SUBOOL +su_iir_rrc_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT T, SUFLOAT beta); /* Initialize Hilbert transform */ SUBOOL su_iir_hilbert_init(su_iir_filt_t *filt, SUSCOUNT n); @@ -113,7 +119,11 @@ SUBOOL su_iir_hilbert_init(su_iir_filt_t *filt, SUSCOUNT n); SUBOOL su_iir_brickwall_lp_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT fc); /* Initialize brickwall BPF filter */ -SUBOOL su_iir_brickwall_bp_init(su_iir_filt_t *filt, SUSCOUNT n, SUFLOAT bw, SUFLOAT ifnor); +SUBOOL su_iir_brickwall_bp_init( + su_iir_filt_t *filt, + SUSCOUNT n, + SUFLOAT bw, + SUFLOAT ifnor); /* Destroy filter */ void su_iir_filt_finalize(su_iir_filt_t *filt); @@ -121,7 +131,7 @@ void su_iir_filt_finalize(su_iir_filt_t *filt); #ifdef __cplusplus # ifdef __clang__ # pragma clang diagnostic pop -# endif // __clang__ +# endif // __clang__ } #endif /* __cplusplus */ diff --git a/sigutils/lfsr.c b/sigutils/lfsr.c index dc853d5..c743a3c 100644 --- a/sigutils/lfsr.c +++ b/sigutils/lfsr.c @@ -19,23 +19,20 @@ #define SU_LOG_LEVEL "lfsr" +#include "lfsr.h" + #include #include "log.h" -#include "lfsr.h" SUBOOL su_lfsr_init_coef(su_lfsr_t *lfsr, const SUBITS *coef, SUSCOUNT order) { memset(lfsr, 0, sizeof(su_lfsr_t)); - SU_TRYCATCH( - lfsr->coef = malloc(order * sizeof(SUBITS)), - goto fail); + SU_TRYCATCH(lfsr->coef = malloc(order * sizeof(SUBITS)), goto fail); - SU_TRYCATCH( - lfsr->buffer = calloc(order, sizeof(SUBITS)), - goto fail); + SU_TRYCATCH(lfsr->buffer = calloc(order, sizeof(SUBITS)), goto fail); memcpy(lfsr->coef, coef, order * sizeof(SUBITS)); lfsr->order = order; @@ -64,7 +61,6 @@ su_lfsr_set_mode(su_lfsr_t *lfsr, enum su_lfsr_mode mode) lfsr->mode = mode; } - /* * There is a common part for both additive and multiplicative * descramblers, related to the shift register. @@ -84,8 +80,8 @@ SUINLINE SUBITS su_lfsr_transfer(su_lfsr_t *lfsr, SUBITS x) { SUBITS F = 0; - int i; - int n = lfsr->p; + uint64_t i; + uint64_t n = lfsr->p; for (i = 1; i < lfsr->order; ++i) { if (++n == lfsr->order) @@ -115,7 +111,6 @@ su_lfsr_set_buffer(su_lfsr_t *lfsr, const SUBITS *seq) lfsr->p = lfsr->order - 1; } - SUBITS su_lfsr_feed(su_lfsr_t *lfsr, SUBITS x) { diff --git a/sigutils/lfsr.h b/sigutils/lfsr.h index 80e117d..89a0298 100644 --- a/sigutils/lfsr.h +++ b/sigutils/lfsr.h @@ -28,9 +28,9 @@ enum su_lfsr_mode { }; struct sigutils_lfsr { - SUBITS *coef; /* LFSR coefficients */ - SUBITS *buffer; /* State buffer */ - SUSCOUNT order; /* Polynomial degree */ + SUBITS *coef; /* LFSR coefficients */ + SUBITS *buffer; /* State buffer */ + SUSCOUNT order; /* Polynomial degree */ enum su_lfsr_mode mode; /* LFSR mode */ SUBITS F_prev; @@ -40,11 +40,14 @@ struct sigutils_lfsr { typedef struct sigutils_lfsr su_lfsr_t; -#define su_lfsr_INITIALIZER {NULL, NULL, 0} +#define su_lfsr_INITIALIZER \ + { \ + NULL, NULL, 0 \ + } SUBOOL su_lfsr_init_coef(su_lfsr_t *lfsr, const SUBITS *coef, SUSCOUNT order); -void su_lfsr_finalize(su_lfsr_t *lfsr); -void su_lfsr_set_mode(su_lfsr_t *lfsr, enum su_lfsr_mode mode); +void su_lfsr_finalize(su_lfsr_t *lfsr); +void su_lfsr_set_mode(su_lfsr_t *lfsr, enum su_lfsr_mode mode); void su_lfsr_set_buffer(su_lfsr_t *lfsr, const SUBITS *seq); SUBITS su_lfsr_feed(su_lfsr_t *lfsr, SUBITS input); diff --git a/sigutils/lib.c b/sigutils/lib.c index 5c445b2..672665c 100644 --- a/sigutils/lib.c +++ b/sigutils/lib.c @@ -23,21 +23,6 @@ #include "sigutils.h" -/* Block classes */ -extern struct sigutils_block_class su_block_class_AGC; -extern struct sigutils_block_class su_block_class_TUNER; -extern struct sigutils_block_class su_block_class_WAVFILE; -extern struct sigutils_block_class su_block_class_COSTAS; -extern struct sigutils_block_class su_block_class_RRC; -extern struct sigutils_block_class su_block_class_CDR; -extern struct sigutils_block_class su_block_class_SIGGEN; - -/* Modem classes */ -extern struct sigutils_modem_class su_modem_class_QPSK; - -/* Encoder classes */ -extern struct sigutils_codec_class su_codec_class_DIFF; - SUPRIVATE SUBOOL su_log_cr = SU_TRUE; SUPRIVATE char @@ -54,13 +39,13 @@ su_log_severity_to_char(enum sigutils_log_severity sev) SUPRIVATE void su_log_func_default(void *private, const struct sigutils_log_message *msg) { - SUBOOL *cr = (SUBOOL *) private; + SUBOOL *cr = (SUBOOL *)private; size_t msglen; if (*cr) fprintf( stderr, - "[%c] %s:%d: ", + "[%c] %s:%u: ", su_log_severity_to_char(msg->severity), msg->function, msg->line); @@ -73,11 +58,10 @@ su_log_func_default(void *private, const struct sigutils_log_message *msg) } /* Log config */ -SUPRIVATE struct sigutils_log_config su_lib_log_config = -{ - &su_log_cr, /* private */ - SU_TRUE, /* exclusive */ - su_log_func_default, /* log_func */ +SUPRIVATE struct sigutils_log_config su_lib_log_config = { + &su_log_cr, /* private */ + SU_TRUE, /* exclusive */ + su_log_func_default, /* log_func */ }; SUBOOL @@ -85,53 +69,11 @@ su_lib_init_ex(const struct sigutils_log_config *logconfig) { unsigned int i = 0; - struct sigutils_block_class *blocks[] = - { - &su_block_class_AGC, - &su_block_class_TUNER, - &su_block_class_WAVFILE, - &su_block_class_COSTAS, - &su_block_class_RRC, - &su_block_class_CDR, - &su_block_class_SIGGEN, - }; - - struct sigutils_modem_class *modems[] = - { - &su_modem_class_QPSK - }; - - struct sigutils_codec_class *codecs[] = - { - &su_codec_class_DIFF - }; - if (logconfig == NULL) logconfig = &su_lib_log_config; su_log_init(logconfig); - for (i = 0; i < sizeof (blocks) / sizeof (blocks[0]); ++i) - if (!su_block_class_register(blocks[i])) { - if (blocks[i]->name != NULL) - SU_ERROR("Failed to register block class `%s'\n", blocks[i]->name); - return SU_FALSE; - } - - for (i = 0; i < sizeof (modems) / sizeof (modems[0]); ++i) - if (!su_modem_class_register(modems[i])) { - if (modems[i]->name != NULL) - SU_ERROR("Failed to register modem class `%s'\n", modems[i]->name); - return SU_FALSE; - } - - for (i = 0; i < sizeof (codecs) / sizeof (codecs[0]); ++i) - if (!su_codec_class_register(codecs[i])) { - if (codecs[i]->name != NULL) - SU_ERROR("Failed to register codec class `%s'\n", codecs[i]->name); - return SU_FALSE; - } - return SU_TRUE; } diff --git a/sigutils/log.c b/sigutils/log.c index 3d053e5..bb58808 100644 --- a/sigutils/log.c +++ b/sigutils/log.c @@ -17,18 +17,23 @@ */ -#include +#include "log.h" + +#include #include +#include #include -#include +#include +#include #include "types.h" -#include "log.h" -#include SUPRIVATE struct sigutils_log_config log_config; SUPRIVATE uint32_t log_mask; SUPRIVATE pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; +SUPRIVATE SUBOOL su_forced_logging = SU_FALSE; +SUPRIVATE SUBOOL su_log_cr = SU_TRUE; +SUPRIVATE FILE *su_log_fp = NULL; void su_log_mask_severity(enum sigutils_log_severity sev) @@ -57,20 +62,20 @@ su_log_set_mask(uint32_t mask) SUBOOL su_log_is_masked(enum sigutils_log_severity sev) { - return !!(log_mask & (1 << sev)); + return !su_forced_logging && !!(log_mask & (1 << sev)); } void sigutils_log_message_destroy(struct sigutils_log_message *msg) { if (msg->domain != NULL) - free((void *) msg->domain); + free((void *)msg->domain); if (msg->function != NULL) - free((void *) msg->function); + free((void *)msg->function); if (msg->message != NULL) - free((void *) msg->message); + free((void *)msg->message); free(msg); } @@ -80,7 +85,7 @@ sigutils_log_message_dup(const struct sigutils_log_message *msg) { struct sigutils_log_message *dup = NULL; - if ((dup = calloc(1, sizeof (struct sigutils_log_message))) == NULL) + if ((dup = calloc(1, sizeof(struct sigutils_log_message))) == NULL) goto fail; if ((dup->domain = strdup(msg->domain)) == NULL) @@ -122,12 +127,86 @@ su_log_severity_to_string(enum sigutils_log_severity sev) case SU_LOG_SEVERITY_DEBUG: return "Debug"; - } return "Unknown"; } +SUPRIVATE void +print_date(void) +{ + time_t t; + struct tm tm; + char mytime[50]; + + time(&t); + localtime_r(&t, &tm); + + strftime(mytime, sizeof(mytime), "%d %b %Y - %H:%M:%S", &tm); + + fprintf(su_log_fp, "%s", mytime); +} + +SUPRIVATE void +su_log_func(void *private, const struct sigutils_log_message *msg) +{ + SUBOOL *cr = (SUBOOL *) private; + SUBOOL is_except; + size_t msglen; + + if (*cr) { + switch (msg->severity) { + case SU_LOG_SEVERITY_DEBUG: + fprintf(su_log_fp, "\033[1;30m"); + print_date(); + fprintf(su_log_fp, " - debug: "); + break; + + case SU_LOG_SEVERITY_INFO: + print_date(); + fprintf(su_log_fp, " - "); + break; + + case SU_LOG_SEVERITY_WARNING: + print_date(); + fprintf(su_log_fp, " - \033[1;33mwarning [%s]\033[0m: ", msg->domain); + break; + + case SU_LOG_SEVERITY_ERROR: + print_date(); + + is_except = + strstr(msg->message, "exception in \"") != NULL + || strstr(msg->message, "failed to create instance") != NULL; + + if (is_except) + fprintf(su_log_fp, "\033[1;30m "); + else + fprintf(su_log_fp, " - \033[1;31merror [%s]\033[0;1m: ", msg->domain); + + break; + + case SU_LOG_SEVERITY_CRITICAL: + print_date(); + fprintf(su_log_fp, + " - \033[1;37;41mcritical[%s] in %s:%u\033[0m: ", + msg->domain, + msg->function, + msg->line); + break; + } + } + + msglen = strlen(msg->message); + + *cr = msg->message[msglen - 1] == '\n' || msg->message[msglen - 1] == '\r'; + + fputs(msg->message, su_log_fp); + + if (*cr) + fputs("\033[0m", su_log_fp); +} + void su_log( enum sigutils_log_severity sev, @@ -137,24 +216,29 @@ su_log( const char *message) { struct sigutils_log_message msg = sigutils_log_message_INITIALIZER; + SUBOOL log_needed = (log_config.log_func != NULL || su_forced_logging); - if (!su_log_is_masked(sev) && log_config.log_func != NULL) { + if (!su_log_is_masked(sev) && log_needed) { gettimeofday(&msg.time, NULL); msg.severity = sev; - msg.domain = domain; + msg.domain = domain; msg.function = function; - msg.line = line; - msg.message = message; + msg.line = line; + msg.message = message; if (log_config.exclusive) if (pthread_mutex_lock(&log_mutex) == -1) /* Too dangerous to log */ return; - (log_config.log_func) (log_config.priv, &msg); + if (log_config.log_func != NULL) + (log_config.log_func)(log_config.priv, &msg); + + if (su_forced_logging) + su_log_func(&su_log_cr, &msg); if (log_config.exclusive) - (void) pthread_mutex_unlock(&log_mutex); + (void)pthread_mutex_unlock(&log_mutex); } } @@ -208,6 +292,20 @@ su_logprintf( void su_log_init(const struct sigutils_log_config *config) { + const char *env = getenv("SIGUTILS_FORCELOG"); + const char *logf = getenv("SIGUTILS_LOGFILE"); + FILE *fp; + + if (env != NULL && strlen(env) > 0) { + su_forced_logging = SU_TRUE; + + if (logf != NULL) + if ((fp = fopen(logf, "w")) != NULL) + su_log_fp = fp; + + if (su_log_fp == NULL) + su_log_fp = stdout; + } + log_config = *config; } - diff --git a/sigutils/log.h b/sigutils/log.h index 2d386ef..4f3000f 100644 --- a/sigutils/log.h +++ b/sigutils/log.h @@ -20,15 +20,16 @@ #ifndef _SIGUTILS_LOG_H #define _SIGUTILS_LOG_H -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - #include #include +#include "defs.h" #include "types.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + enum sigutils_log_severity { SU_LOG_SEVERITY_DEBUG, SU_LOG_SEVERITY_INFO, @@ -46,28 +47,28 @@ struct sigutils_log_message { const char *message; }; -#define sigutils_log_message_INITIALIZER \ -{ \ - SU_LOG_SEVERITY_DEBUG, /* severity */ \ - {0, 0}, /* time */ \ - NULL, /* domain */ \ - NULL, /* function */ \ - 0, /* line */ \ - NULL, /* message */ \ -} +#define sigutils_log_message_INITIALIZER \ + { \ + SU_LOG_SEVERITY_DEBUG, /* severity */ \ + {0, 0}, /* time */ \ + NULL, /* domain */ \ + NULL, /* function */ \ + 0, /* line */ \ + NULL, /* message */ \ + } struct sigutils_log_config { void *priv; SUBOOL exclusive; - void (*log_func) (void *priv, const struct sigutils_log_message *msg); + void (*log_func)(void *priv, const struct sigutils_log_message *msg); }; -#define sigutils_log_config_INITIALIZER \ -{ \ - NULL, /* private */ \ - SU_TRUE, /* exclusive */ \ - NULL, /* log_func */ \ -} +#define sigutils_log_config_INITIALIZER \ + { \ + NULL, /* private */ \ + SU_TRUE, /* exclusive */ \ + NULL, /* log_func */ \ + } #ifndef __FILENAME__ # define __FILENAME__ "(no file)" @@ -77,43 +78,32 @@ struct sigutils_log_config { # define SU_LOG_DOMAIN __FILENAME__ #endif /* SU_LOG_DOMAIN */ -#define SU_ERROR(fmt, arg...) \ - su_logprintf( \ - SU_LOG_SEVERITY_ERROR, \ - SU_LOG_DOMAIN, \ - __FUNCTION__, \ - __LINE__, \ - fmt, \ - ##arg) - -#define SU_WARNING(fmt, arg...) \ - su_logprintf( \ - SU_LOG_SEVERITY_WARNING, \ - SU_LOG_DOMAIN, \ - __FUNCTION__, \ - __LINE__, \ - fmt, \ - ##arg) - -#define SU_INFO(fmt, arg...) \ - su_logprintf( \ - SU_LOG_SEVERITY_INFO, \ - SU_LOG_DOMAIN, \ - __FUNCTION__, \ - __LINE__, \ - fmt, \ - ##arg) - -/* Other useful macros */ -#define SU_TRYCATCH(expr, action) \ - if (!(expr)) { \ - SU_ERROR( \ - "exception in \"%s\" (%s:%d)\n", \ - STRINGIFY(expr), \ - __FILENAME__, \ - __LINE__); \ - action; \ - } +#define SU_ERROR(fmt, arg...) \ + su_logprintf( \ + SU_LOG_SEVERITY_ERROR, \ + SU_LOG_DOMAIN, \ + __FUNCTION__, \ + __LINE__, \ + fmt, \ + ##arg) + +#define SU_WARNING(fmt, arg...) \ + su_logprintf( \ + SU_LOG_SEVERITY_WARNING, \ + SU_LOG_DOMAIN, \ + __FUNCTION__, \ + __LINE__, \ + fmt, \ + ##arg) + +#define SU_INFO(fmt, arg...) \ + su_logprintf( \ + SU_LOG_SEVERITY_INFO, \ + SU_LOG_DOMAIN, \ + __FUNCTION__, \ + __LINE__, \ + fmt, \ + ##arg) void su_log_mask_severity(enum sigutils_log_severity sev); diff --git a/sigutils/matfile.c b/sigutils/matfile.c index 4c0a4ec..a1a7515 100644 --- a/sigutils/matfile.c +++ b/sigutils/matfile.c @@ -20,26 +20,27 @@ #define SU_LOG_DOMAIN "matfile" #include "matfile.h" -#include "log.h" -#include "version.h" #include #include -#define SU_MAT_FILE_VERSION 0x100 +#include "log.h" +#include "version.h" + +#define SU_MAT_FILE_VERSION 0x100 #define SU_MAT_FILE_ENDIANNESS (('M' << 8) | ('I')) -#define SU_MAT_FILE_ALIGNMENT 8 +#define SU_MAT_FILE_ALIGNMENT 8 #define SU_MAT_ALIGN(x) __ALIGN(x, SU_MAT_FILE_ALIGNMENT) -#define SU_MAT_miINT8 1 -#define SU_MAT_miUINT8 2 -#define SU_MAT_miINT16 3 +#define SU_MAT_miINT8 1 +#define SU_MAT_miUINT8 2 +#define SU_MAT_miINT16 3 #define SU_MAT_miUINT16 4 -#define SU_MAT_miINT32 5 +#define SU_MAT_miINT32 5 #define SU_MAT_miUINT32 6 #define SU_MAT_miSINGLE 7 #define SU_MAT_miDOUBLE 9 -#define SU_MAT_miINT64 12 +#define SU_MAT_miINT64 12 #define SU_MAT_miUINT64 13 #define SU_MAT_miMATRIX 14 @@ -56,20 +57,19 @@ struct sigutils_mat_tag { struct { uint16_t type; uint16_t size; - uint8_t data[4]; + uint8_t data[4]; } small; struct { uint32_t type; uint32_t size; - uint8_t data[0]; + uint8_t data[0]; } big; }; } __attribute__((packed)); -SUPRIVATE SUBOOL su_mat_file_dump_matrix( - su_mat_file_t *self, - const su_mat_matrix_t *matrix); +SUPRIVATE SUBOOL +su_mat_file_dump_matrix(su_mat_file_t *self, const su_mat_matrix_t *matrix); SUBOOL su_mat_matrix_resize(su_mat_matrix_t *self, int rows, int cols) @@ -126,7 +126,6 @@ su_mat_matrix_t * su_mat_matrix_new(const char *name, int rows, int cols) { su_mat_matrix_t *new = NULL; - int i; SU_TRYCATCH(rows > 0, goto fail); SU_TRYCATCH(new = calloc(1, sizeof(su_mat_matrix_t)), goto fail); @@ -162,8 +161,8 @@ void su_mat_matrix_discard_cols(su_mat_matrix_t *self) { self->col_start += self->cols; - self->cols = 0; - self->col_ptr = 0; + self->cols = 0; + self->col_ptr = 0; } SUBOOL @@ -204,7 +203,6 @@ su_mat_matrix_write_col(su_mat_matrix_t *self, ...) ok = su_mat_matrix_write_col_va(self, ap); -done: va_end(ap); return ok; @@ -213,7 +211,6 @@ su_mat_matrix_write_col(su_mat_matrix_t *self, ...) SUBOOL su_mat_matrix_write_col_array(su_mat_matrix_t *self, const SUFLOAT *x) { - int i; int ptr = self->col_ptr; if (ptr >= self->cols) @@ -263,16 +260,14 @@ su_mat_file_new(void) } int -su_mat_file_lookup_matrix_handle( - const su_mat_file_t *self, - const char *name) +su_mat_file_lookup_matrix_handle(const su_mat_file_t *self, const char *name) { unsigned int i; for (i = 0; i < self->matrix_count; ++i) if (self->matrix_list[i] != NULL && strcmp(self->matrix_list[i]->name, name) == 0) - return (int) i; + return (int)i; return -1; } @@ -280,7 +275,7 @@ su_mat_file_lookup_matrix_handle( su_mat_matrix_t * su_mat_file_get_matrix_by_handle(const su_mat_file_t *self, int handle) { - if (handle < 0 || handle >= (int) self->matrix_count) + if (handle < 0 || handle >= (int)self->matrix_count) return NULL; return self->matrix_list[handle]; @@ -299,9 +294,7 @@ su_mat_file_give_matrix(su_mat_file_t *self, su_mat_matrix_t *mat) { SUBOOL ok = SU_FALSE; - SU_TRYCATCH( - su_mat_file_lookup_matrix(self, mat->name) == NULL, - goto done); + SU_TRYCATCH(su_mat_file_lookup_matrix(self, mat->name) == NULL, goto done); SU_TRYCATCH(PTR_LIST_APPEND_CHECK(self->matrix, mat) != -1, goto done); @@ -311,17 +304,12 @@ su_mat_file_give_matrix(su_mat_file_t *self, su_mat_matrix_t *mat) return ok; } - SUBOOL -su_mat_file_give_streaming_matrix( - su_mat_file_t *self, - su_mat_matrix_t *mat) +su_mat_file_give_streaming_matrix(su_mat_file_t *self, su_mat_matrix_t *mat) { SUBOOL ok = SU_FALSE; - SU_TRYCATCH( - su_mat_file_lookup_matrix(self, mat->name) == NULL, - goto done); + SU_TRYCATCH(su_mat_file_lookup_matrix(self, mat->name) == NULL, goto done); if (self->fp != NULL && self->sm != NULL) SU_TRYCATCH(su_mat_file_flush(self), goto done); @@ -374,7 +362,6 @@ su_mat_file_stream_col(su_mat_file_t *self, ...) ok = su_mat_matrix_write_col_va(self->sm, ap); -done: va_end(ap); return ok; @@ -403,10 +390,7 @@ su_mat_file_make_streaming_matrix( } SUPRIVATE SUBOOL -su_mat_file_write_big_tag( - su_mat_file_t *self, - uint32_t type, - uint32_t size) +su_mat_file_write_big_tag(su_mat_file_t *self, uint32_t type, uint32_t size) { struct sigutils_mat_tag tag; tag.big.type = type; @@ -450,13 +434,9 @@ su_mat_file_write_tag( if (size <= 4) { return su_mat_file_write_small_tag(self, type, size, data); } else { - SU_TRYCATCH( - su_mat_file_write_big_tag(self, type, size), - return SU_FALSE); + SU_TRYCATCH(su_mat_file_write_big_tag(self, type, size), return SU_FALSE); - SU_TRYCATCH( - fwrite(data, size, 1, self->fp) == 1, - return SU_FALSE); + SU_TRYCATCH(fwrite(data, size, 1, self->fp) == 1, return SU_FALSE); SU_TRYCATCH( fwrite(&align_pad_data, align_pad_size, 1, self->fp) == 1, @@ -479,12 +459,10 @@ su_mat_file_write_int32(su_mat_file_t *self, int32_t val) } SUPRIVATE SUBOOL -su_mat_file_dump_matrix( - su_mat_file_t *self, - const su_mat_matrix_t *matrix) +su_mat_file_dump_matrix(su_mat_file_t *self, const su_mat_matrix_t *matrix) { uint32_t metadata_size = sizeof(struct sigutils_mat_tag) * 6; - uint32_t matrix_size = SU_MAT_ALIGN( + uint32_t matrix_size = SU_MAT_ALIGN( sizeof(SUFLOAT) * matrix->rows * (matrix->cols + matrix->col_start)); off_t last_off; uint32_t extra_size; @@ -510,25 +488,15 @@ su_mat_file_dump_matrix( /* Array flags */ SU_TRYCATCH( - su_mat_file_write_big_tag( - self, - SU_MAT_miUINT32, - 2 * sizeof(uint32_t)), - goto done); - SU_TRYCATCH( - su_mat_file_write_uint32(self, SU_MAT_mxSINGLE_CLASS), - goto done); - SU_TRYCATCH( - su_mat_file_write_uint32(self, 0), + su_mat_file_write_big_tag(self, SU_MAT_miUINT32, 2 * sizeof(uint32_t)), goto done); + SU_TRYCATCH(su_mat_file_write_uint32(self, SU_MAT_mxSINGLE_CLASS), goto done); + SU_TRYCATCH(su_mat_file_write_uint32(self, 0), goto done); /* Dimensions array */ SU_TRYCATCH( - su_mat_file_write_big_tag( - self, - SU_MAT_miINT32, - 2 * sizeof(int32_t)), - goto done); + su_mat_file_write_big_tag(self, SU_MAT_miINT32, 2 * sizeof(int32_t)), + goto done); SU_TRYCATCH(su_mat_file_write_int32(self, matrix->rows), goto done); SU_TRYCATCH( su_mat_file_write_int32(self, matrix->cols + matrix->col_start), @@ -547,22 +515,16 @@ su_mat_file_dump_matrix( if (matrix == self->sm) self->sm_contents_off = ftell(self->fp); SU_TRYCATCH( - su_mat_file_write_big_tag( - self, - SU_MAT_miSINGLE, - matrix_size), - goto done); + su_mat_file_write_big_tag(self, SU_MAT_miSINGLE, matrix_size), + goto done); for (i = 0; i < matrix->col_start * matrix->rows; ++i) SU_TRYCATCH(fwrite(&gap, sizeof(SUFLOAT), 1, self->fp) == 1, goto done); for (i = 0; i < matrix->cols; ++i) SU_TRYCATCH( - fwrite( - matrix->coef[i], - sizeof(SUFLOAT) * matrix->rows, - 1, - self->fp) == 1, + fwrite(matrix->coef[i], sizeof(SUFLOAT) * matrix->rows, 1, self->fp) + == 1, goto done); if (matrix == self->sm) @@ -604,14 +566,14 @@ su_mat_file_dump(su_mat_file_t *self, const char *path) goto done; } - memset(&header, 0, sizeof (struct sigutils_mat_header)); - memset(header.description, ' ', sizeof (header.description)); + memset(&header, 0, sizeof(struct sigutils_mat_header)); + memset(header.description, ' ', sizeof(header.description)); strcpy( header.description, "MATLAB 5.0 MAT-file, written by Sigutils " SIGUTILS_VERSION_STRING); - header.version = SU_MAT_FILE_VERSION; + header.version = SU_MAT_FILE_VERSION; header.endianness = SU_MAT_FILE_ENDIANNESS; SU_TRYCATCH( @@ -651,10 +613,9 @@ su_mat_file_flush(su_mat_file_t *self) off_t last_off; uint32_t extra_size; uint64_t pad = 0; - struct sigutils_mat_tag tag; uint32_t metadata_size = sizeof(struct sigutils_mat_tag) * 6; uint32_t matrix_size; - int total_cols; + uint64_t total_cols; SU_TRYCATCH(self->fp != NULL, goto done); @@ -668,9 +629,7 @@ su_mat_file_flush(su_mat_file_t *self) last_off = ftell(self->fp); if (self->sm_last_col < total_cols) { extra_size = - (total_cols - self->sm_last_col) - * self->sm->rows - * sizeof(SUFLOAT); + (total_cols - self->sm_last_col) * self->sm->rows * sizeof(SUFLOAT); /* Increment matrix size */ SU_TRYCATCH(fseek(self->fp, self->sm_off, SEEK_SET) != -1, goto done); @@ -681,7 +640,6 @@ su_mat_file_flush(su_mat_file_t *self) metadata_size + matrix_size), goto done); - /* Refresh matrix dimensions */ SU_TRYCATCH( fseek(self->fp, self->sm_off + 32, SEEK_SET) != -1, @@ -694,24 +652,19 @@ su_mat_file_flush(su_mat_file_t *self) fseek(self->fp, self->sm_contents_off, SEEK_SET) != -1, goto done); SU_TRYCATCH( - su_mat_file_write_big_tag( - self, - SU_MAT_miSINGLE, - matrix_size), + su_mat_file_write_big_tag(self, SU_MAT_miSINGLE, matrix_size), goto done); SU_TRYCATCH(fseek(self->fp, last_off, SEEK_SET) != -1, goto done); - for ( - i = self->sm_last_col - self->sm->col_start; - i < self->sm->cols; - ++i) + for (i = self->sm_last_col - self->sm->col_start; i < self->sm->cols; ++i) SU_TRYCATCH( fwrite( self->sm->coef[i], sizeof(SUFLOAT) * self->sm->rows, 1, - self->fp) == 1, + self->fp) + == 1, goto done); self->sm_last_col = total_cols; diff --git a/sigutils/matfile.h b/sigutils/matfile.h index 5039251..2b03ec0 100644 --- a/sigutils/matfile.h +++ b/sigutils/matfile.h @@ -20,9 +20,10 @@ #ifndef _SIGUTILS_MATFILE_H #define _SIGUTILS_MATFILE_H -#include "types.h" #include +#include "types.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -46,9 +47,7 @@ typedef struct sigutils_mat_matrix su_mat_matrix_t; SUINLINE SUFLOAT su_mat_matrix_get(const su_mat_matrix_t *self, int row, int col) { - if (row < 0 - || row >= self->rows - || col < 0 + if (row < 0 || row >= self->rows || col < 0 || col >= (self->cols + self->col_start)) return 0; @@ -65,8 +64,8 @@ SUBOOL su_mat_matrix_write_col(su_mat_matrix_t *, ...); SUBOOL su_mat_matrix_write_col_array(su_mat_matrix_t *, const SUFLOAT *); SUBOOL su_mat_matrix_set_col_ptr(su_mat_matrix_t *, int); SUBOOL su_mat_matrix_resize(su_mat_matrix_t *, int, int); -void su_mat_matrix_discard_cols(su_mat_matrix_t *); -void su_mat_matrix_destroy(su_mat_matrix_t *); +void su_mat_matrix_discard_cols(su_mat_matrix_t *); +void su_mat_matrix_destroy(su_mat_matrix_t *); struct sigutils_mat_file { PTR_LIST(su_mat_matrix_t, matrix); @@ -83,34 +82,26 @@ typedef struct sigutils_mat_file su_mat_file_t; su_mat_file_t *su_mat_file_new(void); -int su_mat_file_lookup_matrix_handle( - const su_mat_file_t *, - const char *); +int su_mat_file_lookup_matrix_handle(const su_mat_file_t *, const char *); -su_mat_matrix_t *su_mat_file_get_matrix_by_handle( - const su_mat_file_t *, - int); +su_mat_matrix_t *su_mat_file_get_matrix_by_handle(const su_mat_file_t *, int); -su_mat_matrix_t *su_mat_file_lookup_matrix( - const su_mat_file_t *, - const char *); +su_mat_matrix_t *su_mat_file_lookup_matrix(const su_mat_file_t *, const char *); SUBOOL su_mat_file_give_matrix(su_mat_file_t *, su_mat_matrix_t *); -SUBOOL su_mat_file_give_streaming_matrix( - su_mat_file_t *, - su_mat_matrix_t *); +SUBOOL su_mat_file_give_streaming_matrix(su_mat_file_t *, su_mat_matrix_t *); su_mat_matrix_t *su_mat_file_make_matrix( su_mat_file_t *self, const char *name, - int cols, - int rows); + int rows, + int cols); su_mat_matrix_t *su_mat_file_make_streaming_matrix( su_mat_file_t *self, const char *name, - int cols, - int rows); + int rows, + int cols); SUBOOL su_mat_file_stream_col(su_mat_file_t *, ...); diff --git a/sigutils/modem.c b/sigutils/modem.c deleted file mode 100644 index da1e029..0000000 --- a/sigutils/modem.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - -#include - -#define SU_LOG_LEVEL "modem" - -#include "log.h" -#include "modem.h" - -PTR_LIST(SUPRIVATE su_modem_class_t, modem_class); - -/**************** Modem class API **********************/ -su_modem_class_t * -su_modem_class_lookup(const char *name) -{ - su_modem_class_t *this = NULL; - - FOR_EACH_PTR_STANDALONE(this, modem_class) - if (strcmp(this->name, name) == 0) - return this; - - return NULL; -} - -SUBOOL -su_modem_class_register(su_modem_class_t *modem) -{ - if (su_modem_class_lookup(modem->name) != NULL) { - SU_ERROR("cannot register modem class: %s already exists\n", modem->name); - return SU_FALSE; - } - - if (PTR_LIST_APPEND_CHECK(modem_class, modem) == -1) { - SU_ERROR("cannot apend modem to modem list\n"); - return SU_FALSE; - } - - return SU_TRUE; -} - -/**************** Modem property API *******************/ -void -su_modem_property_destroy(su_modem_property_t *prop) -{ - if (prop->name != NULL) - free(prop->name); - - free(prop); -} - -su_modem_property_t * -su_modem_property_new(const char *name, su_property_type_t type) -{ - su_modem_property_t *new = NULL; - - if ((new = calloc(1, sizeof (su_modem_property_t))) == NULL) - goto fail; - - if ((new->name = strdup(name)) == NULL) - goto fail; - - new->type = type; - - /* Contents already initialized to zero */ - return new; - -fail: - if (new != NULL) - su_modem_property_destroy(new); - - return NULL; -} - -su_modem_property_t * -su_modem_property_set_lookup(const su_modem_property_set_t *set, const char *name) -{ - su_modem_property_t *this = NULL; - - FOR_EACH_PTR(this, set, property) - if (strcmp(this->name, name) == 0) - return this; - - return NULL; -} - -ssize_t -su_modem_property_get_value_marshalled_size(su_property_type_t type) -{ - switch (type) { - case SU_PROPERTY_TYPE_ANY: - return 0; - - case SU_PROPERTY_TYPE_BOOL: - return 1; - - case SU_PROPERTY_TYPE_INTEGER: - return sizeof(uint64_t); - - case SU_PROPERTY_TYPE_FLOAT: - return sizeof(SUFLOAT); - - case SU_PROPERTY_TYPE_COMPLEX: - return sizeof(SUCOMPLEX); - - case SU_PROPERTY_TYPE_OBJECT: - SU_ERROR("object properties cannot be marshalled\n"); - return -1; - - default: - return -1; - } -} - -SUBOOL -su_modem_property_copy( - su_modem_property_t *dst, - const su_modem_property_t *src) -{ - ssize_t size; - - if (dst->type != src->type) { - SU_ERROR("cannot overwrite property of mismatching type\n"); - return SU_FALSE; - } - - if ((size = su_modem_property_get_value_marshalled_size(src->type)) == -1) { - SU_ERROR( - "objects of type %s cannot be copied\n", - su_property_type_to_string(src->type)); - return SU_FALSE; - } - - memcpy(&dst->as_bytes, src->as_bytes, size); - - return SU_TRUE; -} - -SUPRIVATE SUBOOL -__su_modem_set_state_property_from_modem_property( - su_modem_t *modem, - su_property_t *state_prop, - const su_modem_property_t *prop) -{ - if (prop->type == SU_PROPERTY_TYPE_ANY - || prop->type == SU_PROPERTY_TYPE_OBJECT) { - SU_ERROR( - "cannot set properties of type %s\n", - su_property_type_to_string(prop->type)); - return SU_FALSE; - } else if (state_prop->type != prop->type) { - SU_ERROR( - "change of property `%s' rejected: type mismatch (%s != %s)\n", - prop->name, - su_property_type_to_string(state_prop->type), - su_property_type_to_string(prop->type)); - return SU_FALSE; - } - - if (!(modem->classptr->onpropertychanged)(modem->privdata, prop)) { - SU_ERROR("change of property `%s' rejected by modem\n", prop->name); - return SU_FALSE; - } - - switch (prop->type) { - case SU_PROPERTY_TYPE_BOOL: - *state_prop->bool_ptr = prop->as_bool; - break; - - case SU_PROPERTY_TYPE_COMPLEX: - *state_prop->complex_ptr = prop->as_complex; - break; - - case SU_PROPERTY_TYPE_FLOAT: - *state_prop->float_ptr = prop->as_float; - break; - - case SU_PROPERTY_TYPE_INTEGER: - *state_prop->int_ptr = prop->as_int; - break; - - default: - return SU_FALSE; - } - - return SU_TRUE; -} - -SUBOOL -su_modem_load_state_property(su_modem_t *modem, const su_modem_property_t *prop) -{ - su_property_t *state_prop; - - if ((state_prop = su_property_set_lookup( - &modem->state_properties, - prop->name)) != NULL) { - return __su_modem_set_state_property_from_modem_property( - modem, - state_prop, - prop); - } - - /* - * Attempting to set a state property that is not exposed by a modem is not - * an error. The property may be set from a default configuration that - * contains properties that may make sense for other modems. We just ignore - * it in this case. - */ - return SU_TRUE; -} - -SUBOOL -su_modem_load_all_state_properties(su_modem_t *modem) -{ - su_property_t *state_prop; - const su_modem_property_t *prop; - - FOR_EACH_PTR(state_prop, modem, state_properties.property) { - if ((prop = - su_modem_property_lookup_typed( - modem, - state_prop->name, - state_prop->type)) != NULL) { - if (!__su_modem_set_state_property_from_modem_property( - modem, - state_prop, - prop)) { - SU_ERROR("Failed to set state property `%s'\n", prop->name); - return SU_FALSE; - } - } else if (state_prop->mandatory) { - SU_ERROR( - "Mandatory %s property `%s' undefined\n", - su_property_type_to_string(state_prop->type), - state_prop->name); - return SU_FALSE; - } - } - - return SU_TRUE; -} - -SUPRIVATE ssize_t -su_modem_property_get_marshalled_size(const su_modem_property_t *prop) -{ - size_t size = 0; - ssize_t field_size = 0; - size_t tmp_size = 0; - size += sizeof(uint8_t); /* Property type */ - size += sizeof(uint8_t); /* Property name size */ - - if ((tmp_size = strlen(prop->name) + 1) > 255) { - SU_ERROR("property name is too long: %d, can't serialize\n", tmp_size); - return -1; - } - - size += tmp_size; /* Property name */ - - if ((field_size = su_modem_property_get_value_marshalled_size(prop->type)) - == -1) { - SU_ERROR( - "cannot marshall properties of type `%s'\n", - su_property_type_to_string(prop->type)); - return -1; - } - - size += field_size; - - return size; -} - - -SUPRIVATE ssize_t -su_modem_property_marshall( - const su_modem_property_t *prop, - void *buffer, - size_t buffer_size) -{ - uint8_t *as_bytes = NULL; - off_t ptr = 0; - size_t tmp_size = 0; - ssize_t prop_size = 0; - - if ((prop_size = su_modem_property_get_marshalled_size(prop)) == -1) { - SU_ERROR("cannot marshall property `%s'\n", prop->name); - return -1; - } - - if (buffer == NULL || buffer_size == 0) - return prop_size; - else if (buffer_size < prop_size) - return -1; - - as_bytes = (uint8_t *) buffer; - - tmp_size = strlen(prop->name) + 1; - - as_bytes[ptr++] = prop->type; - as_bytes[ptr++] = tmp_size; - - /* Marshall property name */ - memcpy(&as_bytes[ptr], prop->name, tmp_size); - ptr += tmp_size; - - /* Marshall property contents */ - tmp_size = su_modem_property_get_value_marshalled_size(prop->type); - memcpy(&as_bytes[ptr], prop->as_bytes, tmp_size); - ptr += tmp_size; - - return ptr; -} - -SUPRIVATE ssize_t -su_modem_property_unmarshall( - su_modem_property_t *prop, - const void *buffer, - size_t buffer_size) -{ - su_property_type_t type; - const uint8_t *as_bytes = NULL; - size_t name_size = 0; - size_t value_size = 0; - off_t ptr = 0; - const char *name_ptr = NULL; - const uint8_t *value = NULL; - - /* Minimum size: type + name size + null terminator */ - if (buffer_size < 3) - goto corrupted; - - as_bytes = (const uint8_t *) buffer; - type = as_bytes[ptr++]; - name_size = as_bytes[ptr++]; - - /* Does the name fit in the buffer? */ - if (ptr + name_size > buffer_size) - goto corrupted; - - /* Is it a null-terminated string? */ - name_ptr = (const char *) &as_bytes[ptr]; - if (name_ptr[name_size - 1] != 0) - goto corrupted; - ptr += name_size; - - /* Does field contents fit in the buffer? */ - value_size = su_modem_property_get_value_marshalled_size(type); - if (ptr + value_size > buffer_size) - goto corrupted; - value = (const uint8_t *) &as_bytes[ptr]; - ptr += value_size; - - /* All required data is available, initialize property */ - if ((prop->name = strdup(name_ptr)) == NULL) { - SU_ERROR("cannot allocate memory for property name\n"); - return -1; - } - - prop->type = type; - memcpy(prop->as_bytes, value, value_size); - - return ptr; - -corrupted: - SU_ERROR("corrupted property\n"); - - return -1; -} - -/****************** Property Set API *******************/ -void -su_modem_property_set_init(su_modem_property_set_t *set) -{ - memset(set, 0, sizeof (su_modem_property_set_t)); -} - -su_modem_property_t * -su_modem_property_set_assert_property( - su_modem_property_set_t *set, - const char *name, - su_property_type_t type) -{ - su_modem_property_t *prop = NULL; - - if ((prop = su_modem_property_set_lookup(set, name)) == NULL) { - if ((prop = su_modem_property_new(name, type)) == NULL) { - SU_ERROR( - "failed to create new %s property", - su_property_type_to_string(type)); - return NULL; - } - - if (PTR_LIST_APPEND_CHECK(set->property, prop) == -1) { - SU_ERROR( - "failed to append new %s property", - su_property_type_to_string(type)); - su_modem_property_destroy(prop); - return NULL; - } - } else if (prop->type != type) { - SU_ERROR( - "property `%s' found, mismatching type (req: %s, found: %s)\n", - name, - su_property_type_to_string(type), - su_property_type_to_string(prop->type)); - return NULL; - } - - return prop; -} - -SUPRIVATE size_t -su_modem_property_set_get_marshalled_size(const su_modem_property_set_t *set) -{ - size_t size = 0; - ssize_t prop_size = 0; - const su_modem_property_t *this = NULL; - - size = sizeof(uint16_t); /* Property counter */ - - FOR_EACH_PTR(this, set, property) - if ((prop_size = su_modem_property_get_marshalled_size(this)) > 0) - size += prop_size; - - return size; -} - -ssize_t -su_modem_property_set_marshall( - const su_modem_property_set_t *set, - void *buffer, - size_t buffer_size) -{ - size_t marshalled_size = 0; - ssize_t prop_size; - const su_modem_property_t *this = NULL; - off_t ptr = 0; - uint8_t *as_bytes = NULL; - unsigned int count = 0; - - marshalled_size = su_modem_property_set_get_marshalled_size(set); - - if (buffer == NULL || buffer_size == 0) - return marshalled_size; - - if (buffer_size < marshalled_size) - return -1; - - as_bytes = (uint8_t *) buffer; - - ptr = 2; - - FOR_EACH_PTR(this, set, property) { - if ((prop_size = su_modem_property_get_marshalled_size(this)) > 0) { - if ((prop_size = su_modem_property_marshall( - this, - &as_bytes[ptr], - buffer_size - ptr)) < 0) { - SU_ERROR("failed to marshall property `%s'\n", this->name); - return -1; - } - - ptr += prop_size; - if ((uint16_t) ++count == 0) { - SU_ERROR("too many properties (%d)\n", count); - return -1; - } - } else { - SU_WARNING("cannot marshall property `%s', skipping\n", this->name); - } - } - - *((uint16_t *) as_bytes) = count; - - return ptr; -} - -ssize_t -su_modem_property_set_unmarshall( - su_modem_property_set_t *set, - const void *buffer, - size_t buffer_size) -{ - uint16_t count = 0; - unsigned int i = 0; - off_t ptr = 0; - ssize_t prop_size = 0; - su_modem_property_t *prop = NULL; - const uint8_t *as_bytes = NULL; - - if (buffer_size < 2) - goto corrupted; - - as_bytes = (const uint8_t *) buffer; - count = *((const uint16_t *) as_bytes); - - ptr += 2; - - su_modem_property_set_init(set); - - for (i = 0; i < count; ++i) { - if ((prop = calloc(1, sizeof (su_modem_property_t))) == NULL) { - SU_ERROR("cannot allocate new property\n"); - return -1; - } - - if ((prop_size = su_modem_property_unmarshall( - prop, - &as_bytes[ptr], - buffer_size - ptr)) < 0) { - /* Property can be easily freed here */ - free(prop); - goto corrupted; - } - - ptr += prop_size; - - /* TODO: what happens if there are two properties with the same name? */ - if (PTR_LIST_APPEND_CHECK(set->property, prop) == -1) { - SU_ERROR("cannot append new property\n"); - su_modem_property_destroy(prop); - return -1; - } - } - - return ptr; - -corrupted: - SU_ERROR("corrupted marshalled properties\n(su_modem_t *modem,"); - - return -1; -} - -SUBOOL -su_modem_property_set_copy( - su_modem_property_set_t *dest, - const su_modem_property_set_t *src) -{ - su_modem_property_t *this = NULL; - su_modem_property_t *dst_prop = NULL; - - FOR_EACH_PTR(this, src, property) { - if ((dst_prop = su_modem_property_set_assert_property(dest, this->name, this->type)) - == NULL) { - SU_ERROR("failed to assert property `%s'\n", this->name); - return SU_FALSE; - } - - if (!su_modem_property_copy(dst_prop, this)) { - SU_ERROR("failed to copy property `%s'\n", this->name); - return SU_FALSE; - } - } - - return SU_TRUE; -} - -void -su_modem_property_set_finalize(su_modem_property_set_t *set) -{ - su_modem_property_t *this = NULL; - - FOR_EACH_PTR(this, set, property) - su_modem_property_destroy(this); - - if (set->property_list != NULL) - free(set->property_list); -} - -/****************** Modem API *******************/ -void -su_modem_destroy(su_modem_t *modem) -{ - su_block_t *this = NULL; - - if (modem->privdata != NULL) - (modem->classptr->dtor) (modem->privdata); - - FOR_EACH_PTR(this, modem, block) - su_block_destroy(this); - - if (modem->block_list != NULL) - free(modem->block_list); - - su_modem_property_set_finalize(&modem->properties); - su_property_set_finalize(&modem->state_properties); - - free(modem); -} - -su_modem_t * -su_modem_new(const char *class_name) -{ - su_modem_t *new = NULL; - su_modem_class_t *class = NULL; - - if ((class = su_modem_class_lookup(class_name)) == NULL) { - SU_ERROR("modem class `%s' not registered\n", class_name); - goto fail; - } - - if ((new = calloc(1, sizeof(su_modem_t))) == NULL) - goto fail; - - new->classptr = class; - - return new; - -fail: - if (new != NULL) - su_modem_destroy(new); - - return NULL; -} - -SUBOOL -su_modem_set_source(su_modem_t *modem, su_block_t *src) -{ - if (modem->privdata != NULL) { - SU_ERROR("cannot set source while modem has started\n"); - return SU_FALSE; - } - - modem->source = src; - - return SU_TRUE; -} - -SUBOOL -su_modem_set_wav_source(su_modem_t *modem, const char *path) -{ - su_block_t *wav_block = NULL; - const uint64_t *samp_rate = NULL; - - if ((wav_block = su_block_new("wavfile", path)) == NULL) - goto fail; - - if ((samp_rate = su_block_get_property_ref( - wav_block, - SU_PROPERTY_TYPE_INTEGER, - "samp_rate")) == NULL) { - SU_ERROR("failed to acquire wav file sample rate\n"); - goto fail; - } - - if (!su_modem_register_block(modem, wav_block)) { - SU_ERROR("failed to register wav source\n"); - su_block_destroy(wav_block); - goto fail; - } - if (!su_modem_set_int(modem, "samp_rate", *samp_rate)) { - SU_ERROR("failed to set modem sample rate\n"); - goto fail; - } - - if (!su_modem_set_source(modem, wav_block)) - goto fail; - - return SU_TRUE; - -fail: - if (wav_block != NULL) - su_block_destroy(wav_block); - - return SU_FALSE; -} - -SUBOOL -su_modem_register_block(su_modem_t *modem, su_block_t *block) -{ - return PTR_LIST_APPEND_CHECK(modem->block, block) != -1; -} - -SUBOOL -su_modem_expose_state_property( - su_modem_t *modem, - const char *name, - su_property_type_t type, - SUBOOL mandatory, - void *ptr) -{ - su_property_t *state_property = NULL; - uint64_t old; - - if ((state_property = __su_property_set_assert_property( - &modem->state_properties, - name, - type, - mandatory)) == NULL) - return SU_FALSE; - - state_property->generic_ptr = ptr; - - return SU_TRUE; -} - -void * -su_modem_get_state_property_ref( - const su_modem_t *modem, - const char *name, - su_property_type_t type) -{ - su_property_t *state_property; - - if ((state_property = su_property_set_lookup(&modem->state_properties, name)) - == NULL) - return NULL; - - if (state_property->type != type) { - SU_WARNING( - "Property found, wrong type (`%s' is %s)\n", - name, - su_property_type_to_string(state_property->type)); - return NULL; - } - - return state_property->generic_ptr; -} - -SUBOOL -su_modem_set_int(su_modem_t *modem, const char *name, uint64_t val) -{ - su_modem_property_t *prop = NULL; - uint64_t old; - - if ((prop = su_modem_property_set_assert_property( - &modem->properties, - name, - SU_PROPERTY_TYPE_INTEGER)) == NULL) - return SU_FALSE; - - old = prop->as_int; - prop->as_int = val; - - if (!su_modem_load_state_property(modem, prop)) { - SU_ERROR("change of property `%s' rejected\n", name); - prop->as_int = old; - return SU_FALSE; - } - - return SU_TRUE; -} - -SUBOOL -su_modem_set_float(su_modem_t *modem, const char *name, SUFLOAT val) -{ - su_modem_property_t *prop = NULL; - - SUFLOAT old; - - if ((prop = su_modem_property_set_assert_property( - &modem->properties, - name, - SU_PROPERTY_TYPE_FLOAT)) == NULL) - return SU_FALSE; - - old = prop->as_float; - prop->as_float = val; - - if (!su_modem_load_state_property(modem, prop)) { - SU_ERROR("change of property `%s' rejected\n", name); - prop->as_float = old; - - return SU_FALSE; - } - - - return SU_TRUE; -} - -SUBOOL -su_modem_set_complex(su_modem_t *modem, const char *name, SUCOMPLEX val) -{ - su_modem_property_t *prop = NULL; - SUCOMPLEX old; - - if ((prop = su_modem_property_set_assert_property( - &modem->properties, - name, - SU_PROPERTY_TYPE_COMPLEX)) == NULL) - return SU_FALSE; - - old = prop->as_complex; - prop->as_complex = val; - - if (!su_modem_load_state_property(modem, prop)) { - SU_ERROR("change of property `%s' rejected\n", name); - prop->as_complex = old; - return SU_FALSE; - } - - - return SU_TRUE; -} - -SUBOOL -su_modem_set_bool(su_modem_t *modem, const char *name, SUBOOL val) -{ - su_modem_property_t *prop = NULL; - SUBOOL old; - - if ((prop = su_modem_property_set_assert_property( - &modem->properties, - name, - SU_PROPERTY_TYPE_BOOL)) == NULL) - return SU_FALSE; - - old = prop->as_bool; - prop->as_bool = val; - - if (!su_modem_load_state_property(modem, prop)) { - SU_ERROR("change of property `%s' rejected\n", name); - prop->as_bool = old; - return SU_FALSE; - } - - return SU_TRUE; -} - -SUBOOL -su_modem_set_ptr(su_modem_t *modem, const char *name, void *val) -{ - su_modem_property_t *prop = NULL; - void *old; - - if ((prop = su_modem_property_set_assert_property( - &modem->properties, - name, - SU_PROPERTY_TYPE_OBJECT)) == NULL) - return SU_FALSE; - - old = prop->as_ptr; - prop->as_ptr = val; - - if (!su_modem_load_state_property(modem->privdata, prop)) { - SU_ERROR("change of property `%s' rejected\n", name); - prop->as_ptr = old; - - return SU_FALSE; - } - - - return SU_TRUE; -} - -const su_modem_property_t * -su_modem_property_lookup(const su_modem_t *modem, const char *name) -{ - return su_modem_property_set_lookup(&modem->properties, name); -} - -const su_modem_property_t * -su_modem_property_lookup_typed( - const su_modem_t *modem, - const char *name, - su_property_type_t type) -{ - const su_modem_property_t *prop = NULL; - - if ((prop = su_modem_property_lookup(modem, name)) == NULL) - return NULL; - else if (prop->type != type) { - SU_ERROR( - "Property `%s' is of type `%s', but `%s' was expected\n", - name, - su_property_type_to_string(prop->type), - su_property_type_to_string(type)); - return NULL; - } - - return prop; -} - -SUBOOL -su_modem_set_properties(su_modem_t *modem, const su_modem_property_set_t *set) -{ - su_modem_property_t *this = NULL; - su_modem_property_t *dst_prop = NULL; - - FOR_EACH_PTR(this, set, property) { - if ((dst_prop = su_modem_property_set_assert_property( - &modem->properties, - this->name, - this->type)) == NULL) { - SU_ERROR("failed to assert property `%s'\n", this->name); - return SU_FALSE; - } - - /* This is not necessarily an error */ - if (!(modem->classptr->onpropertychanged)(modem->privdata, this)) { - SU_WARNING("property `%s' cannot be changed\n", this->name); - continue; - } - - if (!su_modem_property_copy(dst_prop, this)) { - SU_ERROR("failed to copy property `%s'\n", this->name); - return SU_FALSE; - } - } - - return SU_TRUE; -} - -SUBOOL -su_modem_plug_to_source(su_modem_t *modem, su_block_t *first) -{ - if (modem->source == NULL) { - SU_ERROR("source not defined\n"); - return SU_FALSE; - } - - return su_block_plug(modem->source, 0, 0, first); -} - -SUBOOL -su_modem_get_properties(const su_modem_t *modem, su_modem_property_set_t *set) -{ - return su_modem_property_set_copy(set, &modem->properties); -} - -SUBOOL -su_modem_start(su_modem_t *modem) -{ - if (modem->source == NULL) { - SU_ERROR("cannot start modem: source not defined\n"); - return SU_FALSE; - } - - if (!(modem->classptr->ctor)(modem, &modem->privdata)) { - SU_ERROR("failed to start modem\n"); - modem->privdata = NULL; - - return SU_FALSE; - } - - return SU_TRUE; -} - -SUSYMBOL -su_modem_read(su_modem_t *modem) -{ - if (modem->privdata == NULL) { - SU_ERROR("modem not started\n"); - return SU_EOS; - } - - return (modem->classptr->read_sym)(modem, modem->privdata); -} - -SUCOMPLEX -su_modem_read_sample(su_modem_t *modem) -{ - if (modem->privdata == NULL) { - SU_ERROR("modem not started\n"); - return SU_EOS; - } - - return (modem->classptr->read_sample)(modem, modem->privdata); -} - -SUFLOAT -su_modem_get_fec(su_modem_t *modem) -{ - if (modem->privdata == NULL) { - SU_ERROR("modem not started\n"); - return 0; - } - - return modem->fec; -} - -SUFLOAT -su_modem_get_snr(su_modem_t *modem) -{ - if (modem->privdata == NULL) { - SU_ERROR("modem not started\n"); - return 0; - } - - return modem->snr; -} - -SUFLOAT -su_modem_get_signal(su_modem_t *modem) -{ - if (modem->privdata == NULL) { - SU_ERROR("modem not started\n"); - return 0; - } - - return modem->signal; -} - -void -su_modem_set_fec(su_modem_t *modem, SUFLOAT fec) -{ - modem->fec = fec; -} - -void -su_modem_set_snr(su_modem_t *modem, SUFLOAT snr) -{ - modem->snr = snr; -} - -void -su_modem_set_signal(su_modem_t *modem, SUFLOAT signal) -{ - modem->signal = signal; -} - diff --git a/sigutils/modem.h b/sigutils/modem.h deleted file mode 100644 index 97cf13f..0000000 --- a/sigutils/modem.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ - -#ifndef _SIGUTILS_MODEM_H -#define _SIGUTILS_MODEM_H - -#include -#include "types.h" -#include "block.h" - -#ifdef __cplusplus -# ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wreturn-type-c-linkage" -# endif // __clang__ -extern "C" { -#endif /* __cplusplus */ - -typedef struct sigutils_modem_class su_modem_class_t; - -struct sigutils_modem_property { - su_property_type_t type; - char *name; - - union { - uint64_t as_int; - SUFLOAT as_float; - SUCOMPLEX as_complex; - SUBOOL as_bool; - void *as_ptr; - uint8_t as_bytes[0]; - }; -}; - -typedef struct sigutils_modem_property su_modem_property_t; - -struct sigutils_modem_property_set { - PTR_LIST(su_modem_property_t, property); -}; - -typedef struct sigutils_modem_property_set su_modem_property_set_t; - -struct sigutils_modem; - -struct sigutils_modem_class { - const char *name; - - SUBOOL (*ctor) (struct sigutils_modem *, void **); - SUSYMBOL (*read_sym) (struct sigutils_modem *, void *); - SUCOMPLEX (*read_sample) (struct sigutils_modem *, void *); - SUBOOL (*onpropertychanged) (void *, const su_modem_property_t *); - void (*dtor) (void *); -}; - -struct sigutils_modem { - struct sigutils_modem_class *classptr; - void *privdata; - - SUFLOAT signal; /* signal indicator */ - SUFLOAT fec; /* FEC quality indicator */ - SUFLOAT snr; /* SNR ratio */ - su_block_t *source; /* Loaned */ - PTR_LIST(su_block_t, block); /* Owned */ - su_modem_property_set_t properties; - su_property_set_t state_properties; -}; - -typedef struct sigutils_modem su_modem_t; - -/**************** Modem class API **************************/ -su_modem_class_t *su_modem_class_lookup(const char *name); - -SUBOOL su_modem_class_register(su_modem_class_t *modem); - -/**************** Modem property set API *******************/ -void su_modem_property_set_init(su_modem_property_set_t *set); - -su_modem_property_t *su_modem_property_set_lookup( - const su_modem_property_set_t *set, - const char *name); - -su_modem_property_t *su_modem_property_set_assert_property( - su_modem_property_set_t *set, - const char *name, - su_property_type_t type); - -ssize_t su_modem_property_set_marshall( - const su_modem_property_set_t *set, - void *buffer, - size_t buffer_size); - -ssize_t su_modem_property_set_unmarshall( - su_modem_property_set_t *dest, - const void *buffer, - size_t buffer_size); - -SUBOOL su_modem_property_set_copy( - su_modem_property_set_t *dest, - const su_modem_property_set_t *src); - -void su_modem_property_set_finalize(su_modem_property_set_t *set); - -/****************** Modem API *******************/ -su_modem_t *su_modem_new(const char *class_name); - -SUBOOL su_modem_set_source(su_modem_t *modem, su_block_t *src); - -SUBOOL su_modem_set_wav_source(su_modem_t *modem, const char *path); - -SUBOOL su_modem_register_block(su_modem_t *modem, su_block_t *block); - -SUBOOL su_modem_plug_to_source(su_modem_t *modem, su_block_t *first); - -SUBOOL su_modem_expose_state_property( - su_modem_t *modem, - const char *name, - su_property_type_t type, - SUBOOL mandatory, - void *ptr); - -void *su_modem_get_state_property_ref( - const su_modem_t *modem, - const char *name, - su_property_type_t type); - -SUBOOL su_modem_load_state_property( - su_modem_t *modem, - const su_modem_property_t *prop); -SUBOOL su_modem_load_all_state_properties(su_modem_t *modem); -SUBOOL su_modem_set_int(su_modem_t *modem, const char *name, uint64_t val); -SUBOOL su_modem_set_float(su_modem_t *modem, const char *name, SUFLOAT val); -SUBOOL su_modem_set_complex(su_modem_t *modem, const char *name, SUCOMPLEX val); -SUBOOL su_modem_set_bool(su_modem_t *modem, const char *name, SUBOOL val); -SUBOOL su_modem_set_ptr(su_modem_t *modem, const char *name, void *); - -const su_modem_property_t *su_modem_property_lookup( - const su_modem_t *modem, - const char *name); - -const su_modem_property_t * -su_modem_property_lookup_typed( - const su_modem_t *modem, - const char *name, - su_property_type_t type); - -SUBOOL su_modem_set_properties( - su_modem_t *modem, - const su_modem_property_set_t *set); - -SUBOOL su_modem_get_properties( - const su_modem_t *modem, - su_modem_property_set_t *set); - -SUBOOL su_modem_start(su_modem_t *modem); - -SUSYMBOL su_modem_read(su_modem_t *modem); /* Returns a stream of symbols */ -SUCOMPLEX su_modem_read_sample(su_modem_t *modem); -SUFLOAT su_modem_get_fec(su_modem_t *modem); /* Returns FEC quality */ -SUFLOAT su_modem_get_snr(su_modem_t *modem); /* Returns SNR magnitude */ -SUFLOAT su_modem_get_signal(su_modem_t *modem); /* Signal indicator */ - -/* This functions are to be used by modem implementations */ -void su_modem_set_fec(su_modem_t *modem, SUFLOAT fec); -void su_modem_set_snr(su_modem_t *modem, SUFLOAT snr); -void su_modem_set_signal(su_modem_t *modem, SUFLOAT signal); - -void su_modem_destroy(su_modem_t *modem); - -#ifdef __cplusplus -# ifdef __clang__ -# pragma clang diagnostic pop -# endif // __clang__ -} -#endif /* __cplusplus */ - -#endif /* _SIGUTILS_MODEM_H */ diff --git a/sigutils/modems/qpsk.c b/sigutils/modems/qpsk.c deleted file mode 100644 index 5d7e4f6..0000000 --- a/sigutils/modems/qpsk.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ - -#include -#include - -#define SU_LOG_LEVEL "qpsk-modem" - -#include "log.h" -#include "sampling.h" -#include "modem.h" -#include "agc.h" -#include "pll.h" - -#define SU_QPSK_MODEM_COSTAS_LOOP_ARM_FILTER_ORDER 3 -#define SU_QPSK_MODEM_ARM_BANDWIDTH_FACTOR 2 -#define SU_QPSK_MODEM_LOOP_BANDWIDTH_FACTOR 1e-1 -#define SU_QPSK_MODEM_GAIN_DEFAULT .70711 -#define SU_QPSK_MODEM_RRC_ROLL_OFF_DEFAULT .25 -#define SU_QPSK_MODEM_RRC_SPAN_DEFAULT 6 -#define SU_QPSK_MODEM_SYMBOL_QUEUE_SIZE 256 - -struct qpsk_modem { - SUSCOUNT fs; /* Sampling frequency */ - - SUFLOAT baud; - SUFLOAT arm_bw; /* Arm filter bandwidth */ - SUFLOAT loop_bw; /* Loop bandwidth */ - SUSCOUNT mf_span; /* RRC filter span in symbols */ - SUFLOAT rolloff; /* Rolloff factor */ - SUFLOAT fc; /* Carrier frequency */ - - SUBOOL abc; /* Enable Automatic Baudrate Control */ - SUBOOL afc; /* Enable Automatic Frequency Control */ - - /* Property references */ - SUFLOAT *fc_ref; - - /* Blocks */ - su_block_t *cdr_block; - su_block_t *costas_block; - su_block_t *agc_block; - su_block_t *rrc_block; - - su_block_port_t port; -}; - -void -su_qpsk_modem_dtor(void *private) -{ - free(private); -} - -#define SU_QPSK_MODEM_CREATE_BLOCK(dest, expr) \ - if ((dest = expr) == NULL) { \ - SU_ERROR("operation failed: " STRINGIFY(expr) "\n"); \ - goto fail; \ - } \ - \ - if (!su_modem_register_block(modem, dest)) { \ - SU_ERROR("failed to register block\n"); \ - su_block_destroy(dest); \ - goto fail; \ - } - -#define SU_QPSK_MODEM_INT_PROPERTY(dest, name) \ - if (!su_modem_expose_state_property( \ - modem, \ - name, \ - SU_PROPERTY_TYPE_INTEGER, \ - SU_TRUE, \ - &dest)) { \ - SU_ERROR( \ - "cannot initialize modem: can't expose `%s' property\n", \ - name); \ - goto fail; \ - } - -#define SU_QPSK_MODEM_FLOAT_PROPERTY(dest, name) \ - if (!su_modem_expose_state_property( \ - modem, \ - name, \ - SU_PROPERTY_TYPE_FLOAT, \ - SU_TRUE, \ - &dest)) { \ - SU_ERROR( \ - "cannot initialize modem: can't expose `%s' property\n", \ - name); \ - goto fail; \ - } - -#define SU_QPSK_MODEM_BOOL_PROPERTY(dest, name) \ - if (!su_modem_expose_state_property( \ - modem, \ - name, \ - SU_PROPERTY_TYPE_BOOL, \ - SU_TRUE, \ - &dest)) { \ - SU_ERROR( \ - "cannot initialize modem: can't expose `%s' property\n", \ - name); \ - goto fail; \ - } - -SUBOOL -su_qpsk_modem_ctor(su_modem_t *modem, void **private) -{ - struct qpsk_modem *new = NULL; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - const su_modem_property_t *prop; - SUFLOAT *rrc_gain = NULL; - SUFLOAT *cdr_alpha = NULL; - SUFLOAT *cdr_beta = NULL; - SUFLOAT *costas_beta = NULL; - - if ((new = calloc(1, sizeof(struct qpsk_modem))) == NULL) - goto fail; - - SU_QPSK_MODEM_INT_PROPERTY(new->fs, "samp_rate"); - SU_QPSK_MODEM_INT_PROPERTY(new->mf_span, "mf_span"); - SU_QPSK_MODEM_BOOL_PROPERTY(new->abc, "abc"); - SU_QPSK_MODEM_BOOL_PROPERTY(new->afc, "afc"); - - SU_QPSK_MODEM_FLOAT_PROPERTY(new->baud, "baud"); - SU_QPSK_MODEM_FLOAT_PROPERTY(new->rolloff, "rolloff"); - SU_QPSK_MODEM_FLOAT_PROPERTY(new->fc, "fc"); - - if (!su_modem_load_all_state_properties(modem)) { - SU_ERROR("cannot initialize modem: failed to load mandatory properties\n"); - goto fail; - } - - new->arm_bw = SU_QPSK_MODEM_ARM_BANDWIDTH_FACTOR * new->baud; - new->loop_bw = SU_QPSK_MODEM_LOOP_BANDWIDTH_FACTOR * new->baud; - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - /* Create blocks */ - SU_QPSK_MODEM_CREATE_BLOCK( - new->agc_block, - su_block_new("agc", &agc_params)); - - SU_QPSK_MODEM_CREATE_BLOCK( - new->costas_block, - su_block_new( - "costas", - SU_COSTAS_KIND_QPSK, - SU_ABS2NORM_FREQ(new->fs, new->fc), - SU_ABS2NORM_FREQ(new->fs, new->arm_bw), - SU_QPSK_MODEM_COSTAS_LOOP_ARM_FILTER_ORDER, - SU_ABS2NORM_FREQ(new->fs, new->loop_bw))); - - SU_QPSK_MODEM_CREATE_BLOCK( - new->rrc_block, - su_block_new( - "rrc", - (unsigned int) (new->mf_span * SU_T2N_FLOAT(new->fs, 1./ new->baud)), - SU_T2N_FLOAT(new->fs, 1./ new->baud), - new->rolloff)); - - SU_QPSK_MODEM_CREATE_BLOCK( - new->cdr_block, - su_block_new( - "cdr", - (SUFLOAT) 1., - SU_ABS2NORM_BAUD(new->fs, new->baud), - SU_QPSK_MODEM_SYMBOL_QUEUE_SIZE)); - - /* Expose some properties */ - if ((new->fc_ref = su_block_get_property_ref( - new->costas_block, - SU_PROPERTY_TYPE_FLOAT, - "f")) == NULL) { - SU_ERROR("Cannot find f property in Costas block\n"); - goto fail; - } - - /* Tweak others properties */ - if ((rrc_gain = su_block_get_property_ref( - new->rrc_block, - SU_PROPERTY_TYPE_FLOAT, - "gain")) == NULL) { - SU_ERROR("Cannot find gain property in RRC block\n"); - goto fail; - } - - if ((cdr_alpha = su_block_get_property_ref( - new->cdr_block, - SU_PROPERTY_TYPE_FLOAT, - "alpha")) == NULL) { - SU_ERROR("Cannot find alpha property in CDR block\n"); - goto fail; - } - - if ((cdr_beta = su_block_get_property_ref( - new->cdr_block, - SU_PROPERTY_TYPE_FLOAT, - "beta")) == NULL) { - SU_ERROR("Cannot find beta property in CDR block\n"); - goto fail; - } - - if ((costas_beta = su_block_get_property_ref( - new->costas_block, - SU_PROPERTY_TYPE_FLOAT, - "beta")) == NULL) { - SU_ERROR("Cannot find beta property in Costas block\n"); - goto fail; - } - - - *rrc_gain = 5; - *cdr_alpha *= .75; - - if (!new->abc) - *cdr_beta = 0; /* Disable baudrate control */ - - if (!new->afc) - *costas_beta = 0; /* Disable frequency control */ - - /* Plug everything */ - if (!su_modem_plug_to_source(modem, new->agc_block)) - goto fail; - - if (!su_block_plug(new->agc_block, 0, 0, new->costas_block)) - goto fail; - - if (!su_block_plug(new->costas_block, 0, 0, new->rrc_block)) - goto fail; - - if (!su_block_plug(new->rrc_block, 0, 0, new->cdr_block)) - goto fail; - - if (!su_block_port_plug(&new->port, new->cdr_block, 0)) - goto fail; - - *private = new; - - return SU_TRUE; - -fail: - if (new != NULL) - su_qpsk_modem_dtor(new); - - return SU_FALSE; -} - -SUBOOL -su_qpsk_modem_onpropertychanged(void *private, const su_modem_property_t *prop) -{ - return SU_TRUE; -} - -SUPRIVATE void -su_qpsk_modem_update_state(struct qpsk_modem *modem) -{ - modem->fc = SU_NORM2ABS_FREQ(modem->fs, *modem->fc_ref); -} - -SUCOMPLEX -su_qpsk_modem_read_sample(su_modem_t *modem, void *private) -{ - struct qpsk_modem *qpsk_modem = (struct qpsk_modem *) private; - SUSDIFF got = 0; - SUCOMPLEX sample; - SUSYMBOL sym = 0; - - if ((got = su_block_port_read(&qpsk_modem->port, &sample, 1)) == 0) - return nan("nosym"); - else if (got < 0) - return nan("eos"); - - su_qpsk_modem_update_state(qpsk_modem); - - return sample; -} - -SUSYMBOL -su_qpsk_modem_read_sym(su_modem_t *modem, void *private) -{ - struct qpsk_modem *qpsk_modem = (struct qpsk_modem *) private; - SUSDIFF got = 0; - SUCOMPLEX sample; - SUSYMBOL sym = 0; - - if ((got = su_block_port_read(&qpsk_modem->port, &sample, 1)) == 0) - return SU_NOSYMBOL; - else if (got < 0) - return SU_EOS; - - sym = 3 & (SUSYMBOL) floor(2 * (SU_C_ARG(sample) + M_PI) / M_PI); - - su_qpsk_modem_update_state(qpsk_modem); - - return sym + 1; -} - -struct sigutils_modem_class su_modem_class_QPSK = { - "qpsk", /* name */ - su_qpsk_modem_ctor, /* ctor */ - su_qpsk_modem_read_sym, /* read_sym */ - su_qpsk_modem_read_sample, /* read_sample */ - su_qpsk_modem_onpropertychanged, /* onpropertychanged */ - su_qpsk_modem_dtor, /* dtor */ -}; diff --git a/sigutils/ncqo.c b/sigutils/ncqo.c index 46a9598..65830d6 100644 --- a/sigutils/ncqo.c +++ b/sigutils/ncqo.c @@ -19,6 +19,7 @@ #define _GNU_SOURCE #include +#include #define SU_LOG_DOMAIN "ncqo" @@ -27,29 +28,50 @@ #include "sampling.h" /* Expects: relative frequency */ -void -su_ncqo_init(su_ncqo_t *ncqo, SUFLOAT fnor) +SU_CONSTRUCTOR_TYPED(void, su_ncqo, SUFLOAT fnor) { - ncqo->phi = .0; - ncqo->omega = SU_NORM2ANG_FREQ(fnor); - ncqo->fnor = fnor; - ncqo->sin = 0; - ncqo->cos = 1; + self->phi = .0; + self->omega = SU_NORM2ANG_FREQ(fnor); + self->fnor = fnor; + self->sin = 0; + self->cos = 1; #ifdef SU_NCQO_USE_PRECALC_BUFFER - ncqo->p = 0; - ncqo->pre_c = SU_FALSE; + self->p = 0; + self->pre_c = SU_FALSE; #endif /* SU_NCQO_USE_PRECALC_BUFFER */ } -void -su_ncqo_init_fixed(su_ncqo_t *ncqo, SUFLOAT fnor) +SU_METHOD(su_ncqo, void, init_fixed, SUFLOAT fnor) { - su_ncqo_init(ncqo, fnor); + su_ncqo_init(self, fnor); #ifdef SU_NCQO_USE_PRECALC_BUFFER - ncqo->pre_c = SU_TRUE; - __su_ncqo_populate_precalc_buffer(ncqo); + self->pre_c = SU_TRUE; + __su_ncqo_populate_precalc_buffer(self); +#endif /* SU_NCQO_USE_PRECALC_BUFFER */ +} + +SU_METHOD(su_ncqo, void, copy, const su_ncqo_t *ncqo) +{ +#ifdef SU_NCQO_USE_PRECALC_BUFFER + if (self->pre_c) { + /* We need all the info here */ + memcpy(self, ncqo, sizeof(su_ncqo_t)); + } else { +#endif /* SU_NCQO_USE_PRECALC_BUFFER */ + /* Copy only the relevant fields */ + self->phi = ncqo->phi; + self->omega = ncqo->omega; + self->fnor = ncqo->fnor; + + self->sin_updated = ncqo->sin_updated; + self->sin = ncqo->sin; + + self->cos_updated = ncqo->cos_updated; + self->cos = ncqo->cos; +#ifdef SU_NCQO_USE_PRECALC_BUFFER + } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ } @@ -71,84 +93,79 @@ __su_ncqo_assert_sin(su_ncqo_t *ncqo) } } -void -su_ncqo_set_phase(su_ncqo_t *ncqo, SUFLOAT phi) +SU_METHOD(su_ncqo, void, set_phase, SUFLOAT phi) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { + if (self->pre_c) { SU_ERROR("Cannot set phase on a fixed NCQO\n"); return; } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - ncqo->phi = phi - 2 * PI * SU_FLOOR(phi / (2 * PI)); + self->phi = phi - 2 * PI * SU_FLOOR(phi / (2 * PI)); } -SUFLOAT -su_ncqo_get_i(su_ncqo_t *ncqo) +SU_METHOD(su_ncqo, SUFLOAT, get_i) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { - return ncqo->cos_buffer[ncqo->p]; + if (self->pre_c) { + return self->cos_buffer[self->p]; } else { #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - __su_ncqo_assert_cos(ncqo); - return ncqo->cos; + __su_ncqo_assert_cos(self); + return self->cos; #ifdef SU_NCQO_USE_PRECALC_BUFFER } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ } -SUFLOAT -su_ncqo_get_q(su_ncqo_t *ncqo) +SU_METHOD(su_ncqo, SUFLOAT, get_q) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { - return ncqo->sin_buffer[ncqo->p]; + if (self->pre_c) { + return self->sin_buffer[self->p]; } else { #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - __su_ncqo_assert_sin(ncqo); - return ncqo->sin; + __su_ncqo_assert_sin(self); + return self->sin; #ifdef SU_NCQO_USE_PRECALC_BUFFER } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ } -SUCOMPLEX -su_ncqo_get(su_ncqo_t *ncqo) +SU_METHOD(su_ncqo, SUCOMPLEX, get) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { - return ncqo->cos_buffer[ncqo->p] + I * ncqo->sin_buffer[ncqo->p]; + if (self->pre_c) { + return self->cos_buffer[self->p] + I * self->sin_buffer[self->p]; } else { #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - __su_ncqo_assert_cos(ncqo); - __su_ncqo_assert_sin(ncqo); + __su_ncqo_assert_cos(self); + __su_ncqo_assert_sin(self); - return ncqo->cos + ncqo->sin * I; + return self->cos + self->sin * I; #ifdef SU_NCQO_USE_PRECALC_BUFFER } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ } -SUFLOAT -su_ncqo_read_i(su_ncqo_t *ncqo) +SU_METHOD(su_ncqo, SUFLOAT, read_i) { SUFLOAT old; #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { - old = ncqo->cos_buffer[ncqo->p]; - __su_ncqo_step_precalc(ncqo); + if (self->pre_c) { + old = self->cos_buffer[self->p]; + __su_ncqo_step_precalc(self); } else { #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - old = ncqo->cos; + old = self->cos; - __su_ncqo_step(ncqo); + __su_ncqo_step(self); - ncqo->cos_updated = SU_TRUE; - ncqo->sin_updated = SU_FALSE; - ncqo->cos = SU_COS(ncqo->phi); + self->cos_updated = SU_TRUE; + self->sin_updated = SU_FALSE; + self->cos = SU_COS(self->phi); #ifdef SU_NCQO_USE_PRECALC_BUFFER } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ @@ -156,24 +173,23 @@ su_ncqo_read_i(su_ncqo_t *ncqo) return old; } -SUFLOAT -su_ncqo_read_q(su_ncqo_t *ncqo) +SU_METHOD(su_ncqo, SUFLOAT, read_q) { SUFLOAT old; #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { - old = ncqo->sin_buffer[ncqo->p]; - __su_ncqo_step_precalc(ncqo); + if (self->pre_c) { + old = self->sin_buffer[self->p]; + __su_ncqo_step_precalc(self); } else { #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - old = ncqo->sin; + old = self->sin; - __su_ncqo_step(ncqo); + __su_ncqo_step(self); - ncqo->cos_updated = SU_FALSE; - ncqo->sin_updated = SU_TRUE; - ncqo->sin = SU_SIN(ncqo->phi); + self->cos_updated = SU_FALSE; + self->sin_updated = SU_TRUE; + self->sin = SU_SIN(self->phi); #ifdef SU_NCQO_USE_PRECALC_BUFFER } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ @@ -181,26 +197,25 @@ su_ncqo_read_q(su_ncqo_t *ncqo) return old; } -SUCOMPLEX -su_ncqo_read(su_ncqo_t *ncqo) +SU_METHOD(su_ncqo, SUCOMPLEX, read) { SUCOMPLEX old; #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { - old = ncqo->cos_buffer[ncqo->p] + I * ncqo->sin_buffer[ncqo->p]; - __su_ncqo_step_precalc(ncqo); + if (self->pre_c) { + old = self->cos_buffer[self->p] + I * self->sin_buffer[self->p]; + __su_ncqo_step_precalc(self); } else { #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - old = ncqo->cos + I * ncqo->sin; + old = self->cos + I * self->sin; - __su_ncqo_step(ncqo); + __su_ncqo_step(self); - ncqo->cos_updated = SU_TRUE; - ncqo->sin_updated = SU_TRUE; + self->cos_updated = SU_TRUE; + self->sin_updated = SU_TRUE; - ncqo->cos = SU_COS(ncqo->phi); - ncqo->sin = SU_SIN(ncqo->phi); + self->cos = SU_COS(self->phi); + self->sin = SU_SIN(self->phi); #ifdef SU_NCQO_USE_PRECALC_BUFFER } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ @@ -208,71 +223,64 @@ su_ncqo_read(su_ncqo_t *ncqo) return old; } -void -su_ncqo_set_angfreq(su_ncqo_t *ncqo, SUFLOAT omrel) +SU_METHOD(su_ncqo, void, set_angfreq, SUFLOAT omrel) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { + if (self->pre_c) { SU_ERROR("Cannot change frequency on a fixed NCQO\n"); return; } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - ncqo->omega = omrel; - ncqo->fnor = SU_ANG2NORM_FREQ(omrel); + self->omega = omrel; + self->fnor = SU_ANG2NORM_FREQ(omrel); } -void -su_ncqo_inc_angfreq(su_ncqo_t *ncqo, SUFLOAT delta) +SU_METHOD(su_ncqo, void, inc_angfreq, SUFLOAT delta) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { + if (self->pre_c) { SU_ERROR("Cannot increase frequency on a fixed NCQO\n"); return; } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - ncqo->omega += delta; - ncqo->fnor = SU_ANG2NORM_FREQ(ncqo->omega); + self->omega += delta; + self->fnor = SU_ANG2NORM_FREQ(self->omega); } -SUFLOAT -su_ncqo_get_angfreq(const su_ncqo_t *ncqo) +SU_GETTER(su_ncqo, SUFLOAT, get_angfreq) { - return ncqo->omega; + return self->omega; } -void -su_ncqo_set_freq(su_ncqo_t *ncqo, SUFLOAT fnor) +SU_METHOD(su_ncqo, void, set_freq, SUFLOAT fnor) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { + if (self->pre_c) { SU_ERROR("Cannot change frequency on a fixed NCQO\n"); return; } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - ncqo->fnor = fnor; - ncqo->omega = SU_NORM2ANG_FREQ(fnor); + self->fnor = fnor; + self->omega = SU_NORM2ANG_FREQ(fnor); } -void -su_ncqo_inc_freq(su_ncqo_t *ncqo, SUFLOAT delta) +SU_METHOD(su_ncqo, void, inc_freq, SUFLOAT delta) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { + if (self->pre_c) { SU_ERROR("Cannot increase frequency on a fixed NCQO\n"); return; } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - ncqo->fnor += delta; - ncqo->omega = SU_NORM2ANG_FREQ(ncqo->fnor); + self->fnor += delta; + self->omega = SU_NORM2ANG_FREQ(self->fnor); } -SUFLOAT -su_ncqo_get_freq(const su_ncqo_t *ncqo) +SU_GETTER(su_ncqo, SUFLOAT, get_freq) { - return ncqo->fnor; + return self->fnor; } - diff --git a/sigutils/ncqo.h b/sigutils/ncqo.h index a246918..ca2cc72 100644 --- a/sigutils/ncqo.h +++ b/sigutils/ncqo.h @@ -20,18 +20,19 @@ #ifndef _SIGUTILS_NCQO_H #define _SIGUTILS_NCQO_H -#include "types.h" +#include "defs.h" +#include "log.h" #include "sampling.h" +#include "types.h" #ifdef __cplusplus # ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wreturn-type-c-linkage" -# endif // __clang__ +# endif // __clang__ extern "C" { #endif /* __cplusplus */ - #define SU_NCQO_USE_PRECALC_BUFFER #ifdef SU_NCQO_USE_PRECALC_BUFFER # define SU_NCQO_PRECALC_BUFFER_LEN 1024 @@ -43,24 +44,34 @@ struct sigutils_ncqo { SUFLOAT phi_buffer[SU_NCQO_PRECALC_BUFFER_LEN]; SUFLOAT sin_buffer[SU_NCQO_PRECALC_BUFFER_LEN]; SUFLOAT cos_buffer[SU_NCQO_PRECALC_BUFFER_LEN]; - SUBOOL pre_c; + SUBOOL pre_c; unsigned int p; /* Pointer in precalc buffer */ -#endif /* SU_NCQO_USE_PRECALC_BUFFER */ +#endif /* SU_NCQO_USE_PRECALC_BUFFER */ SUFLOAT phi; SUFLOAT omega; /* Normalized angular frequency */ SUFLOAT fnor; /* Normalized frequency in hcps */ - SUBOOL sin_updated; + SUBOOL sin_updated; SUFLOAT sin; - SUBOOL cos_updated; + SUBOOL cos_updated; SUFLOAT cos; }; typedef struct sigutils_ncqo su_ncqo_t; -#define su_ncqo_INITIALIZER {0, 0, 0, 0, 0} +#ifdef SU_NCQO_USE_PRECALC_BUFFER +# define su_ncqo_INITIALIZER \ + { \ + {0.}, {0.}, {0.}, SU_FALSE, 0, 0., 0., 0., SU_FALSE, 0., SU_FALSE, 0. \ + } +#else +# define su_ncqo_INITIALIZER \ + { \ + 0., 0., 0., SU_FALSE, 0., SU_FALSE, 0. \ + } +#endif /* SU_NCQO_USE_PRECALC_BUFFER */ /* Methods */ SUINLINE SUFLOAT @@ -75,7 +86,7 @@ su_phase_adjust_one_cycle(SUFLOAT phi) if (phi > PI) return phi - 2 * PI; - if (phi < - PI) + if (phi < -PI) return phi + 2 * PI; return phi; @@ -96,7 +107,7 @@ __su_ncqo_step(su_ncqo_t *ncqo) #if defined(_SU_SINGLE_PRECISION) && HAVE_VOLK # define SU_USE_VOLK # define SU_VOLK_CALL_STRIDE_BITS 5 -# define SU_VOLK_CALL_STRIDE (1 << SU_VOLK_CALL_STRIDE_BITS) +# define SU_VOLK_CALL_STRIDE (1 << SU_VOLK_CALL_STRIDE_BITS) # define SU_VOLK_CALL_STRIDE_MASK (SU_VOLK_CALL_STRIDE - 1) # ifdef __cplusplus } @@ -112,16 +123,16 @@ SUINLINE void __su_ncqo_populate_precalc_buffer(su_ncqo_t *ncqo) { unsigned int i; -#ifdef SU_USE_VOLK +# ifdef SU_USE_VOLK unsigned int p; -#endif /* SU_USE_VOLK */ +# endif /* SU_USE_VOLK */ /* Precalculate phase buffer */ for (i = 0; i < SU_NCQO_PRECALC_BUFFER_LEN; ++i) { ncqo->phi_buffer[i] = ncqo->phi; # ifndef SU_USE_VOLK # ifdef HAVE_SINCOS SU_SINCOS(ncqo->phi, ncqo->sin_buffer + i, ncqo->cos_buffer + i); -# else /* HAVE_SINCOS */ +# else /* HAVE_SINCOS */ ncqo->sin_buffer[i] = SU_SIN(ncqo->phi); ncqo->cos_buffer[i] = SU_COS(ncqo->phi); # endif /* HAVE_SINCOS */ @@ -155,52 +166,54 @@ __su_ncqo_step_precalc(su_ncqo_t *ncqo) /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ VOLK HACKS ABOVE ^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /* NCQO constructor */ -void su_ncqo_init(su_ncqo_t *ncqo, SUFLOAT frel); +SU_CONSTRUCTOR_TYPED(void, su_ncqo, SUFLOAT frel); /* NCQO constructor for fixed frequency */ -void su_ncqo_init_fixed(su_ncqo_t *ncqo, SUFLOAT fnor); +SU_METHOD(su_ncqo, void, init_fixed, SUFLOAT fnor); + +/* Init ncqo from existing ncqo */ +SU_METHOD(su_ncqo, void, copy, const su_ncqo_t *ncqo); /* Compute next step */ -SUINLINE void -su_ncqo_step(su_ncqo_t *ncqo) +SUINLINE +SU_METHOD(su_ncqo, void, step) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { - __su_ncqo_step_precalc(ncqo); + if (self->pre_c) { + __su_ncqo_step_precalc(self); } else { #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - __su_ncqo_step(ncqo); + __su_ncqo_step(self); /* Sine & cosine values are now outdated */ - ncqo->cos_updated = SU_FALSE; - ncqo->sin_updated = SU_FALSE; + self->cos_updated = SU_FALSE; + self->sin_updated = SU_FALSE; #ifdef SU_NCQO_USE_PRECALC_BUFFER } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ } - /* Force phase */ -void su_ncqo_set_phase(su_ncqo_t *ncqo, SUFLOAT phi); +SU_METHOD(su_ncqo, void, set_phase, SUFLOAT phi); /* Get current phase */ -SUINLINE SUFLOAT -su_ncqo_get_phase(su_ncqo_t *ncqo) +SUINLINE +SU_GETTER(su_ncqo, SUFLOAT, get_phase) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) - return ncqo->phi_buffer[ncqo->p]; + if (self->pre_c) + return self->phi_buffer[self->p]; #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - return ncqo->phi; + return self->phi; } /* Increment current phase */ -SUINLINE void -su_ncqo_inc_phase(su_ncqo_t *ncqo, SUFLOAT delta) +SUINLINE +SU_METHOD(su_ncqo, void, inc_phase, SUFLOAT delta) { #ifdef SU_NCQO_USE_PRECALC_BUFFER - if (ncqo->pre_c) { + if (self->pre_c) { # ifdef SU_LOG_DOMAIN SU_ERROR("Cannot increase phase on a fixed NCQO\n"); # endif /* SU_LOG_DOMAIN */ @@ -208,52 +221,52 @@ su_ncqo_inc_phase(su_ncqo_t *ncqo, SUFLOAT delta) } #endif /* SU_NCQO_USE_PRECALC_BUFFER */ - ncqo->phi += delta; + self->phi += delta; - if (ncqo->phi < 0 || ncqo->phi >= 2 * PI) { - ncqo->phi -= 2 * PI * SU_FLOOR(ncqo->phi / (2 * PI)); + if (self->phi < 0 || self->phi >= 2 * PI) { + self->phi -= 2 * PI * SU_FLOOR(self->phi / (2 * PI)); } } /* Get in-phase component */ -SUFLOAT su_ncqo_get_i(su_ncqo_t *ncqo); +SU_METHOD(su_ncqo, SUFLOAT, get_i); /* Get cuadrature component */ -SUFLOAT su_ncqo_get_q(su_ncqo_t *ncqo); +SU_METHOD(su_ncqo, SUFLOAT, get_q); /* Get both components as complex */ -SUCOMPLEX su_ncqo_get(su_ncqo_t *ncqo); +SU_METHOD(su_ncqo, SUCOMPLEX, get); /* Read (compute next + get) in-phase component */ -SUFLOAT su_ncqo_read_i(su_ncqo_t *ncqo); +SU_METHOD(su_ncqo, SUFLOAT, read_i); /* Read (compute next + get) cuadrature component */ -SUFLOAT su_ncqo_read_q(su_ncqo_t *ncqo); +SU_METHOD(su_ncqo, SUFLOAT, read_q); /* Read (compute next + get) both components as complex */ -SUCOMPLEX su_ncqo_read(su_ncqo_t *ncqo); +SU_METHOD(su_ncqo, SUCOMPLEX, read); /* Set oscillator frequency (normalized angular freq) */ -void su_ncqo_set_angfreq(su_ncqo_t *ncqo, SUFLOAT omrel); +SU_METHOD(su_ncqo, void, set_angfreq, SUFLOAT omrel); /* Increase or decrease current frequency (normalized angular freq) */ -void su_ncqo_inc_angfreq(su_ncqo_t *ncqo, SUFLOAT delta); +SU_METHOD(su_ncqo, void, inc_angfreq, SUFLOAT delta); /* Get current frequency (normalized angular freq) */ -SUFLOAT su_ncqo_get_angfreq(const su_ncqo_t *ncqo); +SU_GETTER(su_ncqo, SUFLOAT, get_angfreq); /* Set oscillator frequency (normalized freq) */ -void su_ncqo_set_freq(su_ncqo_t *ncqo, SUFLOAT frel); +SU_METHOD(su_ncqo, void, set_freq, SUFLOAT frel); /* Increase or decrease current frequency (normalized freq) */ -void su_ncqo_inc_freq(su_ncqo_t *ncqo, SUFLOAT delta); +SU_METHOD(su_ncqo, void, inc_freq, SUFLOAT delta); /* Get current frequency (normalized freq) */ -SUFLOAT su_ncqo_get_freq(const su_ncqo_t *ncqo); +SU_GETTER(su_ncqo, SUFLOAT, get_freq); #ifdef __cplusplus # ifdef __clang__ # pragma clang diagnostic pop -# endif // __clang__ +# endif // __clang__ } #endif /* __cplusplus */ diff --git a/sigutils/pll.c b/sigutils/pll.c index aa38740..3f47776 100644 --- a/sigutils/pll.c +++ b/sigutils/pll.c @@ -17,97 +17,81 @@ */ +#include "pll.h" + #include -#include "sampling.h" + +#include "coef.h" #include "log.h" -#include "types.h" -#include "pll.h" +#include "sampling.h" #include "taps.h" -#include "coef.h" +#include "types.h" -void -su_pll_finalize(su_pll_t *pll) +SU_DESTRUCTOR(su_pll) { - } -SUBOOL -su_pll_init(su_pll_t *pll, SUFLOAT fhint, SUFLOAT fc) +SU_CONSTRUCTOR(su_pll, SUFLOAT fhint, SUFLOAT fc) { SUFLOAT dinv; - memset(pll, 0, sizeof(su_pll_t)); + memset(self, 0, sizeof(su_pll_t)); fc = SU_NORM2ANG_FREQ(fc); /* Settings taken from GNU Radio */ dinv = 1.f / (1.f + 2.f * .707f * fc + fc * fc); - pll->alpha = 4 * fc * fc * dinv; - pll->beta = 4 * 0.707 * fc * dinv; + self->alpha = 4 * fc * fc * dinv; + self->beta = 4 * 0.707 * fc * dinv; - su_ncqo_init(&pll->ncqo, fhint); + su_ncqo_init(&self->ncqo, fhint); return SU_TRUE; - -fail: - su_pll_finalize(pll); - - return SU_FALSE; } -SUCOMPLEX -su_pll_track(su_pll_t *pll, SUCOMPLEX x) +SU_METHOD(su_pll, SUCOMPLEX, track, SUCOMPLEX x) { - SUCOMPLEX ref = su_ncqo_read(&pll->ncqo); + SUCOMPLEX ref = su_ncqo_read(&self->ncqo); SUCOMPLEX mix = x * SU_C_CONJ(ref); - SUFLOAT phase = su_ncqo_get_phase(&pll->ncqo); - SUFLOAT error = su_phase_adjust_one_cycle(SU_C_ARG(x) - phase); + SUFLOAT phase = su_ncqo_get_phase(&self->ncqo); + SUFLOAT error = su_phase_adjust_one_cycle(SU_C_ARG(x) - phase); - su_ncqo_inc_angfreq(&pll->ncqo, pll->alpha * error); - su_ncqo_inc_phase (&pll->ncqo, pll->beta * error); + su_ncqo_inc_angfreq(&self->ncqo, self->alpha * error); + su_ncqo_inc_phase(&self->ncqo, self->beta * error); return mix; } -void -su_pll_feed(su_pll_t *pll, SUFLOAT x) +SU_METHOD(su_pll, void, feed, SUFLOAT x) { SUCOMPLEX s; SUFLOAT lck = 0; SUFLOAT err = 0; - s = su_ncqo_read(&pll->ncqo); + s = su_ncqo_read(&self->ncqo); err = -x * SU_C_IMAG(s); /* Error signal: projection against Q */ - lck = x * SU_C_REAL(s); /* Lock: projection against I */ + lck = x * SU_C_REAL(s); /* Lock: projection against I */ - pll->lock += pll->beta * (2 * lck - pll->lock); + self->lock += self->beta * (2 * lck - self->lock); - if (pll->ncqo.omega > -pll->alpha * err) { - su_ncqo_inc_angfreq(&pll->ncqo, pll->alpha * err); + if (self->ncqo.omega > -self->alpha * err) { + su_ncqo_inc_angfreq(&self->ncqo, self->alpha * err); } - su_ncqo_inc_phase(&pll->ncqo, pll->beta * err); + su_ncqo_inc_phase(&self->ncqo, self->beta * err); } /**************** QPSK Costas Filter implementation **************************/ -void -su_costas_finalize(su_costas_t *costas) -{ - su_iir_filt_finalize(&costas->af); -} - -void -su_costas_set_loop_gain(su_costas_t *costas, SUFLOAT gain) +SU_DESTRUCTOR(su_costas) { - costas->gain = gain; + SU_DESTRUCT(su_iir_filt, &self->af); } -SUBOOL -su_costas_init( - su_costas_t *costas, +SU_CONSTRUCTOR( + su_costas, enum sigutils_costas_kind kind, SUFLOAT fhint, SUFLOAT arm_bw, @@ -119,24 +103,23 @@ su_costas_init( SUFLOAT scaling; unsigned int i = 0; - memset(costas, 0, sizeof(su_costas_t)); + memset(self, 0, sizeof(su_costas_t)); /* Make LPF filter critically damped (Eric Hagemann) */ - costas->a = SU_NORM2ANG_FREQ(loop_bw); - costas->b = .5 * costas->a * costas->a; - costas->y_alpha = 1; - costas->kind = kind; - costas->gain = 1; + self->a = SU_NORM2ANG_FREQ(loop_bw); + self->b = .5 * self->a * self->a; + self->y_alpha = 1; + self->kind = kind; + self->gain = 1; - su_ncqo_init(&costas->ncqo, fhint); + su_ncqo_init(&self->ncqo, fhint); /* Initialize arm filters */ if (arm_order == 0) arm_order = 1; if (arm_order == 1 || arm_order >= SU_COSTAS_FIR_ORDER_THRESHOLD) { - if ((b = malloc(sizeof (SUFLOAT) * arm_order)) == NULL) - goto fail; + SU_ALLOCATE_MANY_FAIL(b, arm_order, SUFLOAT); if (arm_order == 1) b[0] = 1; /* No filtering */ @@ -144,11 +127,8 @@ su_costas_init( su_taps_brickwall_lp_init(b, arm_bw, arm_order); } else { /* If arm filter order is small, try to build a IIR filter */ - if ((a = su_dcof_bwlp(arm_order - 1, arm_bw)) == NULL) - goto fail; - - if ((b = su_ccof_bwlp(arm_order - 1)) == NULL) - goto fail; + SU_TRY_FAIL(a = su_dcof_bwlp(arm_order - 1, arm_bw)); + SU_TRY_FAIL(b = su_ccof_bwlp(arm_order - 1)); scaling = su_sf_bwlp(arm_order - 1, arm_bw); @@ -156,14 +136,13 @@ su_costas_init( b[i] *= scaling; } - if (!__su_iir_filt_init( - &costas->af, + SU_TRY_FAIL(__su_iir_filt_init( + &self->af, a == NULL ? 0 : arm_order, a, arm_order, b, - SU_FALSE)) - goto fail; + SU_FALSE)); b = NULL; a = NULL; @@ -171,7 +150,7 @@ su_costas_init( return SU_TRUE; fail: - su_costas_finalize(costas); + SU_DESTRUCT(su_costas, self); if (b != NULL) free(b); @@ -182,40 +161,43 @@ su_costas_init( return SU_FALSE; } -SUCOMPLEX -su_costas_feed(su_costas_t *costas, SUCOMPLEX x) +SU_METHOD(su_costas, void, set_loop_gain, SUFLOAT gain) +{ + self->gain = gain; +} + +SU_METHOD(su_costas, SUCOMPLEX, feed, SUCOMPLEX x) { SUCOMPLEX s; SUCOMPLEX L; SUFLOAT e = 0; - s = su_ncqo_read(&costas->ncqo); + s = su_ncqo_read(&self->ncqo); /* * s = cos(wt) + sin(wt). Signal sQ be 90 deg delayed wrt sI, therefore * we must multiply by conj(s). */ - costas->z = costas->gain * su_iir_filt_feed(&costas->af, SU_C_CONJ(s) * x); + self->z = self->gain * su_iir_filt_feed(&self->af, SU_C_CONJ(s) * x); - switch (costas->kind) { + switch (self->kind) { case SU_COSTAS_KIND_NONE: SU_ERROR("Invalid Costas loop\n"); return 0; case SU_COSTAS_KIND_BPSK: /* Taken directly from Wikipedia */ - e = -SU_C_REAL(costas->z) * SU_C_IMAG(costas->z); + e = -SU_C_REAL(self->z) * SU_C_IMAG(self->z); break; case SU_COSTAS_KIND_QPSK: /* Compute limiter output */ - L = SU_C_SGN(costas->z); + L = SU_C_SGN(self->z); /* * Error signal taken from Maarten Tytgat's paper "Time Domain Model * for Costas Loop Based QPSK Receiver. */ - e = SU_C_REAL(L) * SU_C_IMAG(costas->z) - -SU_C_IMAG(L) * SU_C_REAL(costas->z); + e = SU_C_REAL(L) * SU_C_IMAG(self->z) - SU_C_IMAG(L) * SU_C_REAL(self->z); break; case SU_COSTAS_KIND_8PSK: @@ -240,14 +222,14 @@ su_costas_feed(su_costas_t *costas, SUCOMPLEX x) * -----------8<-------------------------------------------------- */ - L = SU_C_SGN(costas->z); + L = SU_C_SGN(self->z); - if (SU_ABS(SU_C_REAL(costas->z)) >= SU_ABS(SU_C_IMAG(costas->z))) - e = SU_C_REAL(L) * SU_C_IMAG(costas->z) - -SU_C_IMAG(L) * SU_C_REAL(costas->z) * (SU_SQRT2 - 1); + if (SU_ABS(SU_C_REAL(self->z)) >= SU_ABS(SU_C_IMAG(self->z))) + e = SU_C_REAL(L) * SU_C_IMAG(self->z) + - SU_C_IMAG(L) * SU_C_REAL(self->z) * (SU_SQRT2 - 1); else - e = SU_C_REAL(L) * SU_C_IMAG(costas->z) * (SU_SQRT2 - 1) - -SU_C_IMAG(L) * SU_C_REAL(costas->z); + e = SU_C_REAL(L) * SU_C_IMAG(self->z) * (SU_SQRT2 - 1) + - SU_C_IMAG(L) * SU_C_REAL(self->z); break; default: @@ -255,19 +237,17 @@ su_costas_feed(su_costas_t *costas, SUCOMPLEX x) return 0; } - costas->lock += costas->a * (1 - e - costas->lock); - costas->y += costas->y_alpha * (costas->z - costas->y); + self->lock += self->a * (1 - e - self->lock); + self->y += self->y_alpha * (self->z - self->y); /* IIR loop filter suggested by Eric Hagemann */ - su_ncqo_inc_angfreq(&costas->ncqo, costas->b * e); - su_ncqo_inc_phase(&costas->ncqo, costas->a * e); + su_ncqo_inc_angfreq(&self->ncqo, self->b * e); + su_ncqo_inc_phase(&self->ncqo, self->a * e); - return costas->y; + return self->y; } - -void -su_costas_set_kind(su_costas_t *costas, enum sigutils_costas_kind kind) +SU_METHOD(su_costas, void, set_kind, enum sigutils_costas_kind kind) { - costas->kind = kind; + self->kind = kind; } diff --git a/sigutils/pll.h b/sigutils/pll.h index e7c46d3..8fdc899 100644 --- a/sigutils/pll.h +++ b/sigutils/pll.h @@ -20,24 +20,36 @@ #ifndef _SIGUTILS_PLL_H #define _SIGUTILS_PLL_H -#include "types.h" +#include "defs.h" #include "iir.h" #include "ncqo.h" +#include "types.h" + +#ifdef __cplusplus +# ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +# endif // __clang__ +extern "C" { +#endif /* __cplusplus */ #define SU_PLL_ORDER_DEFAULT 5 #define SU_COSTAS_FIR_ORDER_THRESHOLD 20 struct sigutils_pll { - SUFLOAT alpha; - SUFLOAT beta; - SUFLOAT lock; + SUFLOAT alpha; + SUFLOAT beta; + SUFLOAT lock; SUCOMPLEX a; su_ncqo_t ncqo; }; typedef struct sigutils_pll su_pll_t; -#define su_pll_INITIALIZER {0., 0., 0., 0, su_ncqo_INITIALIZER} +#define su_pll_INITIALIZER \ + { \ + 0., 0., 0., 0, su_ncqo_INITIALIZER \ + } enum sigutils_costas_kind { SU_COSTAS_KIND_NONE, @@ -51,51 +63,48 @@ struct sigutils_costas { SUFLOAT a; SUFLOAT b; SUFLOAT lock; - su_iir_filt_t af; /* Arm filter */ - SUCOMPLEX z; /* Arm filter output */ - SUCOMPLEX y; /* Demodulation result */ + su_iir_filt_t af; /* Arm filter */ + SUCOMPLEX z; /* Arm filter output */ + SUCOMPLEX y; /* Demodulation result */ SUCOMPLEX y_alpha; /* Result alpha */ - SUFLOAT gain; /* Loop gain */ + SUFLOAT gain; /* Loop gain */ su_ncqo_t ncqo; }; typedef struct sigutils_costas su_costas_t; -#define su_costas_INITIALIZER \ -{ \ - SU_COSTAS_KIND_NONE, \ - 0., \ - 0., \ - 0., \ - su_iir_filt_INITIALIZER, \ - 0., \ - 0., \ - 0., \ - 1., \ - su_ncqo_INITIALIZER \ -} +#define su_costas_INITIALIZER \ + { \ + SU_COSTAS_KIND_NONE, 0., 0., 0., su_iir_filt_INITIALIZER, 0., 0., 0., 1., \ + su_ncqo_INITIALIZER \ + } /* Second order PLL */ -void su_pll_finalize(su_pll_t *); -SUBOOL su_pll_init(su_pll_t *, SUFLOAT, SUFLOAT); -SUCOMPLEX su_pll_track(su_pll_t *, SUCOMPLEX); -void su_pll_feed(su_pll_t *, SUFLOAT); +SU_CONSTRUCTOR(su_pll, SUFLOAT fhint, SUFLOAT fc); +SU_DESTRUCTOR(su_pll); -/* QPSK costas loops are way more complex than that */ -void su_costas_finalize(su_costas_t *); +SU_METHOD(su_pll, SUCOMPLEX, track, SUCOMPLEX x); +SU_METHOD(su_pll, void, feed, SUFLOAT x); -SUBOOL su_costas_init( - su_costas_t *costas, +/* QPSK costas loops are way more complex than that */ +SU_CONSTRUCTOR( + su_costas, enum sigutils_costas_kind kind, SUFLOAT fhint, SUFLOAT arm_bw, unsigned int arm_order, SUFLOAT loop_bw); +SU_DESTRUCTOR(su_costas); -void su_costas_set_kind(su_costas_t *costas, enum sigutils_costas_kind); +SU_METHOD(su_costas, void, set_kind, enum sigutils_costas_kind kind); +SU_METHOD(su_costas, void, set_loop_gain, SUFLOAT gain); +SU_METHOD(su_costas, SUCOMPLEX, feed, SUCOMPLEX x); -void su_costas_set_loop_gain(su_costas_t *costas, SUFLOAT gain); - -SUCOMPLEX su_costas_feed(su_costas_t *costas, SUCOMPLEX x); +#ifdef __cplusplus +# ifdef __clang__ +# pragma clang diagnostic pop +# endif // __clang__ +} +#endif /* __cplusplus */ #endif /* _SIGUTILS_PLL_H */ diff --git a/sigutils/property.c b/sigutils/property.c index 60f4eef..91cc92e 100644 --- a/sigutils/property.c +++ b/sigutils/property.c @@ -17,9 +17,9 @@ */ -#include -#include #include +#include +#include #define SU_LOG_LEVEL "property" #include "log.h" @@ -32,7 +32,7 @@ su_property_new(const char *name, su_property_type_t type, SUBOOL m, void *p) su_property_t *new = NULL; char *namedup = NULL; - if ((new = malloc(sizeof (su_property_t))) == NULL) + if ((new = malloc(sizeof(su_property_t))) == NULL) goto fail; if ((namedup = strdup(name)) == NULL) @@ -68,7 +68,7 @@ su_property_destroy(su_property_t *prop) void su_property_set_init(su_property_set_t *set) { - memset(set, 0, sizeof (su_property_set_t)); + memset(set, 0, sizeof(su_property_set_t)); } su_property_t * @@ -77,8 +77,8 @@ su_property_set_lookup(const su_property_set_t *set, const char *name) su_property_t *this = NULL; FOR_EACH_PTR(this, set, property) - if (strcmp(this->name, name) == 0) - return this; + if (strcmp(this->name, name) == 0) + return this; return NULL; } @@ -86,7 +86,7 @@ su_property_set_lookup(const su_property_set_t *set, const char *name) const char * su_property_type_to_string(su_property_type_t type) { - switch(type) { + switch (type) { case SU_PROPERTY_TYPE_ANY: return "(any)"; @@ -170,7 +170,7 @@ su_property_set_finalize(su_property_set_t *set) su_property_t *this = NULL; FOR_EACH_PTR(this, set, property) - su_property_destroy(this); + su_property_destroy(this); if (set->property_list != NULL) free(set->property_list); diff --git a/sigutils/property.h b/sigutils/property.h index 2992b08..92d027c 100644 --- a/sigutils/property.h +++ b/sigutils/property.h @@ -72,7 +72,9 @@ su_property_t *su_property_new( /* Property set API */ void su_property_set_init(su_property_set_t *set); -su_property_t *su_property_set_lookup(const su_property_set_t *set, const char *name); +su_property_t *su_property_set_lookup( + const su_property_set_t *set, + const char *name); su_property_t *su_property_set_assert_property( su_property_set_t *set, const char *name, diff --git a/sigutils/sampling.h b/sigutils/sampling.h index 5062a62..34db06f 100644 --- a/sigutils/sampling.h +++ b/sigutils/sampling.h @@ -27,9 +27,9 @@ * --------------------------------------------- * SAMPLING FREQUENCY (fs): How many samples are taken per second, in Hz. * - * NORMALIZED FREQUENCY (fnor): Represents the frequency of a discretized signal, - * ranging from 0 (constant signal) to 1 (a signal that flips sign on each - * time step). Units: hcps ("half cycles per sample") + * NORMALIZED FREQUENCY (fnor): Represents the frequency of a discretized + * signal, ranging from 0 (constant signal) to 1 (a signal that flips sign on + * each time step). Units: hcps ("half cycles per sample") * * ABSOLUTE FREQUENCY (freq): Represents the actual frequency of the signal, * in Hz. It is defined as: @@ -45,8 +45,8 @@ * time step. */ -#define SU_ABS2NORM_FREQ(fs, freq) (2 * (SUFLOAT) (freq) / (SUFLOAT) (fs)) -#define SU_NORM2ABS_FREQ(fs, fnor) ((SUFLOAT) (fs) * (SUFLOAT) (fnor) / 2.) +#define SU_ABS2NORM_FREQ(fs, freq) (2 * (SUFLOAT)(freq) / (SUFLOAT)(fs)) +#define SU_NORM2ABS_FREQ(fs, fnor) ((SUFLOAT)(fs) * (SUFLOAT)(fnor) / 2.) /* * Normalized and absolute baud rates are transformed using a different @@ -57,19 +57,19 @@ * sample. */ -#define SU_ABS2NORM_BAUD(fs, freq) ((SUFLOAT) (freq) / (SUFLOAT) (fs)) -#define SU_NORM2ABS_BAUD(fs, fnor) ((SUFLOAT) (fs) * (SUFLOAT) (fnor)) +#define SU_ABS2NORM_BAUD(fs, freq) ((SUFLOAT)(freq) / (SUFLOAT)(fs)) +#define SU_NORM2ABS_BAUD(fs, fnor) ((SUFLOAT)(fs) * (SUFLOAT)(fnor)) #define SU_NORM2ANG_FREQ(freq) (PI * (freq)) #define SU_ANG2NORM_FREQ(omrel) ((omrel) / (PI)) -#define SU_T2N(fs, t) ((unsigned int) SU_FLOOR((t) * (SUFLOAT) (fs))) -#define SU_N2T(fs, n) ((unsigned int) SU_FLOOR((n) / (SUFLOAT) (fs))) +#define SU_T2N(fs, t) ((unsigned int)SU_FLOOR((t) * (SUFLOAT)(fs))) +#define SU_N2T(fs, n) ((unsigned int)SU_FLOOR((n) / (SUFLOAT)(fs))) -#define SU_T2N_COUNT(fs, t) ((unsigned int) SU_CEIL((t) * (SUFLOAT) (fs))) -#define SU_N2T_COUNT(fs, n) ((unsigned int) SU_CEIL((n) / (SUFLOAT) (fs))) +#define SU_T2N_COUNT(fs, t) ((unsigned int)SU_CEIL((t) * (SUFLOAT)(fs))) +#define SU_N2T_COUNT(fs, n) ((unsigned int)SU_CEIL((n) / (SUFLOAT)(fs))) -#define SU_T2N_FLOAT(fs, t) ((t) * (SUFLOAT) (fs)) -#define SU_N2T_FLOAT(fs, n) ((n) / (SUFLOAT) (fs)) +#define SU_T2N_FLOAT(fs, t) ((t) * (SUFLOAT)(fs)) +#define SU_N2T_FLOAT(fs, n) ((n) / (SUFLOAT)(fs)) #endif /* _SIGUTILS_SAMPLING_H */ diff --git a/sigutils/sigutils.h b/sigutils/sigutils.h index a1cf4a5..40544c7 100644 --- a/sigutils/sigutils.h +++ b/sigutils/sigutils.h @@ -20,11 +20,9 @@ #ifndef _SIGUTILS_SIGUTILS_H #define _SIGUTILS_SIGUTILS_H -#include "types.h" -#include "log.h" #include "block.h" -#include "codec.h" -#include "modem.h" +#include "log.h" +#include "types.h" #include "version.h" SUBOOL su_lib_init_ex(const struct sigutils_log_config *logconfig); diff --git a/sigutils/smoothpsd.c b/sigutils/smoothpsd.c index e089aff..445ee6a 100644 --- a/sigutils/smoothpsd.c +++ b/sigutils/smoothpsd.c @@ -19,49 +19,51 @@ #define SU_LOG_DOMAIN "smoothpsd" -#include - #include #include #include +#include -#define _SWAP(a, b) \ - tmp = a; \ - a = b; \ +#define _SWAP(a, b) \ + tmp = a; \ + a = b; \ b = tmp; -su_smoothpsd_t * -su_smoothpsd_new( +SU_INSTANCER( + su_smoothpsd, const struct sigutils_smoothpsd_params *params, - SUBOOL (*psd_func) (void *userdata, const SUFLOAT *psd, unsigned int size), + SUBOOL (*psd_func)(void *userdata, const SUFLOAT *psd, unsigned int size), void *userdata) { su_smoothpsd_t *new = NULL; - SU_TRYCATCH(new = calloc(1, sizeof(su_smoothpsd_t)), goto fail); + SU_ALLOCATE_FAIL(new, su_smoothpsd_t); + + SU_TRYZ_FAIL(pthread_mutex_init(&new->mutex, NULL)); - SU_TRYCATCH(pthread_mutex_init(&new->mutex, NULL) == 0, goto fail); new->mutex_init = SU_TRUE; new->psd_func = psd_func; new->userdata = userdata; - SU_TRYCATCH(su_smoothpsd_set_params(new, params), goto fail); + new->nominal_rate = params->samp_rate; + + SU_TRY_FAIL(su_smoothpsd_set_params(new, params)); return new; fail: if (new != NULL) - su_smoothpsd_destroy(new); + SU_DISPOSE(su_smoothpsd, new); return NULL; } -SUPRIVATE SUBOOL -su_smoothpsd_exec_fft(su_smoothpsd_t *self) +SUPRIVATE +SU_METHOD(su_smoothpsd, SUBOOL, exec_fft) { unsigned int i; - SUFLOAT wsizeinv = 1. / self->params.fft_size; + SUFLOAT wsizeinv = 1. / (self->params.fft_size * self->nominal_rate); /* Execute FFT */ SU_FFTW(_execute(self->fft_plan)); @@ -72,28 +74,24 @@ su_smoothpsd_exec_fft(su_smoothpsd_t *self) wsizeinv * SU_C_REAL(self->fft[i] * SU_C_CONJ(self->fft[i])); SU_TRYCATCH( - (self->psd_func)( - self->userdata, - self->realfft, - self->params.fft_size), + (self->psd_func)(self->userdata, self->realfft, self->params.fft_size), return SU_FALSE); ++self->iters; return SU_TRUE; } -SUBOOL -su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) + +SU_METHOD(su_smoothpsd, SUBOOL, feed, const SUCOMPLEX *data, SUSCOUNT size) { unsigned int chunk; unsigned int i; unsigned int p; - SUFLOAT wsizeinv; SUBOOL mutex_acquired = SU_FALSE; SUBOOL ok = SU_FALSE; - SUBOOL exec_fft = SU_FALSE; - SU_TRYCATCH(pthread_mutex_lock(&self->mutex) == 0, goto done); + SU_TRYZ(pthread_mutex_lock(&self->mutex)); + mutex_acquired = SU_TRUE; if (self->max_p > 0) { @@ -111,8 +109,8 @@ su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) chunk = SU_MIN(size, self->max_p - self->fft_p); } - size -= chunk; - data += chunk; + size -= chunk; + data += chunk; self->fft_p += chunk; /* Time to trigger FFT! */ @@ -124,7 +122,7 @@ su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) for (i = 0; i < self->params.fft_size; ++i) self->fft[i] *= self->window_func[i]; - SU_TRYCATCH(su_smoothpsd_exec_fft(self), goto done); + SU_TRY(su_smoothpsd_exec_fft(self)); } } @@ -132,9 +130,8 @@ su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) /* Overlapped mode. This is a bit trickier. */ while (size > 0) { /* We can copy this much */ - chunk = SU_MIN( - self->max_p - self->fft_p, - self->params.fft_size - self->p); + chunk = + SU_MIN(self->max_p - self->fft_p, self->params.fft_size - self->p); /* But maybe we were not fed those many samples */ if (size < chunk) @@ -149,7 +146,7 @@ su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) size -= chunk; data += chunk; - self->p += chunk; + self->p += chunk; self->fft_p += chunk; if (self->p >= self->params.fft_size) @@ -157,7 +154,6 @@ su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) /* Time to trigger FFT! */ if (self->fft_p >= self->max_p) { - wsizeinv = 1. / self->params.fft_size; self->fft_p = 0; p = self->p; @@ -168,7 +164,7 @@ su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) p = 0; } - SU_TRYCATCH(su_smoothpsd_exec_fft(self), goto done); + SU_TRY(su_smoothpsd_exec_fft(self)); } } } @@ -178,14 +174,15 @@ su_smoothpsd_feed(su_smoothpsd_t *self, const SUCOMPLEX *data, SUSCOUNT size) done: if (mutex_acquired) - (void) pthread_mutex_unlock(&self->mutex); + (void)pthread_mutex_unlock(&self->mutex); return ok; } -SUBOOL -su_smoothpsd_set_params( - su_smoothpsd_t *self, +SU_METHOD( + su_smoothpsd, + SUBOOL, + set_params, const struct sigutils_smoothpsd_params *params) { unsigned int i; @@ -193,9 +190,9 @@ su_smoothpsd_set_params( SUBOOL mutex_acquired = SU_FALSE; SU_FFTW(_complex) *window_func = NULL; - SU_FFTW(_complex) *buffer = NULL; - SU_FFTW(_complex) *fftbuf = NULL; - SU_FFTW(_plan) fft_plan = NULL; + SU_FFTW(_complex) *buffer = NULL; + SU_FFTW(_complex) *fftbuf = NULL; + SU_FFTW(_plan) fft_plan = NULL; SUBOOL refresh_window_func = params->window != self->params.window; SUBOOL ok = SU_FALSE; @@ -206,25 +203,25 @@ su_smoothpsd_set_params( * it from the modification of the current object. */ if (params->fft_size != self->params.fft_size) { - if ((window_func - = SU_FFTW(_malloc)( - params->fft_size * sizeof(SU_FFTW(_complex)))) == NULL) { + if ((window_func = + SU_FFTW(_malloc)(params->fft_size * sizeof(SU_FFTW(_complex)))) + == NULL) { SU_ERROR("cannot allocate memory for window\n"); goto done; } - if ((buffer - = SU_FFTW(_malloc)( - params->fft_size * sizeof(SU_FFTW(_complex)))) == NULL) { + if ((buffer = + SU_FFTW(_malloc)(params->fft_size * sizeof(SU_FFTW(_complex)))) + == NULL) { SU_ERROR("cannot allocate memory for circular buffer\n"); goto done; } memset(buffer, 0, params->fft_size * sizeof(SU_FFTW(_complex))); - if ((fftbuf - = SU_FFTW(_malloc)( - params->fft_size * sizeof(SU_FFTW(_complex)))) == NULL) { + if ((fftbuf = + SU_FFTW(_malloc)(params->fft_size * sizeof(SU_FFTW(_complex)))) + == NULL) { SU_ERROR("cannot allocate memory for FFT buffer\n"); goto done; } @@ -233,22 +230,23 @@ su_smoothpsd_set_params( /* Direct FFT plan */ if ((fft_plan = SU_FFTW(_plan_dft_1d)( - params->fft_size, - fftbuf, - fftbuf, - FFTW_FORWARD, - FFTW_ESTIMATE)) == NULL) { + params->fft_size, + fftbuf, + fftbuf, + FFTW_FORWARD, + FFTW_ESTIMATE)) + == NULL) { SU_ERROR("failed to create FFT plan\n"); goto done; } - SU_TRYCATCH(pthread_mutex_lock(&self->mutex) == 0, goto done); + SU_TRYZ(pthread_mutex_lock(&self->mutex)); mutex_acquired = SU_TRUE; _SWAP(window_func, self->window_func); - _SWAP(buffer, self->buffer); - _SWAP(fftbuf, self->fft); - _SWAP(fft_plan, self->fft_plan); + _SWAP(buffer, self->buffer); + _SWAP(fftbuf, self->fft); + _SWAP(fft_plan, self->fft_plan); self->p = 0; @@ -256,7 +254,7 @@ su_smoothpsd_set_params( } if (!mutex_acquired) { - SU_TRYCATCH(pthread_mutex_lock(&self->mutex) == 0, goto done); + SU_TRYZ(pthread_mutex_lock(&self->mutex)); mutex_acquired = SU_TRUE; } @@ -272,15 +270,11 @@ su_smoothpsd_set_params( break; case SU_CHANNEL_DETECTOR_WINDOW_HAMMING: - su_taps_apply_hamming_complex( - self->window_func, - self->params.fft_size); + su_taps_apply_hamming_complex(self->window_func, self->params.fft_size); break; case SU_CHANNEL_DETECTOR_WINDOW_HANN: - su_taps_apply_hann_complex( - self->window_func, - self->params.fft_size); + su_taps_apply_hann_complex(self->window_func, self->params.fft_size); break; case SU_CHANNEL_DETECTOR_WINDOW_FLAT_TOP: @@ -301,7 +295,7 @@ su_smoothpsd_set_params( * never happen either */ SU_WARNING("Unsupported window function %d\n", self->params.window); - return SU_FALSE; + goto done; } } @@ -322,7 +316,7 @@ su_smoothpsd_set_params( done: if (mutex_acquired) - (void) pthread_mutex_unlock(&self->mutex); + (void)pthread_mutex_unlock(&self->mutex); if (fft_plan != NULL) SU_FFTW(_destroy_plan)(fft_plan); @@ -331,7 +325,7 @@ su_smoothpsd_set_params( SU_FFTW(_free)(window_func); if (buffer != NULL) - SU_FFTW(_free)(buffer); + SU_FFTW(_free)(buffer); if (fftbuf != NULL) SU_FFTW(_free)(fftbuf); @@ -339,8 +333,7 @@ su_smoothpsd_set_params( return ok; } -void -su_smoothpsd_destroy(su_smoothpsd_t *self) +SU_COLLECTOR(su_smoothpsd) { if (self->mutex_init) pthread_mutex_destroy(&self->mutex); @@ -352,7 +345,7 @@ su_smoothpsd_destroy(su_smoothpsd_t *self) SU_FFTW(_free)(self->window_func); if (self->buffer != NULL) - SU_FFTW(_free)(self->buffer); + SU_FFTW(_free)(self->buffer); if (self->fft != NULL) SU_FFTW(_free)(self->fft); diff --git a/sigutils/smoothpsd.h b/sigutils/smoothpsd.h index d628432..6bf408e 100644 --- a/sigutils/smoothpsd.h +++ b/sigutils/smoothpsd.h @@ -20,9 +20,9 @@ #ifndef _SIGUTILS_SMOOTHPSD_H #define _SIGUTILS_SMOOTHPSD_H -#include -#include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -35,20 +35,21 @@ struct sigutils_smoothpsd_params { enum sigutils_channel_detector_window window; }; -#define sigutils_smoothpsd_params_INITIALIZER \ -{ \ - 4096, /* fft_size */ \ - 1e6, /* samp_rate */ \ - 25, /* refresh_rate */ \ - SU_CHANNEL_DETECTOR_WINDOW_BLACKMANN_HARRIS /* window */ \ -} +#define sigutils_smoothpsd_params_INITIALIZER \ + { \ + 4096, /* fft_size */ \ + 1e6, /* samp_rate */ \ + 25, /* refresh_rate */ \ + SU_CHANNEL_DETECTOR_WINDOW_BLACKMANN_HARRIS /* window */ \ + } struct sigutils_smoothpsd { struct sigutils_smoothpsd_params params; + SUFLOAT nominal_rate; pthread_mutex_t mutex; - SUBOOL mutex_init; + SUBOOL mutex_init; - SUBOOL (*psd_func) (void *userdata, const SUFLOAT *psd, unsigned int size); + SUBOOL (*psd_func)(void *userdata, const SUFLOAT *psd, unsigned int size); void *userdata; unsigned int p; @@ -57,56 +58,70 @@ struct sigutils_smoothpsd { SUSCOUNT iters; - SU_FFTW(_complex) *window_func; - SU_FFTW(_complex) *buffer; + SU_FFTW(_complex) * window_func; + SU_FFTW(_complex) * buffer; SU_FFTW(_plan) fft_plan; union { - SU_FFTW(_complex) *fft; + SU_FFTW(_complex) * fft; SUFLOAT *realfft; }; }; typedef struct sigutils_smoothpsd su_smoothpsd_t; -SUINLINE SUSCOUNT -su_smoothpsd_get_iters(const su_smoothpsd_t *self) +SUINLINE +SU_GETTER(su_smoothpsd, SUFLOAT, get_nominal_samp_rate) +{ + return self->nominal_rate; +} + +SUINLINE +SU_METHOD( + su_smoothpsd, + void, + set_nominal_samp_rate, + SUFLOAT rate) +{ + self->nominal_rate = rate; +} + +SUINLINE +SU_GETTER(su_smoothpsd, SUSCOUNT, get_iters) { return self->iters; } -SUINLINE unsigned int -su_smoothpsd_get_fft_size(const su_smoothpsd_t *self) +SUINLINE +SU_GETTER(su_smoothpsd, unsigned int, get_fft_size) { return self->params.fft_size; } - -SUINLINE SUFLOAT * -su_smoothpsd_get_last_psd(const su_smoothpsd_t *self) +SUINLINE +SU_GETTER(su_smoothpsd, SUFLOAT *, get_last_psd) { return self->realfft; } -su_smoothpsd_t *su_smoothpsd_new( +SU_INSTANCER( + su_smoothpsd, const struct sigutils_smoothpsd_params *params, - SUBOOL (*psd_func) (void *userdata, const SUFLOAT *psd, unsigned int size), + SUBOOL (*psd_func)(void *userdata, const SUFLOAT *psd, unsigned int size), void *userdata); -SUBOOL su_smoothpsd_feed( - su_smoothpsd_t *self, - const SUCOMPLEX *data, - SUSCOUNT size); +SU_COLLECTOR(su_smoothpsd); -SUBOOL su_smoothpsd_set_params( - su_smoothpsd_t *self, - const struct sigutils_smoothpsd_params *params); +SU_METHOD(su_smoothpsd, SUBOOL, feed, const SUCOMPLEX *data, SUSCOUNT size); -void su_smoothpsd_destroy(su_smoothpsd_t *self); +SU_METHOD( + su_smoothpsd, + SUBOOL, + set_params, + const struct sigutils_smoothpsd_params *params); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _SIGUTILS_SMOOTHPSD_H */ - diff --git a/sigutils/softtune.c b/sigutils/softtune.c index cc0cf31..87bd8fb 100644 --- a/sigutils/softtune.c +++ b/sigutils/softtune.c @@ -49,7 +49,7 @@ su_softtuner_init( assert(params->samp_rate > 0); assert(params->decimation > 0); - memset(tuner, 0, sizeof (su_softtuner_t)); + memset(tuner, 0, sizeof(su_softtuner_t)); tuner->params = *params; tuner->avginv = 1. / params->decimation; @@ -68,8 +68,8 @@ su_softtuner_init( &tuner->antialias, SU_SOFTTUNER_ANTIALIAS_ORDER, .5 * SU_ABS2NORM_FREQ(params->samp_rate, params->bw) - * SU_SOFTTUNER_ANTIALIAS_EXTRA_BW), - goto fail); + * SU_SOFTTUNER_ANTIALIAS_EXTRA_BW), + goto fail); tuner->filtered = SU_TRUE; } @@ -82,12 +82,9 @@ su_softtuner_init( } SUSCOUNT -su_softtuner_feed( - su_softtuner_t *tuner, - const SUCOMPLEX *input, - SUSCOUNT size) +su_softtuner_feed(su_softtuner_t *tuner, const SUCOMPLEX *input, SUSCOUNT size) { - SUSCOUNT i = 0; + SUSCOUNT i = 0; SUCOMPLEX x; SUSCOUNT avail; SUCOMPLEX *buf; @@ -153,5 +150,5 @@ su_softtuner_finalize(su_softtuner_t *tuner) su_stream_finalize(&tuner->output); - memset(tuner, 0, sizeof (su_softtuner_t)); + memset(tuner, 0, sizeof(su_softtuner_t)); } diff --git a/sigutils/softtune.h b/sigutils/softtune.h index 3d4b897..4a8930d 100644 --- a/sigutils/softtune.h +++ b/sigutils/softtune.h @@ -21,48 +21,50 @@ #define _SIGUTILS_SOFTTUNE_H #include "block.h" -#include "sigutils.h" +#include "iir.h" #include "ncqo.h" #include "sampling.h" -#include "iir.h" +#include "sigutils.h" /* Extra bandwidth given to antialias filter */ #define SU_SOFTTUNER_ANTIALIAS_EXTRA_BW 2 -#define SU_SOFTTUNER_ANTIALIAS_ORDER 4 +#define SU_SOFTTUNER_ANTIALIAS_ORDER 4 struct sigutils_channel { - SUFREQ fc; /* Channel central frequency */ - SUFREQ f_lo; /* Lower frequency belonging to the channel */ - SUFREQ f_hi; /* Upper frequency belonging to the channel */ - SUFLOAT bw; /* Equivalent bandwidth */ - SUFLOAT snr; /* Signal-to-noise ratio */ - SUFLOAT S0; /* Peak signal power */ - SUFLOAT N0; /* Noise level */ - SUFREQ ft; /* Tuner frequency */ + SUFREQ fc; /* Channel central frequency */ + SUFREQ f_lo; /* Lower frequency belonging to the channel */ + SUFREQ f_hi; /* Upper frequency belonging to the channel */ + SUFLOAT bw; /* Equivalent bandwidth */ + SUFLOAT snr; /* Signal-to-noise ratio */ + SUFLOAT S0; /* Peak signal power */ + SUFLOAT N0; /* Noise level */ + SUFREQ ft; /* Tuner frequency */ uint32_t age; /* Channel age */ uint32_t present; /* Is channel present? */ }; +typedef struct sigutils_channel su_channel_t; + struct sigutils_softtuner_params { SUSCOUNT samp_rate; SUSCOUNT decimation; - SUFREQ fc; - SUFLOAT bw; + SUFREQ fc; + SUFLOAT bw; }; -#define sigutils_softtuner_params_INITIALIZER \ -{ \ - 0, /* samp_rate */ \ - 0, /* decimation */ \ - 0, /* fc */ \ - 0, /* bw */ \ -} +#define sigutils_softtuner_params_INITIALIZER \ + { \ + 0, /* samp_rate */ \ + 0, /* decimation */ \ + 0, /* fc */ \ + 0, /* bw */ \ + } struct sigutils_softtuner { struct sigutils_softtuner_params params; - su_ncqo_t lo; /* Local oscillator */ + su_ncqo_t lo; /* Local oscillator */ su_iir_filt_t antialias; /* Antialiasing filter */ - su_stream_t output; /* Output stream */ + su_stream_t output; /* Output stream */ su_off_t read_ptr; SUSCOUNT decim_ptr; SUBOOL filtered; @@ -76,9 +78,7 @@ su_channel_detector_set_fc(su_softtuner_t *cd, SUFLOAT fc) { cd->params.fc = fc; - su_ncqo_init( - &cd->lo, - SU_ABS2NORM_FREQ(cd->params.samp_rate, cd->params.fc)); + su_ncqo_init(&cd->lo, SU_ABS2NORM_FREQ(cd->params.samp_rate, cd->params.fc)); } void su_softtuner_params_adjust_to_channel( @@ -89,15 +89,10 @@ SUBOOL su_softtuner_init( su_softtuner_t *tuner, const struct sigutils_softtuner_params *params); -SUSCOUNT su_softtuner_feed( - su_softtuner_t *tuner, - const SUCOMPLEX *input, - SUSCOUNT size); +SUSCOUNT +su_softtuner_feed(su_softtuner_t *tuner, const SUCOMPLEX *input, SUSCOUNT size); -SUSDIFF su_softtuner_read( - su_softtuner_t *tuner, - SUCOMPLEX *out, - SUSCOUNT size); +SUSDIFF su_softtuner_read(su_softtuner_t *tuner, SUCOMPLEX *out, SUSCOUNT size); void su_softtuner_finalize(su_softtuner_t *tuner); diff --git a/sigutils/specific/apt.c b/sigutils/specific/apt.c new file mode 100644 index 0000000..fdcc0c7 --- /dev/null +++ b/sigutils/specific/apt.c @@ -0,0 +1,591 @@ +/* + + Copyright (C) 2021 Gonzalo José Carracedo Carballal + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + + +*/ + +#define _SU_LOG_DOMAIN "apt" + +#include "apt.h" + +#include +#include +#include +#include + +SUPRIVATE unsigned int +su_apt_decoder_correlate( + su_apt_decoder_t *self, + const SUCOMPLEX *pat, + unsigned int start, + unsigned int end, + SUFLOAT *snr, + SUFLOAT *delta) +{ + unsigned int i, where; + unsigned int p = start; + unsigned int len; + int p_signed; + SUFLOAT max, psd; + SUFLOAT sig_noise = SU_APT_MIN_LEVEL; + + SUFLOAT mean, sum; + + /* Correlate */ + SU_FFTW(_execute)(self->direct_plan); + for (i = 0; i < SU_APT_BUFF_LEN; ++i) + self->corr_fft[i] *= SU_C_CONJ(pat[i]); + SU_FFTW(_execute)(self->reverse_plan); + + /* Find pulse. This is actually a first guess. */ + max = SU_APT_MIN_LEVEL; + where = start; + len = (SU_APT_BUFF_LEN + end - start) % SU_APT_BUFF_LEN + 1; + + for (i = 0; i < len; ++i) { + self->corr_fft[p] *= SU_C_CONJ(self->corr_fft[p]); + psd = SU_C_REAL(self->corr_fft[p]); + + sig_noise += psd; + if (psd > max) { + where = p; + max = psd; + } + + if (++p >= SU_APT_BUFF_LEN) + p = 0; + } + + *snr = len * max / (sig_noise - max); + + /* Get the pulse position _with decimals_ */ + mean = sum = 0; + for (i = 0; i < 7; ++i) { + p_signed = where + i - 3; + psd = SU_C_REAL( + self->corr_fft[(SU_APT_BUFF_LEN + p_signed) % SU_APT_BUFF_LEN]); + mean += p_signed * psd; + sum += psd; + } + mean /= sum; + + *delta = mean - SU_FLOOR(mean); + where = (SU_APT_BUFF_LEN + (int)SU_FLOOR(mean)) % SU_APT_BUFF_LEN; + + return where; +} + +SUPRIVATE void +su_apt_decoder_update_levels(su_apt_decoder_t *self, SUBOOL detected) +{ + unsigned int i; + + SUFLOAT mean_white = 0; + SUFLOAT mean_black = 0; + + SUFLOAT min = INFINITY; + SUFLOAT max = -INFINITY; + + if (detected) { + /* Find black and white levels */ + for (i = 0; i < SU_APT_LEVEL_LEN; ++i) { + mean_black += + self->line_buffer[(SU_APT_BLACK_START + i) % SU_APT_LINE_BUFF_LEN]; + mean_white += + self->line_buffer[(SU_APT_WHITE_START + i) % SU_APT_LINE_BUFF_LEN]; + } + + // fprintf(stderr, "%d: %g\n", self->lines, mean_white - mean_black, + // mean_white, mean_black); + mean_black /= SU_APT_LEVEL_LEN; + mean_white /= SU_APT_LEVEL_LEN; + + if (mean_black < mean_white + && !sufeq(mean_white, mean_black, .5 * (mean_white + mean_black))) { + if (!self->have_levels) { + self->mean_black = mean_black; + self->mean_white = mean_white; + self->have_levels = SU_TRUE; + } else { + SU_SPLPF_FEED(self->mean_black, mean_black, self->line_len_alpha); + SU_SPLPF_FEED(self->mean_white, mean_white, self->line_len_alpha); + } + } + } + + /* No valid levels yet. Temporary guess based on signal power. */ + if (!self->have_levels) { + for (i = 0; i < self->line_ptr; ++i) { + if (min > self->line_buffer[i]) + min = self->line_buffer[i]; + if (max < self->line_buffer[i]) + max = self->line_buffer[i]; + } + + self->mean_black = min; + self->mean_white = max + SU_APT_MIN_LEVEL; + } +} + +SUPRIVATE SUBOOL +su_apt_decoder_flush_line(su_apt_decoder_t *self, SUBOOL detected) +{ + uint8_t *line = NULL; + unsigned int i, j, ndx; + SUFLOAT beta, value; + SUFLOAT range; + int px; + + SUBOOL ok = SU_FALSE; + + if (self->line_ptr < SU_APT_CHANNEL_LEN) + return SU_TRUE; + + SU_TRYCATCH(line = malloc(sizeof(uint8_t) * SU_APT_LINE_LEN), goto done); + + su_apt_decoder_update_levels(self, detected); + range = self->mean_white - self->mean_black; + + for (i = 0; i < SU_APT_LINE_LEN; ++i) { + ndx = (self->line_ptr - 1) * i / (SUFLOAT)(SU_APT_LINE_LEN - 1); + j = SU_FLOOR(ndx); + beta = ndx - j; + + if (j < self->line_ptr - 1) + value = + (1 - beta) * self->line_buffer[j] + beta * self->line_buffer[j + 1]; + else + value = self->line_buffer[j]; + + px = (unsigned int)(255 * (value - self->mean_black) / range); + + if (px > 255) + px = 255; + if (px < 0) + px = 0; + + line[i] = px; + } + + if (self->callbacks.on_line_data != NULL) { + SU_TRYCATCH( + (self->callbacks.on_line_data)( + self, + self->callbacks.userdata, + self->lines, + SU_APT_DECODER_CHANNEL_B, + detected, + line, + SU_APT_CHANNEL_LEN), + goto done); + SU_TRYCATCH( + (self->callbacks.on_line_data)( + self, + self->callbacks.userdata, + self->lines + 1, + SU_APT_DECODER_CHANNEL_A, + detected, + line + SU_APT_CHANNEL_LEN, + SU_APT_CHANNEL_LEN), + goto done); + } + + SU_TRYCATCH(PTR_LIST_APPEND_CHECK(self->scan_line, line) != -1, goto done); + line = NULL; + + memset(self->line_buffer, 0, self->line_ptr * sizeof(SUFLOAT)); + self->line_ptr = 0; + + ++self->lines; + + ok = SU_TRUE; + +done: + if (line != NULL) + free(line); + + return ok; +} + +SUPRIVATE void +su_apt_decoder_extract_line_until(su_apt_decoder_t *self, unsigned int pos) +{ + unsigned int p = self->line_last_samp; + + while (p != pos) { + if (p >= SU_APT_LINE_BUFF_LEN) + p = 0; + + if (self->line_ptr >= SU_APT_LINE_LEN) + break; + + self->line_buffer[self->line_ptr++] = + (1 - self->last_sync_delta) * self->samp_buffer[p] + + (self->last_sync_delta) + * self->samp_buffer[(p + 1) % SU_APT_LINE_BUFF_LEN]; + ++p; + } + + self->line_last_samp = pos; +} + +SUINLINE SUSCOUNT +su_apt_decoder_pos_to_abs(const su_apt_decoder_t *self, SUSCOUNT pos) +{ + return pos >= self->samp_ptr ? self->samp_epoch - SU_APT_BUFF_LEN + pos + : self->samp_epoch + pos; +} + +SUPRIVATE SUBOOL +su_apt_decoder_perform_search(su_apt_decoder_t *self) +{ + unsigned int pos; + SUSCOUNT abs_pos; + SUFLOAT snr; + SUSCOUNT line_len; + SUSCOUNT next_search; + unsigned int expected_sync; + unsigned int search_start, search_end; + SUBOOL have_line = SU_FALSE; + SUFLOAT delta; + SUBOOL ok = SU_FALSE; + + /* + * If the last sync is still in the circular buffer, we intentionally + * skip it from search. + */ + if (self->count - self->last_sync < SU_APT_BUFF_LEN) + search_start = (self->last_sync + SU_APT_SYNC_SIZE) % SU_APT_BUFF_LEN; + else + search_start = self->samp_ptr; + search_end = (SU_APT_BUFF_LEN + self->samp_ptr - 1) % SU_APT_BUFF_LEN; + + next_search = self->count + self->line_len / 2; + + /* Correlate against SYNC B */ + pos = su_apt_decoder_correlate( + self, + self->sync_fft, + search_start, + search_end, + &snr, + &delta); + abs_pos = su_apt_decoder_pos_to_abs(self, pos); + + if (snr > SU_APT_SYNC_MIN_SNR) { + /* + * Sync found! + * + * If the distance between this sync and the last one is compatible + * with the line size, we assume it is a full line and adjust the true + * line size accordingly. + */ + + if (self->callbacks.on_sync != NULL) { + SU_TRYCATCH( + (self->callbacks.on_sync)(self, self->callbacks.userdata, abs_pos), + goto done); + } + + line_len = abs_pos - self->last_sync; + + if (sufeq(line_len, SU_APT_LINE_LEN, 5e-2 * SU_APT_LINE_LEN)) { + SU_SPLPF_FEED(self->line_len, line_len, self->line_len_alpha); + + if (self->callbacks.on_line != NULL) { + SU_TRYCATCH( + (self->callbacks.on_line)( + self, + self->callbacks.userdata, + self->line_len), + goto done); + } + + have_line = SU_TRUE; + } + + /* In any case, we already have a guess for the next sync */ + next_search = abs_pos + self->line_len + SU_APT_SYNC_SIZE; + self->last_sync = abs_pos; + self->next_sync = self->last_sync + self->line_len; + + su_apt_decoder_extract_line_until(self, pos); + su_apt_decoder_flush_line(self, have_line); + + self->last_sync_delta = delta; + } else { + if (self->lines > 0) { + if (su_apt_decoder_pos_to_abs(self, search_start) < self->next_sync + && self->next_sync + SU_APT_SYNC_SIZE + < su_apt_decoder_pos_to_abs(self, search_end)) { + next_search = self->next_sync + self->line_len + SU_APT_SYNC_SIZE; + expected_sync = self->next_sync % SU_APT_LINE_BUFF_LEN; + self->next_sync += SU_FLOOR(self->line_len); + delta = 0; + + su_apt_decoder_extract_line_until(self, expected_sync); + su_apt_decoder_flush_line(self, SU_FALSE); + + self->last_sync_delta = delta; + } + } + } + + su_apt_decoder_extract_line_until(self, self->samp_ptr); + self->next_search = next_search; + + ok = SU_TRUE; + +done: + return ok; +} + +void +su_apt_decoder_set_snr(su_apt_decoder_t *self, SUFLOAT snr) +{ + self->sync_snr = snr; +} + +SUBOOL +su_apt_decoder_feed_ex( + su_apt_decoder_t *self, + SUBOOL phase_only, + const SUCOMPLEX *buffer, + SUSCOUNT count) +{ + SUSCOUNT i; + SUCOMPLEX x; + SUFLOAT pwr; + SUFLOAT snr; + + for (i = 0; i < count; ++i) { + x = su_iir_filt_feed( + &self->mf, + su_pll_track( + &self->pll, + phase_only + ? SU_C_ARG(buffer[i]) + : buffer[i])); + + if (su_sampler_feed(&self->resampler, &x)) { + pwr = SU_C_REAL(x * SU_C_CONJ(x)); + self->mean_i += SU_C_REAL(x) * SU_C_REAL(x); + self->mean_q += SU_C_IMAG(x) * SU_C_IMAG(x); + + self->samp_buffer[self->samp_ptr++] = pwr; + if (self->samp_ptr >= SU_APT_BUFF_LEN) { + snr = SU_ABS(SU_POWER_DB_RAW(self->mean_i / self->mean_q)); + + if (self->callbacks.on_carrier != NULL) + SU_TRYCATCH( + (self->callbacks.on_carrier)( + self, + self->callbacks.userdata, + SU_POWER_DB(snr)), + return SU_FALSE); + + self->samp_ptr = 0; + self->mean_i = self->mean_q = 0; + self->samp_epoch += SU_APT_BUFF_LEN; + } + + ++self->count; + + if (self->count >= self->next_search) { + SU_TRYCATCH(su_apt_decoder_perform_search(self), return SU_FALSE); + } + } + } + + return SU_TRUE; +} + +SUBOOL +su_apt_decoder_feed( + su_apt_decoder_t *self, + const SUCOMPLEX *buffer, + SUSCOUNT count) +{ + return su_apt_decoder_feed_ex(self, SU_FALSE, buffer, count); +} + +void +su_apt_decoder_clear_image(su_apt_decoder_t *self) +{ + unsigned int i; + + for (i = 0; i < self->scan_line_count; ++i) + free(self->scan_line_list[i]); + + if (self->scan_line_list != NULL) + free(self->scan_line_list); + + self->scan_line_count = 0; + self->scan_line_list = NULL; +} + +SUBOOL +su_apt_decoder_dump_pgm(const su_apt_decoder_t *self, const char *path) +{ + FILE *fp = NULL; + unsigned int i, j; + SUBOOL ok = SU_FALSE; + + SU_TRYCATCH(fp = fopen(path, "w"), goto fail); + + fprintf(fp, "P2\n"); + fprintf(fp, "# Generated by BatchDrake's APT Hack\n"); + fprintf(fp, "%d %u\n", SU_APT_LINE_LEN, self->scan_line_count); + fprintf(fp, "255\n"); + + for (j = 1; j < self->scan_line_count; ++j) { + for (i = 0; i < SU_APT_CHANNEL_LEN; ++i) + fprintf(fp, "%4d", self->scan_line_list[j][i + SU_APT_CHANNEL_LEN]); + for (i = 0; i < SU_APT_CHANNEL_LEN; ++i) + fprintf(fp, "%4d", self->scan_line_list[j - 1][i]); + + fprintf(fp, "\n"); + } + + ok = SU_TRUE; + +fail: + if (fp != NULL) + fclose(fp); + + return ok; +} + +/* + * fs: samples per second + * SU_APT_IF_RATE: words per second + * fs / SU_APT_IF_RATE: samples per word + */ + +su_apt_decoder_t * +su_apt_decoder_new(SUFLOAT fs, const struct sigutils_apt_decoder_callbacks *cb) +{ + su_apt_decoder_t *new = NULL; + SU_FFTW(_plan) pattern_plan = NULL; + unsigned int i = 0, j; + SUFLOAT kinv; + SUFLOAT bw; + SUFLOAT samps_per_word = fs / SU_APT_IF_RATE; + SUBOOL ok = SU_FALSE; + + SU_TRYCATCH(new = calloc(1, sizeof(su_apt_decoder_t)), goto done); + + if (cb != NULL) + new->callbacks = *cb; + + new->samp_rate = fs; + new->line_len = SU_APT_LINE_LEN; + new->line_len_alpha = SU_SPLPF_ALPHA(SU_APT_TRAINING_LINES); + new->sync_snr = SU_APT_SYNC_MIN_SNR; + new->next_search = new->line_len / 2; + + /* Setup PLL */ + bw = SU_ABS2NORM_FREQ(fs, SU_APT_AM_BANDWIDTH); + + SU_TRYCATCH( + pattern_plan = SU_FFTW(_plan_dft_1d)( + SU_APT_BUFF_LEN, + new->sync_fft, + new->sync_fft, + FFTW_FORWARD, + FFTW_ESTIMATE), + goto done); + + SU_TRYCATCH( + new->direct_plan = SU_FFTW(_plan_dft_1d)( + SU_APT_BUFF_LEN, + new->samp_buffer, + new->corr_fft, + FFTW_FORWARD, + FFTW_ESTIMATE), + goto done); + + SU_TRYCATCH( + new->reverse_plan = SU_FFTW(_plan_dft_1d)( + SU_APT_BUFF_LEN, + new->corr_fft, + new->corr_fft, + FFTW_BACKWARD, + FFTW_ESTIMATE), + goto done); + + su_pll_init( + &new->pll, + SU_ABS2NORM_FREQ(fs, SU_APT_AM_CARRIER_FREQ), + .001f * bw); + + /* Setup matched filter for 4160 Hz */ + SU_TRYCATCH( + su_iir_rrc_init( + &new->mf, + 5 * SU_CEIL(2 * samps_per_word), + 2 * samps_per_word, + .55), + goto done); + + /* Set resampler */ + SU_TRYCATCH( + su_sampler_init(&new->resampler, SU_ABS2NORM_BAUD(fs, SU_APT_IF_RATE)), + goto done); + + kinv = 1. / SU_APT_SYNC_SIZE; + + /* Configure channel B detector */ + for (i = 0; i < SU_APT_SYNC_SIZE; ++i) { + j = (i - 4) % 5; + new->sync_fft[i] = (i >= 4 && j < 3) ? kinv : -kinv; + } + + SU_FFTW(_execute)(pattern_plan); + + ok = SU_TRUE; + +done: + if (!ok) { + if (new != NULL) { + su_apt_decoder_destroy(new); + new = NULL; + } + } + + if (pattern_plan != NULL) + SU_FFTW(_destroy_plan)(pattern_plan); + + return new; +} + +void +su_apt_decoder_destroy(su_apt_decoder_t *self) +{ + if (self->reverse_plan != NULL) + SU_FFTW(_destroy_plan)(self->reverse_plan); + + if (self->direct_plan != NULL) + SU_FFTW(_destroy_plan)(self->direct_plan); + + su_apt_decoder_clear_image(self); + + su_sampler_finalize(&self->resampler); + su_iir_filt_finalize(&self->mf); + su_pll_finalize(&self->pll); + + free(self); +} diff --git a/sigutils/specific/apt.h b/sigutils/specific/apt.h new file mode 100644 index 0000000..9449eb8 --- /dev/null +++ b/sigutils/specific/apt.h @@ -0,0 +1,169 @@ +/* + + Copyright (C) 2021 Gonzalo José Carracedo Carballal + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + + +*/ + +#ifndef _SIGUTILS_SPECIFIC_APT_H +#define _SIGUTILS_SPECIFIC_APT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* https://web.archive.org/web/20070505090431/http://www2.ncdc.noaa.gov/docs/klm/html/c4/sec4-2.htm + */ + +#define SU_APT_IF_RATE 4160 +#define SU_APT_LINE_LEN (SU_APT_IF_RATE / 2) +#define SU_APT_CHANNEL_LEN (SU_APT_LINE_LEN / 2) + +#define SU_APT_SYNC_SIZE 39 /* By spec */ +#define SU_APT_SYNC_MIN_SNR 40 + +#define SU_APT_AM_CARRIER_FREQ 2400 +#define SU_APT_AM_BANDWIDTH 2400 + +#define SU_APT_BUFF_LEN (2 * SU_APT_LINE_LEN + 2 * SU_APT_SYNC_SIZE) +#define SU_APT_LINE_BUFF_LEN SU_APT_BUFF_LEN +#define SU_APT_TRAINING_LINES 50 +#define SU_APT_LINE_LEN_THRESHOLD (SU_APT_SYNC_SIZE / 2) +#define SU_APT_MINUTE_MARKER_LEN 47 +#define SU_APT_VIDEO_DATA_LEN 909 +#define SU_APT_TELEMETRY_LEN 45 +#define SU_APT_SYNC_B_OFFSET \ + (SU_APT_SYNC_SIZE + SU_APT_MINUTE_MARKER_LEN + SU_APT_TELEMETRY_LEN \ + + SU_APT_VIDEO_DATA_LEN) +#define SU_APT_LEVEL_LEN 10 +#define SU_APT_BLACK_START 1085 +#define SU_APT_WHITE_START 45 +#define SU_APT_MIN_CARRIER_DB 1 +#define SU_APT_MIN_LEVEL 1e-30 + +enum sigutils_apt_decoder_channel { + SU_APT_DECODER_CHANNEL_A, + SU_APT_DECODER_CHANNEL_B +}; + +struct sigutils_apt_decoder; + +struct sigutils_apt_decoder_callbacks { + void *userdata; + + SUBOOL (*on_carrier)(struct sigutils_apt_decoder *, void *, SUFLOAT); + SUBOOL (*on_sync)(struct sigutils_apt_decoder *, void *, SUSCOUNT); + SUBOOL (*on_line)(struct sigutils_apt_decoder *, void *, SUFLOAT); + SUBOOL(*on_line_data) + (struct sigutils_apt_decoder *, + void *, + SUSCOUNT, + enum sigutils_apt_decoder_channel, + SUBOOL, + const uint8_t *, + size_t); +}; + +#define sigutils_apt_decoder_callbacks_INITIALIZER \ + { \ + NULL, /* userdata */ \ + NULL, /* on_carrier */ \ + NULL, /* on_sync */ \ + NULL, /* on_line */ \ + NULL, /* on_line_data */ \ + } + +struct sigutils_apt_decoder { + SUFLOAT samp_rate; + su_pll_t pll; /* To center carrier */ + su_iir_filt_t mf; /* Matched filter for 4160 Hz */ + su_sampler_t resampler; /* Resampler */ + + /* The following objects work at a 4160 rate */ + SUSCOUNT count; + + SUCOMPLEX samp_buffer[SU_APT_BUFF_LEN]; + unsigned int samp_ptr; + SUSCOUNT samp_epoch; + + SUFLOAT mean_i; + SUFLOAT mean_q; + + /* Correlator data */ + SUFLOAT sync_snr; + SUCOMPLEX sync_fft[SU_APT_BUFF_LEN]; + SUCOMPLEX corr_fft[SU_APT_BUFF_LEN]; + SU_FFTW(_plan) direct_plan; + SU_FFTW(_plan) reverse_plan; + + /* Sync detection */ + SUSCOUNT last_sync; + SUSCOUNT next_sync; + SUSCOUNT next_search; + SUFLOAT last_sync_delta; + + /* Line buffer */ + SUFLOAT line_buffer[SU_APT_LINE_BUFF_LEN]; + SUSCOUNT last_epoch; + unsigned int line_ptr; + unsigned int line_last_samp; + + /* Image */ + PTR_LIST(uint8_t, scan_line); + + SUSCOUNT lines; + SUFLOAT line_len_alpha; + SUFLOAT line_len; + SUFLOAT mean_black; + SUFLOAT mean_white; + SUBOOL have_levels; + + struct sigutils_apt_decoder_callbacks callbacks; +}; + +typedef struct sigutils_apt_decoder su_apt_decoder_t; + +su_apt_decoder_t *su_apt_decoder_new( + SUFLOAT fs, + const struct sigutils_apt_decoder_callbacks *); + +SUBOOL su_apt_decoder_feed_ex( + su_apt_decoder_t *self, + SUBOOL phase_only, + const SUCOMPLEX *buffer, + SUSCOUNT count); + +SUBOOL su_apt_decoder_feed( + su_apt_decoder_t *self, + const SUCOMPLEX *buffer, + SUSCOUNT count); + +void su_apt_decoder_clear_image(su_apt_decoder_t *self); + +void su_apt_decoder_set_snr(su_apt_decoder_t *self, SUFLOAT); + +SUBOOL su_apt_decoder_dump_pgm(const su_apt_decoder_t *self, const char *path); + +void su_apt_decoder_destroy(su_apt_decoder_t *self); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _SIGUTILS_SPECIFIC_APT_H */ diff --git a/sigutils/specttuner.c b/sigutils/specttuner.c index 0995814..00d464b 100644 --- a/sigutils/specttuner.c +++ b/sigutils/specttuner.c @@ -19,53 +19,79 @@ #define SU_LOG_DOMAIN "specttuner" -#include "log.h" -#include +#include "specttuner.h" + #include +#include + +#include "log.h" #include "sampling.h" #include "taps.h" -#include "specttuner.h" -SUPRIVATE void -su_specttuner_channel_destroy(su_specttuner_channel_t *channel) +#ifdef SU_USE_VOLK +# define calloc su_volk_calloc +# define malloc su_volk_malloc +# define free volk_free +SUINLINE void * +su_volk_malloc(size_t size) +{ + return volk_malloc(size, volk_get_alignment()); +} + +SUINLINE void * +su_volk_calloc(size_t nmemb, size_t size) +{ + void *result = su_volk_malloc(nmemb * size); + + if (result != NULL) + memset(result, 0, nmemb * size); + + return result; +} +#endif /* SU_USE_VOLK */ + +SUPRIVATE +SU_COLLECTOR(su_specttuner_channel) { - if (channel->plan[SU_SPECTTUNER_STATE_EVEN] != NULL) - SU_FFTW(_destroy_plan) (channel->plan[SU_SPECTTUNER_STATE_EVEN]); + if (self->plan[SU_SPECTTUNER_STATE_EVEN] != NULL) + SU_FFTW(_destroy_plan)(self->plan[SU_SPECTTUNER_STATE_EVEN]); - if (channel->plan[SU_SPECTTUNER_STATE_ODD] != NULL) - SU_FFTW(_destroy_plan) (channel->plan[SU_SPECTTUNER_STATE_ODD]); + if (self->plan[SU_SPECTTUNER_STATE_ODD] != NULL) + SU_FFTW(_destroy_plan)(self->plan[SU_SPECTTUNER_STATE_ODD]); - if (channel->ifft[SU_SPECTTUNER_STATE_EVEN] != NULL) - SU_FFTW(_free) (channel->ifft[SU_SPECTTUNER_STATE_EVEN]); + if (self->ifft[SU_SPECTTUNER_STATE_EVEN] != NULL) + SU_FFTW(_free)(self->ifft[SU_SPECTTUNER_STATE_EVEN]); - if (channel->ifft[SU_SPECTTUNER_STATE_ODD] != NULL) - SU_FFTW(_free) (channel->ifft[SU_SPECTTUNER_STATE_ODD]); + if (self->ifft[SU_SPECTTUNER_STATE_ODD] != NULL) + SU_FFTW(_free)(self->ifft[SU_SPECTTUNER_STATE_ODD]); - if (channel->fft != NULL) - SU_FFTW(_free) (channel->fft); + if (self->fft != NULL) + SU_FFTW(_free)(self->fft); - if (channel->window != NULL) - SU_FFTW(_free) (channel->window); + if (self->window != NULL) + SU_FFTW(_free)(self->window); - if (channel->forward != NULL) - SU_FFTW(_destroy_plan) (channel->forward); + if (self->forward != NULL) + SU_FFTW(_destroy_plan)(self->forward); - if (channel->backward != NULL) - SU_FFTW(_destroy_plan) (channel->backward); + if (self->backward != NULL) + SU_FFTW(_destroy_plan)(self->backward); - if (channel->h != NULL) - SU_FFTW(_free) (channel->h); + if (self->h != NULL) + SU_FFTW(_free)(self->h); - free(channel); + free(self); } -SUPRIVATE void -su_specttuner_update_channel_filter( - const su_specttuner_t *owner, +SUPRIVATE +SU_METHOD_CONST( + su_specttuner, + void, + update_channel_filter, su_specttuner_channel_t *channel) { SUCOMPLEX tmp; - unsigned int window_size = owner->params.window_size; + unsigned int window_size = self->params.window_size; unsigned int window_half = window_size / 2; unsigned int i; @@ -78,7 +104,7 @@ su_specttuner_update_channel_filter( } /* Second step: switch to time domain */ - SU_FFTW(_execute) (channel->backward); + SU_FFTW(_execute)(channel->backward); /* Third step: recenter coefficients to apply window function */ for (i = 0; i < window_half; ++i) { @@ -98,38 +124,38 @@ su_specttuner_update_channel_filter( } /* Sixth step: move back to frequency domain */ - SU_FFTW(_execute) (channel->forward); + SU_FFTW(_execute)(channel->forward); } -SUPRIVATE SUBOOL -su_specttuner_init_filter_response( - const su_specttuner_t *owner, +SUPRIVATE +SU_METHOD_CONST( + su_specttuner, + SUBOOL, + init_filter_response, su_specttuner_channel_t *channel) { SUBOOL ok = SU_FALSE; - unsigned int window_size = owner->params.window_size; + unsigned int window_size = self->params.window_size; /* Backward plan */ - SU_TRYCATCH( + SU_TRY( channel->forward = SU_FFTW(_plan_dft_1d)( window_size, channel->h, channel->h, FFTW_FORWARD, - FFTW_ESTIMATE), - goto done); + FFTW_MEASURE)); /* Forward plan */ - SU_TRYCATCH( + SU_TRY( channel->backward = SU_FFTW(_plan_dft_1d)( window_size, channel->h, channel->h, FFTW_BACKWARD, - FFTW_ESTIMATE), - goto done); + FFTW_MEASURE)); - su_specttuner_update_channel_filter(owner, channel); + su_specttuner_update_channel_filter(self, channel); ok = SU_TRUE; done: @@ -137,42 +163,66 @@ su_specttuner_init_filter_response( return ok; } -void -su_specttuner_set_channel_freq( - const su_specttuner_t *st, - su_specttuner_channel_t *channel, - SUFLOAT f0) +SUPRIVATE +SU_METHOD_CONST( + su_specttuner, + void, + refresh_channel_center, + su_specttuner_channel_t *channel) { - unsigned int window_size = st->params.window_size; - su_ncqo_t lo = su_ncqo_INITIALIZER; - SUFLOAT off; + unsigned int window_size = self->params.window_size; + SUFLOAT rbw = 2 * PI / window_size; + SUFLOAT off, ef; - channel->params.f0 = f0; - channel->center = 2 * SU_ROUND(f0 / (4 * PI) * window_size); + ef = su_specttuner_channel_get_effective_freq(channel); + channel->center = 2 * SU_FLOOR(.5 * (ef + 1 * rbw) / (2 * PI) * window_size); - if (channel->center < 0) + if (channel->center < 0) { channel->center = 0; + } if (channel->center >= window_size) channel->center = window_size - 2; if (channel->params.precise) { - off = channel->center * (2 * PI) / (SUFLOAT) window_size - f0; + off = (channel->center) * rbw - ef; off *= channel->decimation; - su_ncqo_init_fixed(&channel->lo, SU_ANG2NORM_FREQ(off)); + su_ncqo_set_angfreq(&channel->lo, off); } } -SUBOOL -su_specttuner_set_channel_bandwidth( - const su_specttuner_t *st, +SU_METHOD_CONST( + su_specttuner, + void, + set_channel_freq, + su_specttuner_channel_t *channel, + SUFLOAT f0) +{ + channel->params.f0 = f0; + channel->pending_freq = SU_TRUE; +} + +SU_METHOD_CONST( + su_specttuner, + void, + set_channel_delta_f, + su_specttuner_channel_t *channel, + SUFLOAT delta_f) +{ + channel->params.delta_f = delta_f; + channel->pending_freq = SU_TRUE; +} + +SU_METHOD_CONST( + su_specttuner, + SUBOOL, + set_channel_bandwidth, su_specttuner_channel_t *channel, SUFLOAT bw) { SUFLOAT k; - unsigned int min_size; unsigned int width; - unsigned int window_size = st->params.window_size; + unsigned int window_size = self->params.window_size; if (bw > 2 * PI) bw = 2 * PI; @@ -192,38 +242,57 @@ su_specttuner_set_channel_bandwidth( SU_TRYCATCH(width <= channel->size, return SU_FALSE); SU_TRYCATCH(width > 1, return SU_FALSE); - channel->width = width; - channel->halfw = channel->width >> 1; + channel->width = width; + channel->halfw = channel->width >> 1; - su_specttuner_update_channel_filter(st, channel); + su_specttuner_update_channel_filter(self, channel); return SU_TRUE; } -SUPRIVATE su_specttuner_channel_t * -su_specttuner_channel_new( +SUPRIVATE +SU_INSTANCER( + su_specttuner_channel, const su_specttuner_t *owner, const struct sigutils_specttuner_channel_params *params) { su_specttuner_channel_t *new = NULL; unsigned int window_size = owner->params.window_size; + SUFLOAT rbw = 2 * PI / window_size; unsigned int n = 1; unsigned int i; unsigned int min_size; SUFLOAT actual_bw; SUFLOAT off; SUFLOAT corrbw; - SUBOOL full_spectrum = SU_FALSE; - SU_TRYCATCH(params->guard >= 1, goto fail); - SU_TRYCATCH(params->bw > 0, goto fail); - SU_TRYCATCH(params->f0 >= 0 && params->f0 < 2 * PI, goto fail); + SUFLOAT effective_freq; + SUBOOL full_spectrum = SU_FALSE; + + if (params->guard < 1) { + SU_ERROR( + "Guard bandwidth is smaller than channel bandwidth (guard = %g < 1)\n", + params->guard); + goto fail; + } + + if (params->bw <= 0) { + SU_ERROR("Cannot open a zero-bandwidth channel\n"); + goto fail; + } + + effective_freq = params->f0 + params->delta_f; + + if (effective_freq < 0 || effective_freq >= 2 * PI) { + SU_ERROR("Channel center frequency is outside the spectrum\n"); + goto fail; + } corrbw = params->bw; if (corrbw > 2 * PI) corrbw = 2 * PI; - SU_TRYCATCH(new = calloc(1, sizeof(su_specttuner_channel_t)), goto fail); + SU_ALLOCATE_FAIL(new, su_specttuner_channel_t); actual_bw = corrbw * params->guard; @@ -235,7 +304,6 @@ su_specttuner_channel_new( new->params = *params; new->index = -1; - if (!full_spectrum) { /* Tentative configuration */ new->k = 1. / (2 * PI / actual_bw); @@ -249,8 +317,10 @@ su_specttuner_channel_new( * * TODO: Look into this ASAP */ - new->center = 2 * SU_ROUND(params->f0 / (4 * PI) * window_size); - min_size = SU_CEIL(new->k * window_size); + + new->center = + 2 * SU_FLOOR(.5 * (effective_freq + 1 * rbw) / (2 * PI) * window_size); + min_size = SU_CEIL(new->k *window_size); /* Find the nearest power of 2 than can hold all these samples */ while (n < min_size) @@ -258,87 +328,87 @@ su_specttuner_channel_new( new->size = n; - new->width = SU_CEIL(min_size / params->guard); - new->halfw = new->width >> 1; + new->width = SU_CEIL(min_size / params->guard); + new->halfw = new->width >> 1; } else { new->k = 1. / (2 * PI / params->bw); - new->center = SU_ROUND(params->f0 / (2 * PI) * window_size); - new->size = window_size; - new->width = SU_CEIL(new->k * window_size); + new->center = + 2 * SU_FLOOR(.5 * (effective_freq + 1 * rbw) / (2 * PI) * window_size); + new->size = window_size; + new->width = SU_CEIL(new->k *window_size); if (new->width > window_size) new->width = window_size; - new->halfw = new->width >> 1; + new->halfw = new->width >> 1; } /* Adjust configuration to new size */ new->decimation = window_size / new->size; - new->k = 1. / (new->decimation * new->size); + new->k = 1. / (new->decimation *new->size); /* * High precision mode: initialize local oscillator to compensate * for rounding errors introduced by bin index calculation */ if (params->precise) { - off = new->center * (2 * PI) / (SUFLOAT) window_size - params->f0; + off = new->center *(2 * PI) / (SUFLOAT)window_size - effective_freq; off *= new->decimation; - su_ncqo_init_fixed(&new->lo, SU_ANG2NORM_FREQ(off)); + su_ncqo_init(&new->lo, SU_ANG2NORM_FREQ(off)); } new->halfsz = new->size >> 1; new->offset = new->size >> 2; - new->gain = SU_SQRT(1.f / new->size); + new->gain = 1.f; - SU_TRYCATCH(new->width > 0, goto fail); + SU_TRY_FAIL(new->width > 0); /* * Window function. We leverage fftw(f)_malloc aligned addresses * to attempt some kind of cache efficiency here. */ - SU_TRYCATCH( - new->window = SU_FFTW(_malloc)(new->size * sizeof(SUFLOAT)), - goto fail); + SU_TRY_FAIL(new->window = SU_FFTW(_malloc)(new->size * sizeof(SUFLOAT))); - SU_TRYCATCH( - new->h = SU_FFTW(_malloc)(window_size * sizeof(SU_FFTW(_complex))), - goto fail); + SU_TRY_FAIL( + new->h = SU_FFTW(_malloc)(window_size * sizeof(SU_FFTW(_complex)))); - SU_TRYCATCH(su_specttuner_init_filter_response(owner, new), goto fail); + SU_TRY_FAIL(su_specttuner_init_filter_response(owner, new)); - /* - * Squared cosine window. Seems odd, right? Well, it turns out that - * since we are storing the square of half a cycle, when we add the - * odd and even halves we are actually adding up something weighted - * by two squared cosine halves DELAYED one quarter of a cycle. - * - * This is equivalent to adding up something weighted by a squared SINE - * and a squared COSINE. And it can be proven that cos^2 + sin^2 = 1. - * - * In the end, we are favouring central IFFT values before those in - * the borders. This is something that we generally want. - * - * PS: We use SU_SIN instead of SU_COS because we are assuming that - * the 0 is at new->size/2. - */ - for (i = 0; i < new->size; ++i) { - new->window[i] = SU_SIN(PI * (SUFLOAT) i / new->size); - new->window[i] *= new->window[i]; + if (owner->params.early_windowing) { + for (i = 0; i < new->size; ++i) + new->window[i] = 1.; + } else { + /* + * Squared cosine window. Seems odd, right? Well, it turns out that + * since we are storing the square of half a cycle, when we add the + * odd and even halves we are actually adding up something weighted + * by two squared cosine halves DELAYED one quarter of a cycle. + * + * This is equivalent to adding up something weighted by a squared SINE + * and a squared COSINE. And it can be proven that cos^2 + sin^2 = 1. + * + * In the end, we are favouring central IFFT values before those in + * the borders. This is something that we generally want. + * + * PS: We use SU_SIN instead of SU_COS because we are assuming that + * the 0 is at new->size/2. + */ + for (i = 0; i < new->size; ++i) { + new->window[i] = SU_SIN(PI * (SUFLOAT)i / new->size); + new->window[i] *= new->window[i]; + } } - + /* FFT initialization */ - SU_TRYCATCH( + SU_TRY_FAIL( new->ifft[SU_SPECTTUNER_STATE_EVEN] = - SU_FFTW(_malloc)(new->size * sizeof(SU_FFTW(_complex))), - goto fail); + SU_FFTW(_malloc)(new->size * sizeof(SU_FFTW(_complex)))); - SU_TRYCATCH( + SU_TRY_FAIL( new->ifft[SU_SPECTTUNER_STATE_ODD] = - SU_FFTW(_malloc)(new->size * sizeof(SU_FFTW(_complex))), - goto fail); + SU_FFTW(_malloc)(new->size * sizeof(SU_FFTW(_complex)))); - SU_TRYCATCH( - new->fft = SU_FFTW(_malloc)(new->size * sizeof(SU_FFTW(_complex))), - goto fail); + SU_TRY_FAIL( + new->fft = SU_FFTW(_malloc)(new->size * sizeof(SU_FFTW(_complex)))); memset(new->fft, 0, new->size * sizeof(SU_FFTW(_complex))); @@ -352,167 +422,228 @@ su_specttuner_channel_new( 0, new->size * sizeof(SU_FFTW(_complex))); - SU_TRYCATCH( - new->plan[SU_SPECTTUNER_STATE_EVEN] = - SU_FFTW(_plan_dft_1d)( - new->size, - new->fft, - new->ifft[SU_SPECTTUNER_STATE_EVEN], - FFTW_BACKWARD, - FFTW_ESTIMATE), - goto fail); - - SU_TRYCATCH( - new->plan[SU_SPECTTUNER_STATE_ODD] = - SU_FFTW(_plan_dft_1d)( - new->size, - new->fft, - new->ifft[SU_SPECTTUNER_STATE_ODD], - FFTW_BACKWARD, - FFTW_ESTIMATE), - goto fail); + SU_TRY_FAIL( + new->plan[SU_SPECTTUNER_STATE_EVEN] = SU_FFTW(_plan_dft_1d)( + new->size, + new->fft, + new->ifft[SU_SPECTTUNER_STATE_EVEN], + FFTW_BACKWARD, + FFTW_MEASURE)); + + SU_TRY_FAIL( + new->plan[SU_SPECTTUNER_STATE_ODD] = SU_FFTW(_plan_dft_1d)( + new->size, + new->fft, + new->ifft[SU_SPECTTUNER_STATE_ODD], + FFTW_BACKWARD, + FFTW_MEASURE)); return new; fail: if (new != NULL) - su_specttuner_channel_destroy(new); + SU_DISPOSE(su_specttuner_channel, new); return NULL; } -void -su_specttuner_destroy(su_specttuner_t *st) +SU_COLLECTOR(su_specttuner) { unsigned int i; - for (i = 0; i < st->channel_count; ++i) - if (st->channel_list[i] != NULL) - su_specttuner_close_channel(st, st->channel_list[i]); + for (i = 0; i < self->channel_count; ++i) + if (self->channel_list[i] != NULL) + (void)su_specttuner_close_channel(self, self->channel_list[i]); + + if (self->channel_list != NULL) + free(self->channel_list); - if (st->channel_list != NULL) - free(st->channel_list); + if (self->plans[SU_SPECTTUNER_STATE_EVEN] != NULL) + SU_FFTW(_destroy_plan)(self->plans[SU_SPECTTUNER_STATE_EVEN]); - if (st->plans[SU_SPECTTUNER_STATE_EVEN] != NULL) - SU_FFTW(_destroy_plan) (st->plans[SU_SPECTTUNER_STATE_EVEN]); + if (self->plans[SU_SPECTTUNER_STATE_ODD] != NULL) + SU_FFTW(_destroy_plan)(self->plans[SU_SPECTTUNER_STATE_ODD]); - if (st->plans[SU_SPECTTUNER_STATE_ODD] != NULL) - SU_FFTW(_destroy_plan) (st->plans[SU_SPECTTUNER_STATE_ODD]); + if (self->fft != NULL) + SU_FFTW(_free)(self->fft); - if (st->fft != NULL) - SU_FFTW(_free) (st->fft); + if (self->wfunc != NULL) + free(self->wfunc); - if (st->window != NULL) - SU_FFTW(_free) (st->window); + if (self->buffer != NULL) + SU_FFTW(_free)(self->buffer); - free(st); + free(self); } -su_specttuner_t * -su_specttuner_new(const struct sigutils_specttuner_params *params) +SU_INSTANCER(su_specttuner, const struct sigutils_specttuner_params *params) { su_specttuner_t *new = NULL; + unsigned int i; SU_TRYCATCH((params->window_size & 1) == 0, goto fail); - SU_TRYCATCH(new = calloc(1, sizeof(su_specttuner_t)), goto fail); + SU_ALLOCATE_FAIL(new, su_specttuner_t); new->params = *params; new->half_size = params->window_size >> 1; new->full_size = 3 * params->window_size; - /* Window is 3/2 the FFT size */ - SU_TRYCATCH( - new->window = SU_FFTW(_malloc( - new->full_size * sizeof(SU_FFTW(_complex)))), - goto fail); + /* Early windowing enabled */ + if (params->early_windowing) { + SU_TRY_FAIL(new->wfunc = malloc(params->window_size * sizeof(SUFLOAT))); + + for (i = 0; i < params->window_size; ++i) { + new->wfunc[i] = SU_SIN(PI * (SUFLOAT) i / params->window_size); + new->wfunc[i] *= new->wfunc[i]; + } + } + + /* Buffer is 3/2 the FFT size */ + SU_TRY_FAIL( + new->buffer = + SU_FFTW(_malloc(new->full_size * sizeof(SU_FFTW(_complex))))); + memset(new->buffer, 0, new->full_size * sizeof(SU_FFTW(_complex))); /* FFT is the size provided by params */ - SU_TRYCATCH( - new->fft = SU_FFTW(_malloc( - params->window_size * sizeof(SU_FFTW(_complex)))), - goto fail); - - /* Even plan starts at the beginning of the window */ - SU_TRYCATCH( - new->plans[SU_SPECTTUNER_STATE_EVEN] = SU_FFTW(_plan_dft_1d)( - params->window_size, - new->window, - new->fft, - FFTW_FORWARD, - FFTW_ESTIMATE), - goto fail); - - /* Odd plan stars at window_size / 2 */ - SU_TRYCATCH( - new->plans[SU_SPECTTUNER_STATE_ODD] = SU_FFTW(_plan_dft_1d)( - params->window_size, - new->window + new->half_size, - new->fft, - FFTW_FORWARD, - FFTW_ESTIMATE), - goto fail); + SU_TRY_FAIL( + new->fft = + SU_FFTW(_malloc(params->window_size * sizeof(SU_FFTW(_complex))))); + + memset(new->fft, 0, params->window_size * sizeof(SU_FFTW(_complex))); + + if (new->params.early_windowing) { + SU_TRY_FAIL( + new->plans[SU_SPECTTUNER_STATE_EVEN] = SU_FFTW(_plan_dft_1d)( + params->window_size, + new->fft, + new->fft, + FFTW_FORWARD, + FFTW_MEASURE)); + + SU_TRY_FAIL( + new->plans[SU_SPECTTUNER_STATE_ODD] = SU_FFTW(_plan_dft_1d)( + params->window_size, + new->fft, + new->fft, + FFTW_FORWARD, + FFTW_MEASURE)); + } else { + /* Even plan starts at the beginning of the window */ + SU_TRY_FAIL( + new->plans[SU_SPECTTUNER_STATE_EVEN] = SU_FFTW(_plan_dft_1d)( + params->window_size, + new->buffer, + new->fft, + FFTW_FORWARD, + FFTW_MEASURE)); + + /* Odd plan stars at window_size / 2 */ + SU_TRY_FAIL( + new->plans[SU_SPECTTUNER_STATE_ODD] = SU_FFTW(_plan_dft_1d)( + params->window_size, + new->buffer + new->half_size, + new->fft, + FFTW_FORWARD, + FFTW_MEASURE)); + } return new; fail: if (new != NULL) - su_specttuner_destroy(new); + SU_DISPOSE(su_specttuner, new); return NULL; } +SU_METHOD(su_specttuner, void, run_fft) +{ + unsigned int i; + + /* Early windowing, copy windowed input */ + if (self->params.early_windowing) { + if (self->state == SU_SPECTTUNER_STATE_EVEN) { +#ifdef SU_USE_VOLK + volk_32fc_32f_multiply_32fc( + self->fft, + self->buffer, + self->wfunc, + self->params.window_size); +#else + for (i = 0; i < self->params.window_size; ++i) + self->fft[i] = self->buffer[i] * self->wfunc[i]; +#endif /* SU_USE_VOLK */ + } else { +#ifdef SU_USE_VOLK + volk_32fc_32f_multiply_32fc( + self->fft, + self->buffer + self->half_size, + self->wfunc, + self->params.window_size); +#else + for (i = 0; i < self->params.window_size; ++i) + self->fft[i] = self->buffer[i + self->half_size] * self->wfunc[i]; +#endif /* SU_USE_VOLK */ + } + } + + /* Compute FFT */ + SU_FFTW(_execute)(self->plans[self->state]); +} + SUINLINE SUSCOUNT __su_specttuner_feed_bulk( - su_specttuner_t *st, - const SUCOMPLEX *buf, + su_specttuner_t *self, + const SUCOMPLEX *__restrict buf, SUSCOUNT size) { SUSDIFF halfsz; - SUSDIFF p; - - if (size + st->p > st->params.window_size) - size = st->params.window_size - st->p; + SUSDIFF p, i; + + if (size + self->p > self->params.window_size) + size = self->params.window_size - self->p; - switch (st->state) - { + switch (self->state) { case SU_SPECTTUNER_STATE_EVEN: /* Just copy at the beginning */ - memcpy(st->window + st->p, buf, size * sizeof(SUCOMPLEX)); + memcpy(self->buffer + self->p, buf, size * sizeof(SUCOMPLEX)); break; case SU_SPECTTUNER_STATE_ODD: /* Copy to the second third */ - memcpy(st->window + st->p + st->half_size, buf, size * sizeof(SUCOMPLEX)); + memcpy( + self->buffer + self->p + self->half_size, + buf, + size * sizeof(SUCOMPLEX)); /* Did this copy populate the last third? */ - if (st->p + size > st->half_size) { - halfsz = st->p + size - st->half_size; - p = st->p > st->half_size ? st->p : st->half_size; + if (self->p + size > self->half_size) { + halfsz = self->p + size - self->half_size; + p = self->p > self->half_size ? self->p : self->half_size; /* Don't take into account data already written */ - halfsz -= p - st->half_size; + halfsz -= p - self->half_size; /* Copy to the first third */ if (halfsz > 0) memcpy( - st->window + p - st->half_size, - st->window + p + st->half_size, + self->buffer + p - self->half_size, + self->buffer + p + self->half_size, halfsz * sizeof(SUCOMPLEX)); } } - st->p += size; + self->p += size; - if (st->p == st->params.window_size) { - st->p = st->half_size; + if (self->p == self->params.window_size) { + self->p = self->half_size; - /* Compute FFT */ - SU_FFTW(_execute) (st->plans[st->state]); + su_specttuner_run_fft(self); /* Toggle state */ - st->state = !st->state; - st->ready = SU_TRUE; + self->state = !self->state; + self->ready = SU_TRUE; } return size; @@ -520,18 +651,42 @@ __su_specttuner_feed_bulk( SUINLINE SUBOOL __su_specttuner_feed_channel( - const su_specttuner_t *st, + const su_specttuner_t *self, su_specttuner_channel_t *channel) { int p; int len; - int window_size = st->params.window_size; + int window_size = self->params.window_size; unsigned int i; - SUCOMPLEX phase; + SUCOMPLEX phase, phold; SUFLOAT alpha, beta; + SUBOOL changing_freqs = SU_FALSE; + int a_sign, b_sign; SUCOMPLEX *prev, *curr; + /* + * This is how the phase continuity trick works: as soon as a new + * center frequency is signaled, we make a copy of the current + * LO state. Next, during overlapping, the previous buffer is + * adjusted by the old LO, while the most recent buffer is + * adjusted by the new LO. Also, phase continuity between bins is + * ensured, as all bins refer to frequencies multiple of 2pi. + */ + + b_sign = 1 - (channel->center & 2); + + if (!channel->state && channel->pending_freq) { + channel->pending_freq = SU_FALSE; + + su_ncqo_copy(&channel->old_lo, &channel->lo); + + su_specttuner_refresh_channel_center(self, channel); + + changing_freqs = SU_TRUE; + } + p = channel->center; + a_sign = 1 - (channel->center & 2); /***************************** Upper sideband ******************************/ len = channel->halfw; @@ -539,38 +694,34 @@ __su_specttuner_feed_channel( len = window_size - p; /* Copy to the end */ - memcpy( - channel->fft, - st->fft + p, - len * sizeof(SUCOMPLEX)); + memcpy(channel->fft, self->fft + p, len * sizeof(SUCOMPLEX)); /* Copy remaining part */ if (len < channel->halfw) memcpy( channel->fft + len, - st->fft, + self->fft, (channel->halfw - len) * sizeof(SUCOMPLEX)); /***************************** Lower sideband ******************************/ len = channel->halfw; if (p < len) /* Roll over */ - len = p; /* Can copy up to p bytes */ - + len = p; /* Can copy up to p bytes */ /* Copy higher frequencies */ memcpy( channel->fft + channel->size - len, - st->fft + p - len, + self->fft + p - len, len * sizeof(SUCOMPLEX)); /* Copy remaining part */ if (len < channel->halfw) memcpy( channel->fft + channel->size - channel->halfw, - st->fft + window_size - (channel->halfw - len), + self->fft + window_size - (channel->halfw - len), (channel->halfw - len) * sizeof(SUCOMPLEX)); - /*********************** Apply filter and scaling **************************/ + /*********************** Apply filter and scaling ************************/ #ifdef SU_SPECTTUNER_SQUARE_FILTER for (i = 0; i < channel->halfw; ++i) channel->fft[i] *= channel->k; @@ -585,78 +736,134 @@ __su_specttuner_feed_channel( } #endif /************************* Back to time domain******************************/ - SU_FFTW(_execute) (channel->plan[channel->state]); + SU_FFTW(_execute)(channel->plan[channel->state]); curr = channel->ifft[channel->state]; prev = channel->ifft[!channel->state] + channel->halfsz; /* Glue buffers */ if (channel->params.precise) { - for (i = 0; i < channel->halfsz; ++i) { - alpha = channel->window[i]; /* Positive slope */ - beta = channel->window[i + channel->halfsz]; /* Negative slope */ - - phase = su_ncqo_read(&channel->lo); - - curr[i] = channel->gain * phase * (alpha * curr[i] + beta * prev[i]); + if (changing_freqs) { + /* Do this only when switching frequencies */ + if (self->params.early_windowing) { + /* Windowing already applied, no need to apply it here */ + for (i = 0; i < channel->halfsz; ++i) { + phold = su_ncqo_read(&channel->old_lo); + phase = su_ncqo_read(&channel->lo); + curr[i] = + channel->gain * (phase * curr[i] + phold * prev[i]); + } + } else { + /* Late windowing, need to apply it here */ + for (i = 0; i < channel->halfsz; ++i) { + alpha = channel->window[i]; + beta = channel->window[i + channel->halfsz]; + + phold = su_ncqo_read(&channel->old_lo); + phase = su_ncqo_read(&channel->lo); + curr[i] = + channel->gain * (phase * alpha * curr[i] + phold * beta * prev[i]); + } + } + } else { + if (self->params.early_windowing) { + /* Early windowing, speed things up */ + for (i = 0; i < channel->halfsz; ++i) { + phase = su_ncqo_read(&channel->lo); + curr[i] = channel->gain * phase * (curr[i] + prev[i]); + } + } else { + /* Late windowing, need to apply it here */ + for (i = 0; i < channel->halfsz; ++i) { + alpha = channel->window[i]; /* Positive slope */ + beta = channel->window[i + channel->halfsz]; /* Negative slope */ + + phase = su_ncqo_read(&channel->lo); + curr[i] = channel->gain * phase * (alpha * curr[i] + beta * prev[i]); + } + } } } else { - for (i = 0; i < channel->halfsz; ++i) { - alpha = channel->window[i]; /* Positive slope */ - beta = channel->window[i + channel->halfsz]; /* Negative slope */ - - curr[i] = channel->gain * (alpha * curr[i] + beta * prev[i]); + if (self->params.early_windowing) { + /* Early windowing */ + for (i = 0; i < channel->halfsz; ++i) + curr[i] = channel->gain * (a_sign * curr[i] + b_sign * prev[i]); + } else { + /* Late windowing */ + for (i = 0; i < channel->halfsz; ++i) { + alpha = a_sign * channel->window[i]; /* Positive slope */ + beta = b_sign * channel->window[i + channel->halfsz]; /* Negative slope */ + + curr[i] = channel->gain * (alpha * curr[i] + beta * prev[i]); + } } } channel->state = !channel->state; /************************** Call user callback *****************************/ - return (channel->params.on_data) ( + return (channel->params.on_data)( channel, channel->params.privdata, curr, channel->halfsz); } -SUSDIFF -su_specttuner_feed_bulk_single( - su_specttuner_t *st, - const SUCOMPLEX *buf, +SU_METHOD(su_specttuner, SUBOOL, feed_all_channels) +{ + unsigned int i; + SUBOOL ok = SU_TRUE; + + if (su_specttuner_new_data(self)) { + for (i = 0; i < self->channel_count; ++i) + if (self->channel_list[i] != NULL) + ok = __su_specttuner_feed_channel(self, self->channel_list[i]) && ok; + su_specttuner_ack_data(self); + } + + return ok; +} + +SU_METHOD( + su_specttuner, + SUSDIFF, + feed_bulk_single, + const SUCOMPLEX *__restrict buf, SUSCOUNT size) { SUSDIFF got; SUSCOUNT ok = SU_TRUE; unsigned int i; - if (st->ready) + if (self->ready) return 0; - got = __su_specttuner_feed_bulk(st, buf, size); + got = __su_specttuner_feed_bulk(self, buf, size); /* Buffer full, feed channels */ - if (st->ready) - for (i = 0; i < st->channel_count; ++i) - if (st->channel_list[i] != NULL) - ok = __su_specttuner_feed_channel(st, st->channel_list[i]) && ok; + if (self->ready) + for (i = 0; i < self->channel_count; ++i) + if (self->channel_list[i] != NULL) + ok = __su_specttuner_feed_channel(self, self->channel_list[i]) && ok; return ok ? got : -1; } -SUBOOL -su_specttuner_feed_bulk( - su_specttuner_t *st, - const SUCOMPLEX *buf, +SU_METHOD( + su_specttuner, + SUBOOL, + feed_bulk, + const SUCOMPLEX *__restrict buf, SUSCOUNT size) { SUSDIFF got; SUBOOL ok = SU_TRUE; while (size > 0) { - got = su_specttuner_feed_bulk_single(st, buf, size); + got = su_specttuner_feed_bulk_single(self, buf, size); - if (su_specttuner_new_data(st)) - su_specttuner_ack_data(st); + if (su_specttuner_new_data(self)) + su_specttuner_ack_data(self); if (got == -1) ok = SU_FALSE; @@ -668,23 +875,22 @@ su_specttuner_feed_bulk( return ok; } -su_specttuner_channel_t * -su_specttuner_open_channel( - su_specttuner_t *st, +SU_METHOD( + su_specttuner, + su_specttuner_channel_t *, + open_channel, const struct sigutils_specttuner_channel_params *params) { su_specttuner_channel_t *new = NULL; int index; - SU_TRYCATCH(new = su_specttuner_channel_new(st, params), goto fail); + SU_MAKE_FAIL(new, su_specttuner_channel, self, params); - SU_TRYCATCH( - (index = PTR_LIST_APPEND_CHECK(st->channel, new)) != -1, - goto fail); + SU_TRYC_FAIL(index = PTR_LIST_APPEND_CHECK(self->channel, new)); new->index = index; - ++st->count; + ++self->count; return new; @@ -695,22 +901,23 @@ su_specttuner_open_channel( return NULL; } -SUBOOL -su_specttuner_close_channel( - su_specttuner_t *st, +SU_METHOD( + su_specttuner, + SUBOOL, + close_channel, su_specttuner_channel_t *channel) { SU_TRYCATCH(channel->index >= 0, return SU_FALSE); - SU_TRYCATCH(channel->index < st->channel_count, return SU_FALSE); + SU_TRYCATCH(channel->index < self->channel_count, return SU_FALSE); - SU_TRYCATCH(st->channel_list[channel->index] == channel, return SU_FALSE); + SU_TRYCATCH(self->channel_list[channel->index] == channel, return SU_FALSE); - st->channel_list[channel->index] = NULL; + self->channel_list[channel->index] = NULL; su_specttuner_channel_destroy(channel); - --st->count; + --self->count; return SU_TRUE; } diff --git a/sigutils/specttuner.h b/sigutils/specttuner.h index 33f29e1..725fca3 100644 --- a/sigutils/specttuner.h +++ b/sigutils/specttuner.h @@ -20,17 +20,28 @@ #ifndef _SIGUTILS_SPECTTUNER_H #define _SIGUTILS_SPECTTUNER_H -#include "types.h" +#include "defs.h" #include "ncqo.h" +#include "types.h" + +#ifdef __cplusplus +# ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +# endif // __clang__ +extern "C" { +#endif /* __cplusplus */ struct sigutils_specttuner_params { SUSCOUNT window_size; + SUBOOL early_windowing; }; -#define sigutils_specttuner_params_INITIALIZER \ -{ \ - 4096, /* window_size */ \ -} +#define sigutils_specttuner_params_INITIALIZER \ + { \ + 4096, /* window_size */ \ + SU_TRUE, /* early_windowing */ \ + } enum sigutils_specttuner_state { SU_SPECTTUNER_STATE_EVEN, @@ -40,36 +51,41 @@ enum sigutils_specttuner_state { struct sigutils_specttuner_channel; struct sigutils_specttuner_channel_params { - SUFLOAT f0; /* Central frequency (angular frequency) */ - SUFLOAT bw; /* Bandwidth (angular frequency) */ - SUFLOAT guard; /* Relative extra bandwidth */ - SUBOOL precise; /* Precision mode */ - void *privdata; /* Private data */ - SUBOOL (*on_data) ( - const struct sigutils_specttuner_channel *channel, - void *privdata, - const SUCOMPLEX *data, /* This pointer remains valid until the next call to feed */ - SUSCOUNT size); + SUFLOAT f0; /* Central frequency (angular frequency) */ + SUFLOAT delta_f; /* Frequency correction (angular frequency) */ + SUFLOAT bw; /* Bandwidth (angular frequency) */ + SUFLOAT guard; /* Relative extra bandwidth */ + SUBOOL precise; /* Precision mode */ + void *privdata; /* Private data */ + SUBOOL(*on_data) + (const struct sigutils_specttuner_channel *channel, + void *privdata, + const SUCOMPLEX + *data, /* This pointer remains valid until the next call to feed */ + SUSCOUNT size); }; -#define sigutils_specttuner_channel_params_INITIALIZER \ -{ \ - 0, /* f0 */ \ - 0, /* bw */ \ - 1, /* guard */ \ - SU_FALSE, /* precise */ \ - NULL, /* private */ \ - NULL, /* on_data */ \ -} +#define sigutils_specttuner_channel_params_INITIALIZER \ + { \ + 0, /* f0 */ \ + 0, /* delta_f */ \ + 0, /* bw */ \ + 1, /* guard */ \ + SU_FALSE, /* precise */ \ + NULL, /* private */ \ + NULL, /* on_data */ \ + } struct sigutils_specttuner_channel { struct sigutils_specttuner_channel_params params; - int index; /* Back reference */ + int index; /* Back reference */ SUFLOAT k; /* Scaling factor */ SUFLOAT gain; /* Channel gain */ SUFLOAT decimation; /* Equivalent decimation */ - su_ncqo_t lo; /* Local oscilator to correct imprecise centering */ + su_ncqo_t lo; /* Local oscillator to correct imprecise centering */ + su_ncqo_t old_lo; /* Copy of the old local oscillator */ + SUBOOL pending_freq; /* Pending frequency adjustment */ unsigned int center; /* FFT center bin */ unsigned int size; /* FFT bins to allocate */ unsigned int width; /* FFT bins to copy (for guard bands, etc) */ @@ -82,35 +98,52 @@ struct sigutils_specttuner_channel { * a good windowing that does not rely on rectangular windows */ enum sigutils_specttuner_state state; - SU_FFTW(_complex) *fft; /* Filtered spectrum */ - SU_FFTW(_complex) *h; /* Frequency response of filter */ - SU_FFTW(_plan) plan[2]; /* Even & Odd plans */ - SU_FFTW(_plan) forward; /* Filter response forward plan */ - SU_FFTW(_plan) backward; /* Filter response backward plan */ - - SU_FFTW(_complex) *ifft[2]; /* Even & Odd time-domain signal */ - SUFLOAT *window; /* Window function */ + SU_FFTW(_complex) * fft; /* Filtered spectrum */ + SU_FFTW(_complex) * h; /* Frequency response of filter */ + SU_FFTW(_plan) plan[2]; /* Even & Odd plans */ + SU_FFTW(_plan) forward; /* Filter response forward plan */ + SU_FFTW(_plan) backward; /* Filter response backward plan */ + + SU_FFTW(_complex) * ifft[2]; /* Even & Odd time-domain signal */ + SUFLOAT *window; /* Window function */ }; typedef struct sigutils_specttuner_channel su_specttuner_channel_t; -SUINLINE SUFLOAT -su_specttuner_channel_get_decimation(const su_specttuner_channel_t *channel) +SUINLINE +SU_GETTER(su_specttuner_channel, SUFLOAT, get_decimation) +{ + return self->decimation; +} + +SUINLINE +SU_GETTER(su_specttuner_channel, SUFLOAT, get_bw) +{ + return 2 * PI * (SUFLOAT)self->width + / (SUFLOAT)(self->size * self->decimation); +} + +SUINLINE +SU_GETTER(su_specttuner_channel, SUFLOAT, get_f0) { - return channel->decimation; + return self->params.f0; } -SUINLINE SUFLOAT -su_specttuner_channel_get_bw(const su_specttuner_channel_t *channel) +SUINLINE +SU_GETTER(su_specttuner_channel, SUFLOAT, get_delta_f) { - return 2 * PI * (SUFLOAT) channel->width - / (SUFLOAT) (channel->size * channel->decimation); + return self->params.delta_f; } -SUINLINE SUFLOAT -su_specttuner_channel_get_f0(const su_specttuner_channel_t *channel) +SUINLINE +SU_GETTER(su_specttuner_channel, SUFLOAT, get_effective_freq) { - return channel->params.f0; + SUFLOAT ef = SU_FMOD(self->params.f0 + self->params.delta_f, 2 * M_PI); + + if (ef < 0) + ef += 2 * PI; + + return ef; } /* @@ -141,15 +174,16 @@ su_specttuner_channel_get_f0(const su_specttuner_channel_t *channel) struct sigutils_specttuner { struct sigutils_specttuner_params params; - SU_FFTW(_complex) *window; /* 3/2 the space, double allocation trick */ - SU_FFTW(_complex) *fft; + SUFLOAT * wfunc; /* Window function */ + SU_FFTW(_complex) * buffer; /* 3/2 the space, double allocation trick */ + SU_FFTW(_complex) * fft; enum sigutils_specttuner_state state; SU_FFTW(_plan) plans[2]; /* Even and odd plans */ unsigned int half_size; /* 3/2 of window size */ unsigned int full_size; /* 3/2 of window size */ - unsigned int p; /* From 0 to window_size - 1 */ + unsigned int p; /* From 0 to window_size - 1 */ unsigned int count; /* Active channels */ @@ -161,55 +195,125 @@ struct sigutils_specttuner { typedef struct sigutils_specttuner su_specttuner_t; -SUINLINE unsigned int -su_specttuner_get_channel_count(const su_specttuner_t *st) +SUINLINE +SU_GETTER(su_specttuner, unsigned int, get_channel_count) { - return st->count; + return self->count; } -SUINLINE SUBOOL -su_specttuner_new_data(const su_specttuner_t *st) +SUINLINE +SU_GETTER(su_specttuner, SUBOOL, new_data) { - return st->ready; + return self->ready; } -SUINLINE void -su_specttuner_ack_data(su_specttuner_t *st) +SUINLINE +SU_METHOD(su_specttuner, void, ack_data) { - st->ready = SU_FALSE; + self->ready = SU_FALSE; } -void su_specttuner_destroy(su_specttuner_t *st); +#ifndef __cplusplus + +/* Internal */ +SU_METHOD(su_specttuner, SUBOOL, feed_all_channels); + +/* Internal */ +SU_METHOD(su_specttuner, void, run_fft); + +SUINLINE +SU_METHOD(su_specttuner, SUBOOL, feed_sample, SUCOMPLEX x) +{ + SUSDIFF halfsz = self->half_size; + SUSDIFF p = self->p; + + switch (self->state) { + case SU_SPECTTUNER_STATE_EVEN: + /* Just copy at the beginning */ + self->buffer[p] = x; + break; + + case SU_SPECTTUNER_STATE_ODD: + /* Copy to the second third */ + self->buffer[p + halfsz] = x; + + /* Are we populating the last third too? */ + if (p >= halfsz) + self->buffer[p - halfsz] = x; + } + + if (++p < self->params.window_size) { + self->p = p; + } else { + self->p = halfsz; + + /* Compute FFT */ + su_specttuner_run_fft(self); + + /* Toggle state */ + self->state = !self->state; + self->ready = SU_TRUE; + } + + return self->ready; +} +#endif /* __cplusplus */ -su_specttuner_t *su_specttuner_new( - const struct sigutils_specttuner_params *params); +SU_INSTANCER(su_specttuner, const struct sigutils_specttuner_params *params); +SU_COLLECTOR(su_specttuner); -SUSDIFF su_specttuner_feed_bulk_single( - su_specttuner_t *st, - const SUCOMPLEX *buf, +SU_METHOD( + su_specttuner, + SUSDIFF, + feed_bulk_single, + const SUCOMPLEX *__restrict buf, SUSCOUNT size); -SUBOOL su_specttuner_feed_bulk( - su_specttuner_t *st, - const SUCOMPLEX *buf, +SU_METHOD( + su_specttuner, + SUBOOL, + feed_bulk, + const SUCOMPLEX *__restrict buf, SUSCOUNT size); -su_specttuner_channel_t *su_specttuner_open_channel( - su_specttuner_t *st, +SU_METHOD( + su_specttuner, + su_specttuner_channel_t *, + open_channel, const struct sigutils_specttuner_channel_params *params); -void su_specttuner_set_channel_freq( - const su_specttuner_t *st, +SU_METHOD( + su_specttuner, + SUBOOL, + close_channel, + su_specttuner_channel_t *channel); + +SU_METHOD_CONST( + su_specttuner, + void, + set_channel_freq, su_specttuner_channel_t *channel, SUFLOAT f0); -SUBOOL su_specttuner_set_channel_bandwidth( - const su_specttuner_t *st, +SU_METHOD_CONST( + su_specttuner, + void, + set_channel_delta_f, + su_specttuner_channel_t *channel, + SUFLOAT delta_f); + +SU_METHOD_CONST( + su_specttuner, + SUBOOL, + set_channel_bandwidth, su_specttuner_channel_t *channel, SUFLOAT bw); -SUBOOL su_specttuner_close_channel( - su_specttuner_t *st, - su_specttuner_channel_t *channel); +#ifdef __cplusplus +# ifdef __clang__ +# pragma clang diagnostic pop +# endif // __clang__ +} +#endif /* __cplusplus */ #endif /* _SIGUTILS_SPECTTUNER_H */ diff --git a/sigutils/taps.c b/sigutils/taps.c index 588da12..743b6f9 100644 --- a/sigutils/taps.c +++ b/sigutils/taps.c @@ -17,9 +17,10 @@ */ -#include "types.h" #include "taps.h" + #include "sampling.h" +#include "types.h" /************************* Real window functions *****************************/ SUPRIVATE void @@ -47,8 +48,7 @@ su_taps_apply_hann(SUFLOAT *h, SUSCOUNT size) unsigned int i; for (i = 0; i < size; ++i) - h[i] *= - SU_HANN_ALPHA - SU_HANN_BETA * SU_COS(2 * M_PI * i / (size - 1)); + h[i] *= SU_HANN_ALPHA - SU_HANN_BETA * SU_COS(2 * M_PI * i / (size - 1)); } void @@ -57,12 +57,10 @@ su_taps_apply_flat_top(SUFLOAT *h, SUSCOUNT size) unsigned int i; for (i = 0; i < size; ++i) - h[i] *= - SU_FLAT_TOP_A0 - - SU_FLAT_TOP_A1 * SU_COS(2 * M_PI * i / (size - 1)) - + SU_FLAT_TOP_A2 * SU_COS(4 * M_PI * i / (size - 1)) - - SU_FLAT_TOP_A3 * SU_COS(6 * M_PI * i / (size - 1)) - + SU_FLAT_TOP_A1 * SU_COS(8 * M_PI * i / (size - 1)); + h[i] *= SU_FLAT_TOP_A0 - SU_FLAT_TOP_A1 * SU_COS(2 * M_PI * i / (size - 1)) + + SU_FLAT_TOP_A2 * SU_COS(4 * M_PI * i / (size - 1)) + - SU_FLAT_TOP_A3 * SU_COS(6 * M_PI * i / (size - 1)) + + SU_FLAT_TOP_A1 * SU_COS(8 * M_PI * i / (size - 1)); } void @@ -71,14 +69,12 @@ su_taps_apply_blackmann_harris(SUFLOAT *h, SUSCOUNT size) unsigned int i; for (i = 0; i < size; ++i) - h[i] *= - SU_BLACKMANN_HARRIS_A0 - - SU_BLACKMANN_HARRIS_A1 * SU_COS(2 * M_PI * i / (size - 1)) - + SU_BLACKMANN_HARRIS_A2 * SU_COS(4 * M_PI * i / (size - 1)) - - SU_BLACKMANN_HARRIS_A3 * SU_COS(6 * M_PI * i / (size - 1)); + h[i] *= SU_BLACKMANN_HARRIS_A0 + - SU_BLACKMANN_HARRIS_A1 * SU_COS(2 * M_PI * i / (size - 1)) + + SU_BLACKMANN_HARRIS_A2 * SU_COS(4 * M_PI * i / (size - 1)) + - SU_BLACKMANN_HARRIS_A3 * SU_COS(6 * M_PI * i / (size - 1)); } - /********************** Complex window functions ****************************/ void su_taps_apply_hamming_complex(SUCOMPLEX *h, SUSCOUNT size) @@ -105,12 +101,10 @@ su_taps_apply_flat_top_complex(SUCOMPLEX *h, SUSCOUNT size) unsigned int i; for (i = 0; i < size; ++i) - h[i] *= - SU_FLAT_TOP_A0 - - SU_FLAT_TOP_A1 * SU_COS(2 * M_PI * i / (size - 1)) - + SU_FLAT_TOP_A2 * SU_COS(4 * M_PI * i / (size - 1)) - - SU_FLAT_TOP_A3 * SU_COS(6 * M_PI * i / (size - 1)) - + SU_FLAT_TOP_A1 * SU_COS(8 * M_PI * i / (size - 1)); + h[i] *= SU_FLAT_TOP_A0 - SU_FLAT_TOP_A1 * SU_COS(2 * M_PI * i / (size - 1)) + + SU_FLAT_TOP_A2 * SU_COS(4 * M_PI * i / (size - 1)) + - SU_FLAT_TOP_A3 * SU_COS(6 * M_PI * i / (size - 1)) + + SU_FLAT_TOP_A1 * SU_COS(8 * M_PI * i / (size - 1)); } void @@ -119,11 +113,10 @@ su_taps_apply_blackmann_harris_complex(SUCOMPLEX *h, SUSCOUNT size) unsigned int i; for (i = 0; i < size; ++i) - h[i] *= - SU_BLACKMANN_HARRIS_A0 - - SU_BLACKMANN_HARRIS_A1 * SU_COS(2 * M_PI * i / (size - 1)) - + SU_BLACKMANN_HARRIS_A2 * SU_COS(4 * M_PI * i / (size - 1)) - - SU_BLACKMANN_HARRIS_A3 * SU_COS(6 * M_PI * i / (size - 1)); + h[i] *= SU_BLACKMANN_HARRIS_A0 + - SU_BLACKMANN_HARRIS_A1 * SU_COS(2 * M_PI * i / (size - 1)) + + SU_BLACKMANN_HARRIS_A2 * SU_COS(4 * M_PI * i / (size - 1)) + - SU_BLACKMANN_HARRIS_A3 * SU_COS(6 * M_PI * i / (size - 1)); } void @@ -187,21 +180,20 @@ su_taps_rrc_init(SUFLOAT *h, SUFLOAT T, SUFLOAT beta, SUSCOUNT size) SUFLOAT dem; SUFLOAT num; SUFLOAT f; - SUFLOAT norm = 0; for (i = 0; i < size; ++i) { r_t = (i - size / 2.) / T; f = 4 * beta * r_t; dem = M_PI * r_t * (1. - f * f); - num = SU_SIN(M_PI * r_t * (1 - beta)) + - 4 * beta * r_t * SU_COS(M_PI * r_t * (1 + beta)); + num = SU_SIN(M_PI * r_t * (1 - beta)) + + 4 * beta * r_t * SU_COS(M_PI * r_t * (1 + beta)); if (SU_ABS(r_t) < SUFLOAT_THRESHOLD) h[i] = 1. - beta + 4. * beta / M_PI; else if (SU_ABS(dem) < SUFLOAT_THRESHOLD) - h[i] = beta / SU_SQRT(2) * ( - (1 + 2 / M_PI) * sin(M_PI / (4 * beta)) + - (1 - 2 / M_PI) * cos(M_PI / (4 * beta))); + h[i] = beta / SU_SQRT(2) + * ((1 + 2 / M_PI) * sin(M_PI / (4 * beta)) + + (1 - 2 / M_PI) * cos(M_PI / (4 * beta))); else h[i] = num / dem; @@ -218,7 +210,7 @@ su_taps_brickwall_lp_init(SUFLOAT *h, SUFLOAT fc, SUSCOUNT size) SUFLOAT t = 0; for (i = 0; i < size; ++i) { - t = i - size / 2.; + t = i - (size >> 1); h[i] = fc * su_sinc(fc * t); } @@ -247,7 +239,6 @@ su_taps_brickwall_bp_init(SUFLOAT *h, SUFLOAT bw, SUFLOAT if_nor, SUSCOUNT size) if (if_nor <= .5 * bw) { su_taps_brickwall_lp_init(h, if_nor + .5 * bw, size); } else { - for (i = 0; i < size; ++i) { t = i - .5 * size; h[i] = bw * su_sinc(.5 * bw * t) * SU_COS(omega * t); @@ -256,4 +247,3 @@ su_taps_brickwall_bp_init(SUFLOAT *h, SUFLOAT bw, SUFLOAT if_nor, SUSCOUNT size) su_taps_apply_hamming(h, size); } } - diff --git a/sigutils/taps.h b/sigutils/taps.h index 7aa0977..f248b2d 100644 --- a/sigutils/taps.h +++ b/sigutils/taps.h @@ -20,10 +20,12 @@ #ifndef _SIGUTILS_TAPS_H #define _SIGUTILS_TAPS_H +#include "types.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - + #define SU_HAMMING_ALPHA 0.54 #define SU_MAMMING_BETA (1 - SU_HAMMING_ALPHA) @@ -41,7 +43,6 @@ extern "C" { #define SU_BLACKMANN_HARRIS_A2 0.14128 #define SU_BLACKMANN_HARRIS_A3 0.01168 - /* Window functions */ void su_taps_apply_hamming(SUFLOAT *h, SUSCOUNT size); void su_taps_apply_hann(SUFLOAT *h, SUSCOUNT size); @@ -63,7 +64,11 @@ void su_taps_rrc_init(SUFLOAT *h, SUFLOAT T, SUFLOAT beta, SUSCOUNT size); void su_taps_brickwall_lp_init(SUFLOAT *h, SUFLOAT fc, SUSCOUNT size); -void su_taps_brickwall_bp_init(SUFLOAT *h, SUFLOAT bw, SUFLOAT if_nor, SUSCOUNT size); +void su_taps_brickwall_bp_init( + SUFLOAT *h, + SUFLOAT bw, + SUFLOAT if_nor, + SUSCOUNT size); #ifdef __cplusplus } diff --git a/sigutils/tvproc.c b/sigutils/tvproc.c index 7c7c075..d7efbca 100644 --- a/sigutils/tvproc.c +++ b/sigutils/tvproc.c @@ -19,14 +19,16 @@ #define SU_LOG_DOMAIN "tvproc" -#include "log.h" #include "tvproc.h" -#include "sampling.h" + #include +#include "log.h" +#include "sampling.h" + /***************************** Pulse finder ***********************************/ -su_pulse_finder_t * -su_pulse_finder_new( +SU_INSTANCER( + su_pulse_finder, SUFLOAT base, SUFLOAT peak, SUSCOUNT len, @@ -37,33 +39,32 @@ su_pulse_finder_new( unsigned int i; SUBOOL ok = SU_FALSE; - SU_TRYCATCH(new = calloc(1, sizeof(su_pulse_finder_t)), goto fail); - SU_TRYCATCH(coef = malloc(sizeof(SUFLOAT) * len), goto fail); + SU_ALLOCATE_FAIL(new, su_pulse_finder_t); + SU_ALLOCATE_MANY_FAIL(coef, len, SUFLOAT); for (i = 0; i < len; ++i) coef[i] = peak - base; - SU_TRYCATCH( - su_iir_filt_init( - &new->corr, - 0, /* y_size */ - NULL, /* y_coef */ - len, /* x_size */ - coef /* x_coef */), - goto fail); + SU_CONSTRUCT_FAIL( + su_iir_filt, + &new->corr, + 0, /* y_size */ + NULL, /* y_coef */ + len, /* x_size */ + coef /* x_coef */); - new->base = base; - new->peak_thr = (peak - base) * (peak - base) * len * (1 - tolerance); - new->length = len; + new->base = base; + new->peak_thr = (peak - base) * (peak - base) * len *(1 - tolerance); + new->length = len; - new->time_tolerance = len * (1 - tolerance); + new->time_tolerance = len *(1 - tolerance); return new; fail: if (!ok) { if (new != NULL) - su_pulse_finder_destroy(new); + SU_DISPOSE(su_pulse_finder, new); new = NULL; } @@ -73,8 +74,7 @@ su_pulse_finder_new( return new; } -SUBOOL -su_pulse_finder_feed(su_pulse_finder_t *self, SUFLOAT x) +SU_METHOD(su_pulse_finder, SUBOOL, feed, SUFLOAT x) { SUFLOAT y; SUBOOL match; @@ -84,7 +84,6 @@ su_pulse_finder_feed(su_pulse_finder_t *self, SUFLOAT x) y = SU_C_REAL(su_iir_filt_feed(&self->corr, x)); - match = y > self->peak_thr; self->last_y = y; @@ -92,11 +91,11 @@ su_pulse_finder_feed(su_pulse_finder_t *self, SUFLOAT x) if (self->present) { if (!match) { if (self->duration <= self->time_tolerance) { - self->rel_pos = - self->accum / self->w_accum + (SUFLOAT) self->length; + self->rel_pos = -self->accum / self->w_accum + (SUFLOAT)self->length; found = SU_TRUE; } } else { - self->accum += y * self->duration++; + self->accum += y * self->duration++; self->w_accum += y; } } else if (match) { @@ -110,16 +109,14 @@ su_pulse_finder_feed(su_pulse_finder_t *self, SUFLOAT x) return found; } -SUFLOAT -su_pulse_finder_get_pos(const su_pulse_finder_t *self) +SU_GETTER(su_pulse_finder, SUFLOAT, get_pos) { return self->rel_pos; } -void -su_pulse_finder_destroy(su_pulse_finder_t *self) +SU_COLLECTOR(su_pulse_finder) { - su_iir_filt_finalize(&self->corr); + SU_DESTRUCT(su_iir_filt, &self->corr); free(self); } @@ -130,36 +127,38 @@ su_tv_processor_params_ntsc( struct sigutils_tv_processor_params *self, SUFLOAT samp_rate) { - self->enable_sync = SU_TRUE; - self->reverse = SU_FALSE; - self->interlace = SU_TRUE; - self->enable_agc = SU_TRUE; - self->x_off = 0; - self->dominance = SU_TRUE; - self->frame_lines = 525; + self->enable_sync = SU_TRUE; + self->reverse = SU_FALSE; + self->interlace = SU_TRUE; + self->enable_agc = SU_TRUE; + self->x_off = 0; + self->dominance = SU_TRUE; + self->frame_lines = 525; - self->enable_comb = SU_TRUE; - self->comb_reverse = SU_FALSE; + self->enable_comb = SU_TRUE; + self->comb_reverse = SU_FALSE; - self->hsync_len = SU_T2N_FLOAT(samp_rate, 4.749e-6); - self->vsync_len = SU_T2N_FLOAT(samp_rate, 2.375e-6); - self->line_len = SU_T2N_FLOAT(samp_rate, 63.556e-6); - self->vsync_odd_trigger = 6; /* VSYNC counter to trigger vertical sync */ + self->hsync_len = SU_T2N_FLOAT(samp_rate, 4.749e-6); + self->vsync_len = SU_T2N_FLOAT(samp_rate, 2.375e-6); + self->line_len = SU_T2N_FLOAT(samp_rate, 63.556e-6); + self->vsync_odd_trigger = 6; /* VSYNC counter to trigger vertical sync */ - self->t_tol = 1e-1; /* Timing error tolerance */ - self->l_tol = 1e-1; /* Level error tolerance */ - self->g_tol = 1e-1; /* Geometry adjustment tolerance */ + self->t_tol = 1e-1; /* Timing error tolerance */ + self->l_tol = 1e-1; /* Level error tolerance */ + self->g_tol = 1e-1; /* Geometry adjustment tolerance */ - self->hsync_huge_err = .25; - self->hsync_max_err = 1e-2; /* Maximum time error for hsync */ - self->hsync_min_err = .5e-2; /* Minimum time error for hsync */ + self->hsync_huge_err = .25; + self->hsync_max_err = 1e-2; /* Maximum time error for hsync */ + self->hsync_min_err = .5e-2; /* Minimum time error for hsync */ - self->hsync_len_tau = 9.5; /* Time constant for hsync length adjust */ - self->line_len_tau = 1e3; /* Time constant for line length estimation */ - self->agc_tau = 1e-5; /* Time constant for AGC adjustment (frames) */ + self->hsync_len_tau = 9.5; /* Time constant for hsync length adjust */ + self->line_len_tau = 1e3; /* Time constant for line length estimation */ + self->agc_tau = 1e-5; /* Time constant for AGC adjustment (frames) */ - self->hsync_fast_track_tau = 9.5; /* Time constant for horizontal adjustment */ - self->hsync_slow_track_tau = 1e3; /* Time constant for horizontal adjustment */ + self->hsync_fast_track_tau = + 9.5; /* Time constant for horizontal adjustment */ + self->hsync_slow_track_tau = + 1e3; /* Time constant for horizontal adjustment */ } void @@ -167,95 +166,85 @@ su_tv_processor_params_pal( struct sigutils_tv_processor_params *self, SUFLOAT samp_rate) { - self->enable_sync = SU_TRUE; - self->reverse = SU_FALSE; - self->interlace = SU_TRUE; - self->enable_agc = SU_TRUE; - self->x_off = 0; - self->dominance = SU_TRUE; - self->frame_lines = 625; + self->enable_sync = SU_TRUE; + self->reverse = SU_FALSE; + self->interlace = SU_TRUE; + self->enable_agc = SU_TRUE; + self->x_off = 0; + self->dominance = SU_TRUE; + self->frame_lines = 625; - self->enable_comb = SU_TRUE; - self->comb_reverse = SU_FALSE; + self->enable_comb = SU_TRUE; + self->comb_reverse = SU_FALSE; - self->hsync_len = SU_T2N_FLOAT(samp_rate, 4e-6); - self->vsync_len = SU_T2N_FLOAT(samp_rate, 2e-6); - self->line_len = SU_T2N_FLOAT(samp_rate, 64e-6); - self->vsync_odd_trigger = 5; /* VSYNC counter to trigger vertical sync */ + self->hsync_len = SU_T2N_FLOAT(samp_rate, 4e-6); + self->vsync_len = SU_T2N_FLOAT(samp_rate, 2e-6); + self->line_len = SU_T2N_FLOAT(samp_rate, 64e-6); + self->vsync_odd_trigger = 5; /* VSYNC counter to trigger vertical sync */ - self->t_tol = 1e-1; /* Timing error tolerance */ - self->l_tol = 1e-1; /* Level error tolerance */ - self->g_tol = 1e-1; /* Geometry adjustment tolerance */ + self->t_tol = 1e-1; /* Timing error tolerance */ + self->l_tol = 1e-1; /* Level error tolerance */ + self->g_tol = 1e-1; /* Geometry adjustment tolerance */ - self->hsync_huge_err = .25; - self->hsync_max_err = 1e-2; /* Maximum time error for hsync */ - self->hsync_min_err = .5e-2; /* Minimum time error for hsync */ + self->hsync_huge_err = .25; + self->hsync_max_err = 1e-2; /* Maximum time error for hsync */ + self->hsync_min_err = .5e-2; /* Minimum time error for hsync */ - self->hsync_len_tau = 9.5; /* Time constant for hsync length adjust */ - self->line_len_tau = 1e3; /* Time constant for line length estimation */ - self->agc_tau = 1e-5; /* Time constant for AGC adjustment (frames) */ + self->hsync_len_tau = 9.5; /* Time constant for hsync length adjust */ + self->line_len_tau = 1e3; /* Time constant for line length estimation */ + self->agc_tau = 1e-5; /* Time constant for AGC adjustment (frames) */ - self->hsync_fast_track_tau = 9.5; /* Time constant for horizontal adjustment */ - self->hsync_slow_track_tau = 1e3; /* Time constant for horizontal adjustment */ + self->hsync_fast_track_tau = + 9.5; /* Time constant for horizontal adjustment */ + self->hsync_slow_track_tau = + 1e3; /* Time constant for horizontal adjustment */ } -struct sigutils_tv_frame_buffer * -su_tv_frame_buffer_new(const struct sigutils_tv_processor_params *params) +SU_INSTANCER( + su_tv_frame_buffer, + const struct sigutils_tv_processor_params *params) { - struct sigutils_tv_frame_buffer *new = NULL; + su_tv_frame_buffer_t *new = NULL; - SU_TRYCATCH( - new = calloc(1, sizeof (struct sigutils_tv_frame_buffer)), - goto fail); + SU_ALLOCATE_FAIL(new, su_tv_frame_buffer_t); - new->width = SU_CEIL(params->line_len); + new->width = SU_CEIL(params->line_len); new->height = params->frame_lines; - SU_TRYCATCH( - new->buffer = calloc(sizeof(SUFLOAT), new->width * new->height), - goto fail); + SU_ALLOCATE_MANY_FAIL(new->buffer, new->width *new->height, SUFLOAT); return new; fail: if (new != NULL) - su_tv_frame_buffer_destroy(new); + SU_DISPOSE(su_tv_frame_buffer, new); return NULL; } -struct sigutils_tv_frame_buffer * -su_tv_frame_buffer_dup(const struct sigutils_tv_frame_buffer *dup) +SU_COPY_INSTANCER(su_tv_frame_buffer) { - struct sigutils_tv_frame_buffer *new = NULL; + su_tv_frame_buffer_t *new = NULL; - SU_TRYCATCH( - new = calloc(1, sizeof (struct sigutils_tv_frame_buffer)), - goto fail); + SU_ALLOCATE_FAIL(new, su_tv_frame_buffer_t); - new->width = dup->width; - new->height = dup->height; + new->width = self->width; + new->height = self->height; - SU_TRYCATCH( - new->buffer = malloc(sizeof(SUFLOAT) * new->width * new->height), - goto fail); + SU_ALLOCATE_MANY_FAIL(new->buffer, new->width *new->height, SUFLOAT); - memcpy( - new->buffer, - dup->buffer, - sizeof(SUFLOAT) * new->width * new->height); + memcpy(new->buffer, self->buffer, sizeof(SUFLOAT) * new->width *new->height); return new; fail: if (new != NULL) - su_tv_frame_buffer_destroy(new); + SU_DISPOSE(su_tv_frame_buffer, new); return NULL; } -void -su_tv_frame_buffer_destroy(struct sigutils_tv_frame_buffer *self) +SU_COLLECTOR(su_tv_frame_buffer) { if (self->buffer != NULL) free(self->buffer); @@ -263,12 +252,12 @@ su_tv_frame_buffer_destroy(struct sigutils_tv_frame_buffer *self) free(self); } -su_tv_processor_t * -su_tv_processor_new(const struct sigutils_tv_processor_params *params) +SU_INSTANCER(su_tv_processor, const struct sigutils_tv_processor_params *params) { su_tv_processor_t *new = NULL; - SU_TRYCATCH(new = calloc(1, sizeof(su_tv_processor_t)), goto fail); + SU_ALLOCATE_FAIL(new, su_tv_processor_t); + SU_TRYCATCH(su_tv_processor_set_params(new, params), goto fail); new->agc_gain = 1; @@ -282,8 +271,8 @@ su_tv_processor_new(const struct sigutils_tv_processor_params *params) return NULL; } -SUINLINE void -su_tv_processor_swap_field(su_tv_processor_t *self) +SUINLINE +SU_METHOD(su_tv_processor, void, swap_field) { if (self->params.interlace) { self->field_parity = !self->field_parity; @@ -293,8 +282,8 @@ su_tv_processor_swap_field(su_tv_processor_t *self) } } -SUINLINE SUSCOUNT -su_tv_processor_get_line(const su_tv_processor_t *self) +SUINLINE +SU_GETTER(su_tv_processor, SUSCOUNT, get_line) { if (self->params.interlace) return 2 * self->field_y + !self->field_parity; @@ -302,32 +291,36 @@ su_tv_processor_get_line(const su_tv_processor_t *self) return self->field_y; } -SUBOOL -su_tv_processor_set_params( - su_tv_processor_t *self, +SU_METHOD( + su_tv_processor, + SUBOOL, + set_params, const struct sigutils_tv_processor_params *params) { SUFLOAT *line_buffer = NULL; + SUFLOAT *tmp = NULL; + SUSCOUNT delay_line_len = SU_CEIL(params->line_len); + SUBOOL ok = SU_FALSE; - SU_TRYCATCH(params->line_len >= 1, goto fail); - SU_TRYCATCH(params->frame_lines >= 1, goto fail); + SU_TRY_FAIL(params->line_len >= 1); + SU_TRY_FAIL(params->frame_lines >= 1); - SU_TRYCATCH(!params->enable_sync || params->hsync_len >= 1, goto fail); - SU_TRYCATCH(!params->enable_sync || params->vsync_len >= 1, goto fail); + SU_TRY_FAIL(!params->enable_sync || params->hsync_len >= 1); + SU_TRY_FAIL(!params->enable_sync || params->vsync_len >= 1); /* Reset comb filter */ self->delay_line_len = delay_line_len; if (params->enable_comb) { if (self->delay_line_len != delay_line_len || line_buffer == NULL) { - SU_TRYCATCH( - line_buffer = realloc(line_buffer, sizeof(SUFLOAT) * delay_line_len), - goto fail); + SU_TRY_FAIL(tmp = realloc(line_buffer, sizeof(SUFLOAT) * delay_line_len)); + + line_buffer = tmp; if (self->delay_line == NULL) { memset(line_buffer, 0, sizeof(SUFLOAT) * delay_line_len); - } else if (delay_line_len > self->delay_line_len) { + } else if (delay_line_len > self->delay_line_len) { memset( line_buffer + self->delay_line_len, 0, @@ -343,10 +336,10 @@ su_tv_processor_set_params( } self->delay_line = line_buffer; - line_buffer = NULL; + line_buffer = NULL; self->params = *params; - self->state = SU_TV_PROCESSOR_SEARCH; + self->state = SU_TV_PROCESSOR_SEARCH; #if 0 /* Reset coordinates */ @@ -360,31 +353,31 @@ su_tv_processor_set_params( /* Reset AGC state */ if (!SU_VALID(self->agc_gain)) { - self->agc_gain = 1; + self->agc_gain = 1; self->agc_line_max = 0; - self->agc_accum = 0; - self->agc_lines = 0; + self->agc_accum = 0; + self->agc_lines = 0; } /* Reset pulse filter state */ - self->pulse_x = 0; + self->pulse_x = 0; /* Reset pulse finder state */ - self->sync_found = SU_FALSE; - self->sync_start = 0; + self->sync_found = SU_FALSE; + self->sync_start = 0; /* Reset HSYNC detector state */ - self->last_hsync = 0; - self->have_last_hsync = SU_FALSE; - self->est_hsync_len = params->hsync_len; + self->last_hsync = 0; + self->have_last_hsync = SU_FALSE; + self->est_hsync_len = params->hsync_len; /* Reset VSYNC detector state */ - self->last_frame = 0; - self->last_vsync = 0; - self->hsync_slow_track = SU_FALSE; + self->last_frame = 0; + self->last_vsync = 0; + self->hsync_slow_track = SU_FALSE; /* Reset line estimations */ - self->est_line_len = params->line_len; + self->est_line_len = params->line_len; self->est_line_len_accum = 0; self->est_line_len_count = 0; @@ -424,31 +417,35 @@ su_tv_processor_set_params( */ /* Data precalculation */ - self->pulse_alpha = SU_SPLPF_ALPHA(params->hsync_len / 5); - self->agc_alpha = SU_SPLPF_ALPHA(params->agc_tau); - self->hsync_len_alpha = SU_SPLPF_ALPHA(params->hsync_len_tau); + self->pulse_alpha = SU_SPLPF_ALPHA(params->hsync_len / 5); + self->agc_alpha = SU_SPLPF_ALPHA(params->agc_tau); + self->hsync_len_alpha = SU_SPLPF_ALPHA(params->hsync_len_tau); self->hsync_slow_track_alpha = SU_SPLPF_ALPHA(params->hsync_slow_track_tau); self->hsync_fast_track_alpha = SU_SPLPF_ALPHA(params->hsync_fast_track_tau); - self->line_len_alpha = SU_SPLPF_ALPHA(params->line_len_tau); + self->line_len_alpha = SU_SPLPF_ALPHA(params->line_len_tau); - return SU_TRUE; + ok = SU_TRUE; fail: + if (line_buffer != NULL) + free(line_buffer); - return SU_FALSE; + return ok; } -SUINLINE SUBOOL -su_tv_processor_frame_buffer_is_valid( - const su_tv_processor_t *self, +SUINLINE +SU_GETTER( + su_tv_processor, + SUBOOL, + frame_buffer_is_valid, const struct sigutils_tv_frame_buffer *fb) { return fb->width == self->delay_line_len - && fb->height == self->params.frame_lines; + && fb->height == self->params.frame_lines; } -SUINLINE struct sigutils_tv_frame_buffer * -su_tv_processor_take_from_pool(su_tv_processor_t *self) +SUINLINE +SU_METHOD(su_tv_processor, su_tv_frame_buffer_t *, take_from_pool) { struct sigutils_tv_frame_buffer *this = NULL; @@ -459,24 +456,22 @@ su_tv_processor_take_from_pool(su_tv_processor_t *self) if (su_tv_processor_frame_buffer_is_valid(self, this)) break; - su_tv_frame_buffer_destroy(this); + SU_DISPOSE(su_tv_frame_buffer, this); this = NULL; } return this; } -SUINLINE void -su_tv_processor_return_to_pool( - su_tv_processor_t *self, - struct sigutils_tv_frame_buffer *this) +SUINLINE +SU_METHOD(su_tv_processor, void, return_to_pool, su_tv_frame_buffer_t *this) { this->next = self->free_pool; self->free_pool = this; } -SUPRIVATE SUBOOL -su_tv_processor_assert_current_frame(su_tv_processor_t *self) +SUPRIVATE +SU_METHOD(su_tv_processor, SUBOOL, assert_current_frame) { if (self->current != NULL) { if (!su_tv_processor_frame_buffer_is_valid(self, self->current)) { @@ -496,8 +491,7 @@ su_tv_processor_assert_current_frame(su_tv_processor_t *self) return SU_TRUE; } -struct sigutils_tv_frame_buffer * -su_tv_processor_take_frame(su_tv_processor_t *self) +SU_METHOD(su_tv_processor, su_tv_frame_buffer_t *, take_frame) { struct sigutils_tv_frame_buffer *curr = self->current; @@ -506,16 +500,13 @@ su_tv_processor_take_frame(su_tv_processor_t *self) return curr; } -void -su_tv_processor_return_frame( - su_tv_processor_t *self, - struct sigutils_tv_frame_buffer *fb) +SU_METHOD(su_tv_processor, void, return_frame, su_tv_frame_buffer_t *fb) { su_tv_processor_return_to_pool(self, fb); } -SUINLINE SUFLOAT -su_tv_processor_comb_filter_feed(su_tv_processor_t *self, SUFLOAT x) +SUINLINE +SU_METHOD(su_tv_processor, SUFLOAT, comb_filter_feed, SUFLOAT x) { SUFLOAT prev_x; @@ -538,55 +529,54 @@ su_tv_processor_comb_filter_feed(su_tv_processor_t *self, SUFLOAT x) return x; } -SUINLINE SUFLOAT -su_tv_processor_pulse_filter_feed(su_tv_processor_t *self, SUFLOAT x) +SUINLINE +SU_METHOD(su_tv_processor, SUFLOAT, pulse_filter_feed, SUFLOAT x) { self->pulse_x += self->pulse_alpha * (x - self->pulse_x); return self->pulse_x; } -SUINLINE void -su_tv_processor_line_agc_feed(su_tv_processor_t *self, SUFLOAT x) +SUINLINE +SU_METHOD(su_tv_processor, void, line_agc_feed, SUFLOAT x) { if (x > self->agc_line_max) self->agc_line_max = x; } -SUINLINE void -su_tv_processor_line_agc_commit(su_tv_processor_t *self) +SUINLINE +SU_METHOD(su_tv_processor, void, line_agc_commit) { self->agc_accum += self->agc_line_max; ++self->agc_lines; self->agc_line_max = 0; } -SUINLINE void -su_tv_processor_line_agc_update_gain(su_tv_processor_t *self) +SUINLINE +SU_METHOD(su_tv_processor, void, line_agc_update_gain) { if (self->agc_lines > 10) { - self->agc_gain - += (self->agc_lines / self->agc_accum - self->agc_gain); + self->agc_gain += (self->agc_lines / self->agc_accum - self->agc_gain); self->agc_accum = 0; self->agc_lines = 0; } } -SUINLINE SUFLOAT -su_tv_processor_get_field_x(const su_tv_processor_t *self) +SUINLINE +SU_GETTER(su_tv_processor, SUFLOAT, get_field_x) { return self->field_x + self->field_x_dec; } -SUINLINE void -su_tv_processor_set_field_x(su_tv_processor_t *self, SUFLOAT xf) +SUINLINE +SU_METHOD(su_tv_processor, void, set_field_x, SUFLOAT xf) { self->field_x = SU_FLOOR(xf); self->field_x_dec = xf - self->field_x; } -SUINLINE void -su_tv_processor_measure_line_len(su_tv_processor_t *self) +SUINLINE +SU_METHOD(su_tv_processor, void, measure_line_len) { SUSCOUNT new_line_len; @@ -603,13 +593,13 @@ su_tv_processor_measure_line_len(su_tv_processor_t *self) self->last_hsync = self->sync_start; } -SUINLINE void -su_tv_processor_estimate_line_len(su_tv_processor_t *self) +SUINLINE +SU_METHOD(su_tv_processor, void, estimate_line_len) { if (self->est_line_len_count > 0 && self->field_parity) { - self->est_line_len += self->line_len_alpha * - (self->est_line_len_accum / self->est_line_len_count - - self->est_line_len); + self->est_line_len += self->line_len_alpha + * (self->est_line_len_accum / self->est_line_len_count + - self->est_line_len); self->est_line_len_count = 0; self->est_line_len_accum = 0; } @@ -626,17 +616,17 @@ su_tv_processor_estimate_line_len(su_tv_processor_t *self) * traditional single pole IIR low pass filter in order to achieve * this. We do this only for the first pulse we find. */ -SUINLINE void -su_tv_processor_do_hsync(su_tv_processor_t *self, SUSCOUNT hsync_len) +SUINLINE +SU_METHOD(su_tv_processor, void, do_hsync, SUSCOUNT hsync_len) { - SUFLOAT xf = su_tv_processor_get_field_x(self); - SUFLOAT xf_offset = + SUFLOAT xf = su_tv_processor_get_field_x(self); + SUFLOAT xf_offset = self->params.hsync_len / 2 + self->params.x_off * self->est_line_len; - SUFLOAT xf_error = xf_offset - xf; + SUFLOAT xf_error = xf_offset - xf; /* 1. Improve HSYNC length estimation */ - self->est_hsync_len - += self->hsync_len_alpha * (hsync_len - self->est_hsync_len); + self->est_hsync_len += + self->hsync_len_alpha * (hsync_len - self->est_hsync_len); /* 2. Horizontal offset ajustment. */ if (SU_ABS(xf_error / self->est_line_len) > self->params.hsync_max_err) { @@ -647,7 +637,7 @@ su_tv_processor_do_hsync(su_tv_processor_t *self, SUSCOUNT hsync_len) } if (self->state == SU_TV_PROCESSOR_SEARCH) { - xf_error = xf_offset - xf; + xf_error = xf_offset - xf; /* Derived from the max lines and off tau */ if (self->hsync_slow_track) @@ -657,7 +647,7 @@ su_tv_processor_do_hsync(su_tv_processor_t *self, SUSCOUNT hsync_len) su_tv_processor_set_field_x(self, xf); - xf_error = xf_offset - xf; + xf_error = xf_offset - xf; if (SU_ABS(xf_error / self->est_line_len) < self->params.hsync_min_err) { self->state = SU_TV_PROCESSOR_SYNCED; @@ -677,46 +667,41 @@ su_tv_processor_do_hsync(su_tv_processor_t *self, SUSCOUNT hsync_len) * frame as synced. */ -SUINLINE SUBOOL -su_tv_processor_do_vsync(su_tv_processor_t *self, SUSCOUNT vsync_len) +SUINLINE +SU_METHOD(su_tv_processor, SUBOOL, do_vsync, SUSCOUNT vsync_len) { SUSCOUNT last_hsync_age; SUSCOUNT last_vsync_age; - SUFLOAT frame_len = self->est_line_len * self->params.frame_lines; + SUFLOAT frame_len = self->est_line_len * self->params.frame_lines; SUFLOAT vsync_pos; - SUBOOL vsync_forced = SU_FALSE; + SUBOOL vsync_forced = SU_FALSE; last_hsync_age = self->ptr - self->last_hsync; last_vsync_age = self->ptr - self->last_vsync; - vsync_pos = SU_MOD(last_hsync_age, self->est_line_len); + vsync_pos = SU_MOD(last_hsync_age, self->est_line_len); - if (sufreleq( - vsync_pos, - self->est_line_len / 2, - 2 * self->params.t_tol) + if (sufreleq(vsync_pos, self->est_line_len / 2, 2 * self->params.t_tol) && last_vsync_age > frame_len / 4) { /* * First oddly separated pulse seen in a while. * This marks the beginning of a vsync pulse train */ self->vsync_counter = 1; - } else if (sufreleq( - last_vsync_age, - self->est_line_len / 2, - 2 * self->params.t_tol) + } else if ( + sufreleq(last_vsync_age, self->est_line_len / 2, 2 * self->params.t_tol) && self->vsync_counter > 0) { /* * Last vsync found half a line ago, and we stared counting. Increase * the counter. */ if (++self->vsync_counter == self->params.vsync_odd_trigger) { - if (self->field_parity) - su_tv_processor_swap_field(self); - self->field_y = self->field_lines - 1; - vsync_forced = SU_TRUE; - } + if (self->field_parity) + su_tv_processor_swap_field(self); + self->field_y = self->field_lines - 1; + vsync_forced = SU_TRUE; + } } else { /* * None of the above. Reset the pulse train. @@ -729,20 +714,17 @@ su_tv_processor_do_vsync(su_tv_processor_t *self, SUSCOUNT vsync_len) return vsync_forced; } -SUINLINE void -su_tv_processor_sync_feed( - su_tv_processor_t *self, - SUFLOAT pulse_x) +SUINLINE +SU_METHOD(su_tv_processor, void, sync_feed, SUFLOAT pulse_x) { - - SUBOOL pulse_trigger_up; - SUBOOL pulse_trigger_down; + SUBOOL pulse_trigger_up; + SUBOOL pulse_trigger_down; SUSCOUNT sync_len; pulse_x *= self->agc_gain; - pulse_trigger_up = pulse_x > (1 - self->params.l_tol); + pulse_trigger_up = pulse_x > (1 - self->params.l_tol); pulse_trigger_down = pulse_x < (1 - self->params.l_tol); if (!self->sync_found) { @@ -753,20 +735,20 @@ su_tv_processor_sync_feed( } else { if (pulse_trigger_down) { /* SYNC PULSE END */ self->sync_found = SU_FALSE; - sync_len = self->ptr - self->sync_start; + sync_len = self->ptr - self->sync_start; /* * We now proceed to compare the pulse length to any known * pulse length (hsync and vsync). */ - if (sufreleq(sync_len, self->params.hsync_len, self->params.t_tol)) { + if (sufreleq(sync_len, self->params.hsync_len, self->params.t_tol)) { su_tv_processor_measure_line_len(self); su_tv_processor_do_hsync(self, sync_len); } else { self->have_last_hsync = SU_FALSE; } - if (sufreleq(sync_len, self->params.vsync_len, 2 * self->params.t_tol)) + if (sufreleq(sync_len, self->params.vsync_len, 2 * self->params.t_tol)) if (!self->frame_has_vsync) if (su_tv_processor_do_vsync(self, sync_len)) self->frame_has_vsync = SU_TRUE; @@ -774,22 +756,20 @@ su_tv_processor_sync_feed( } } -SUINLINE SUBOOL -su_tv_processor_frame_feed(su_tv_processor_t *self, SUFLOAT x) +SUINLINE +SU_METHOD(su_tv_processor, SUBOOL, frame_feed, SUFLOAT x) { SUSCOUNT line; SUSCOUNT p; SUFLOAT xf; SUFLOAT beta = self->field_x_dec; - SUFLOAT value = self->params.reverse - ? self->agc_gain * x - : (1 - self->agc_gain * x); + SUFLOAT value = + self->params.reverse ? self->agc_gain * x : (1 - self->agc_gain * x); SUBOOL have_line = SU_FALSE; line = su_tv_processor_get_line(self); - if (self->field_x < self->delay_line_len - && line < self->params.frame_lines) { + if (self->field_x < self->delay_line_len && line < self->params.frame_lines) { p = line * self->delay_line_len + self->field_x; if (self->field_prev_ptr < p) @@ -827,8 +807,7 @@ su_tv_processor_frame_feed(su_tv_processor_t *self, SUFLOAT x) return have_line; } -SUBOOL -su_tv_processor_feed(su_tv_processor_t *self, SUFLOAT x) +SU_METHOD(su_tv_processor, SUBOOL, feed, SUFLOAT x) { SUBOOL have_frame = SU_FALSE; SUFLOAT pulse_x; @@ -851,7 +830,7 @@ su_tv_processor_feed(su_tv_processor_t *self, SUFLOAT x) if (self->field_complete) { have_frame = !self->params.interlace - || self->field_parity == !!self->params.dominance; + || self->field_parity == !!self->params.dominance; if (have_frame) self->last_frame = self->ptr; if (self->params.enable_agc) @@ -864,16 +843,15 @@ su_tv_processor_feed(su_tv_processor_t *self, SUFLOAT x) return have_frame; } -void -su_tv_processor_destroy(su_tv_processor_t *self) +SU_COLLECTOR(su_tv_processor) { struct sigutils_tv_frame_buffer *frame = NULL; while ((frame = su_tv_processor_take_from_pool(self)) != NULL) - su_tv_frame_buffer_destroy(frame); + SU_DISPOSE(su_tv_frame_buffer, frame); if (self->current != NULL) - su_tv_frame_buffer_destroy(self->current); + SU_DISPOSE(su_tv_frame_buffer, self->current); if (self->delay_line != NULL) free(self->delay_line); diff --git a/sigutils/tvproc.h b/sigutils/tvproc.h index 289ca89..6fb92bb 100644 --- a/sigutils/tvproc.h +++ b/sigutils/tvproc.h @@ -1,5 +1,4 @@ /* - Copyright (C) 2020 Gonzalo José Carracedo Carballal This program is free software: you can redistribute it and/or modify @@ -14,14 +13,14 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see - */ #ifndef _SIGUTILS_TVPROC_H #define _SIGUTILS_TVPROC_H -#include "types.h" +#include "defs.h" #include "iir.h" +#include "types.h" #ifdef __cplusplus extern "C" { @@ -29,57 +28,56 @@ extern "C" { struct sigutils_tv_processor_params { /* Flags */ - SUBOOL enable_sync; - SUBOOL reverse; - SUBOOL interlace; - SUBOOL enable_agc; - SUFLOAT x_off; + SUBOOL enable_sync; + SUBOOL reverse; + SUBOOL interlace; + SUBOOL enable_agc; + SUFLOAT x_off; /* Geometry */ SUSCOUNT frame_lines; /* Filtering */ - SUBOOL enable_comb; - SUBOOL comb_reverse; + SUBOOL enable_comb; + SUBOOL comb_reverse; /* Timing */ - SUFLOAT hsync_len; - SUFLOAT vsync_len; - SUFLOAT line_len; + SUFLOAT hsync_len; + SUFLOAT vsync_len; + SUFLOAT line_len; SUSCOUNT vsync_odd_trigger; - SUBOOL dominance; + SUBOOL dominance; /* Tolerances */ - SUFLOAT t_tol; /* Timing tolerance */ - SUFLOAT l_tol; /* Level tolerance */ - SUFLOAT g_tol; /* Geometry tolerance. */ + SUFLOAT t_tol; /* Timing tolerance */ + SUFLOAT l_tol; /* Level tolerance */ + SUFLOAT g_tol; /* Geometry tolerance. */ /* Error triggers */ - SUFLOAT hsync_huge_err; /* .25 */ - SUFLOAT hsync_max_err; /* .15 */ - SUFLOAT hsync_min_err; /* .1 */ + SUFLOAT hsync_huge_err; /* .25 */ + SUFLOAT hsync_max_err; /* .15 */ + SUFLOAT hsync_min_err; /* .1 */ /* Time constants */ - SUFLOAT hsync_len_tau; /* 9.5 */ - SUFLOAT hsync_fast_track_tau; /* 9.5 */ - SUFLOAT hsync_slow_track_tau; - SUFLOAT line_len_tau; /* 9.5 */ - - SUFLOAT agc_tau; /* 3 */ + SUFLOAT hsync_len_tau; /* 9.5 */ + SUFLOAT hsync_fast_track_tau; /* 9.5 */ + SUFLOAT hsync_slow_track_tau; + SUFLOAT line_len_tau; /* 9.5 */ + SUFLOAT agc_tau; /* 3 */ }; struct sigutils_pulse_finder { - SUFLOAT base; - SUFLOAT peak_thr; + SUFLOAT base; + SUFLOAT peak_thr; SUSCOUNT length; - SUFLOAT level_tolerance; - SUFLOAT time_tolerance; + SUFLOAT level_tolerance; + SUFLOAT time_tolerance; - SUFLOAT last_y; + SUFLOAT last_y; su_iir_filt_t corr; - SUBOOL present; + SUBOOL present; SUFLOAT accum; SUFLOAT w_accum; SUFLOAT duration; @@ -88,17 +86,16 @@ struct sigutils_pulse_finder { typedef struct sigutils_pulse_finder su_pulse_finder_t; -su_pulse_finder_t *su_pulse_finder_new( +SU_INSTANCER( + su_pulse_finder, SUFLOAT base, SUFLOAT peak, SUSCOUNT len, SUFLOAT tolerance); +SU_COLLECTOR(su_pulse_finder); -SUBOOL su_pulse_finder_feed(su_pulse_finder_t *self, SUFLOAT); - -SUFLOAT su_pulse_finder_get_pos(const su_pulse_finder_t *self); - -void su_pulse_finder_destroy(su_pulse_finder_t *self); +SU_METHOD(su_pulse_finder, SUBOOL, feed, SUFLOAT x); +SU_GETTER(su_pulse_finder, SUFLOAT, get_pos); struct sigutils_tv_frame_buffer { int width, height; @@ -106,13 +103,14 @@ struct sigutils_tv_frame_buffer { struct sigutils_tv_frame_buffer *next; }; -struct sigutils_tv_frame_buffer *su_tv_frame_buffer_new( - const struct sigutils_tv_processor_params *); +typedef struct sigutils_tv_frame_buffer su_tv_frame_buffer_t; -struct sigutils_tv_frame_buffer *su_tv_frame_buffer_dup( - const struct sigutils_tv_frame_buffer *dup); +SU_INSTANCER( + su_tv_frame_buffer, + const struct sigutils_tv_processor_params *params); -void su_tv_frame_buffer_destroy(struct sigutils_tv_frame_buffer *); +SU_COPY_INSTANCER(su_tv_frame_buffer); +SU_COLLECTOR(su_tv_frame_buffer); enum sigutils_tv_processor_state { SU_TV_PROCESSOR_SEARCH, @@ -131,19 +129,19 @@ struct sigutils_tv_processor { /* Precalculated data */ SUSCOUNT field_lines; - SUFLOAT agc_alpha; - SUFLOAT pulse_alpha; - SUFLOAT hsync_len_alpha; - SUFLOAT hsync_slow_track_alpha; - SUFLOAT hsync_fast_track_alpha; - SUFLOAT line_len_alpha; + SUFLOAT agc_alpha; + SUFLOAT pulse_alpha; + SUFLOAT hsync_len_alpha; + SUFLOAT hsync_slow_track_alpha; + SUFLOAT hsync_fast_track_alpha; + SUFLOAT line_len_alpha; /* Frame state */ SUSCOUNT field_x; - SUFLOAT field_x_dec; + SUFLOAT field_x_dec; SUSCOUNT field_y; - SUBOOL field_parity; - SUBOOL field_complete; + SUBOOL field_parity; + SUBOOL field_complete; SUSCOUNT field_prev_ptr; /* Comb filter's delay line */ @@ -152,38 +150,43 @@ struct sigutils_tv_processor { SUSCOUNT delay_line_ptr; /* AGC */ - SUFLOAT agc_gain; - SUFLOAT agc_line_max; - SUFLOAT agc_accum; + SUFLOAT agc_gain; + SUFLOAT agc_line_max; + SUFLOAT agc_accum; SUSCOUNT agc_lines; /* Pulse output */ - SUFLOAT pulse_x; + SUFLOAT pulse_x; /* Sync pulse detection */ - SUBOOL sync_found; + SUBOOL sync_found; SUSCOUNT sync_start; /* HSYNC detection */ SUSCOUNT last_hsync; - SUBOOL have_last_hsync; - SUFLOAT est_hsync_len; - SUBOOL hsync_slow_track; + SUBOOL have_last_hsync; + SUFLOAT est_hsync_len; + SUBOOL hsync_slow_track; /* VSYNC detection */ SUSCOUNT last_frame; SUSCOUNT last_vsync; SUSCOUNT vsync_counter; - SUBOOL frame_has_vsync; + SUBOOL frame_has_vsync; /* Line length estimation */ - SUFLOAT est_line_len; - SUFLOAT est_line_len_accum; + SUFLOAT est_line_len; + SUFLOAT est_line_len_accum; SUSCOUNT est_line_len_count; }; typedef struct sigutils_tv_processor su_tv_processor_t; +SU_INSTANCER( + su_tv_processor, + const struct sigutils_tv_processor_params *params); +SU_COLLECTOR(su_tv_processor); + void su_tv_processor_params_pal( struct sigutils_tv_processor_params *self, SUFLOAT samp_rate); @@ -192,25 +195,15 @@ void su_tv_processor_params_ntsc( struct sigutils_tv_processor_params *self, SUFLOAT samp_rate); -su_tv_processor_t *su_tv_processor_new( - const struct sigutils_tv_processor_params *params); - -SUBOOL su_tv_processor_set_params( - su_tv_processor_t *self, +SU_METHOD( + su_tv_processor, + SUBOOL, + set_params, const struct sigutils_tv_processor_params *params); +SU_METHOD(su_tv_processor, SUBOOL, feed, SUFLOAT x); -SUBOOL su_tv_processor_feed( - su_tv_processor_t *self, - SUFLOAT feed); - -struct sigutils_tv_frame_buffer *su_tv_processor_take_frame( - su_tv_processor_t *); - -void su_tv_processor_return_frame( - su_tv_processor_t *self, - struct sigutils_tv_frame_buffer *); - -void su_tv_processor_destroy(su_tv_processor_t *self); +SU_METHOD(su_tv_processor, su_tv_frame_buffer_t *, take_frame); +SU_METHOD(su_tv_processor, void, return_frame, su_tv_frame_buffer_t *); #ifdef __cplusplus } diff --git a/sigutils/types.h b/sigutils/types.h index c94c709..3a378d5 100644 --- a/sigutils/types.h +++ b/sigutils/types.h @@ -1,5 +1,4 @@ /* - Copyright (C) 2016 Gonzalo José Carracedo Carballal This program is free software: you can redistribute it and/or modify @@ -14,7 +13,6 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see - */ #ifndef _SIGUTILS_TYPES_H @@ -24,134 +22,165 @@ # define _GNU_SOURCE #endif /* __GNUC__ */ -#include -#include -#include -#include #include #include - +#include +#include +#include +#include #include #if defined(__cplusplus) # define SU_USE_CPP_COMPLEX_API #endif +#if __STDC_VERSION__ >= 199901L +# define SU_ENABLE_C99 +#endif /* __STDC_VERSION__ */ + +#if defined(SU_ENABLE_C99) +# define __restrict restrict +#elif !defined(__GNUC__) +# define __restrict +#endif + #ifdef SU_USE_CPP_COMPLEX_API # ifdef I # undef I # endif /* I */ -# define I std::complex{0,1} -# define SUCOMPLEX std::complex -# define SU_C_REAL(c) (c).real() -# define SU_C_IMAG(c) (c).imag() -# define SU_C_ABS(c) std::abs(c) -# define SU_C_ARG(c) std::arg(c) -# define SU_C_EXP(c) std::exp(c) -# define SU_C_CONJ(c) std::conj(c) +# define I \ + std::complex \ + { \ + 0, 1 \ + } +# define SUCOMPLEX std::complex +# define SU_C_REAL(c) (c).real() +# define SU_C_IMAG(c) (c).imag() +# define SU_C_ABS(c) std::abs(c) +# define SU_C_ARG(c) std::arg(c) +# define SU_C_EXP(c) std::exp(c) +# define SU_C_CONJ(c) std::conj(c) # define SU_C_SGN(x) SUCOMPLEX(SU_SGN(SU_C_REAL(x)), SU_SGN(SU_C_IMAG(x))) #else -# define SUCOMPLEX _Complex SUFLOAT +# define SUCOMPLEX _Complex SUFLOAT # define SU_C_REAL(c) (SU_ADDSFX(creal)(c)) # define SU_C_IMAG(c) (SU_ADDSFX(cimag)(c)) -# define SU_C_ABS SU_ADDSFX(cabs) -# define SU_C_ARG SU_ADDSFX(carg) -# define SU_C_EXP SU_ADDSFX(cexp) -# define SU_C_CONJ SU_ADDSFX(conj) -# define SU_C_SGN(x) (SU_SGN(SU_C_REAL(x)) + I * SU_SGN(SU_C_IMAG(x))) +# define SU_C_ABS SU_ADDSFX(cabs) +# define SU_C_ARG SU_ADDSFX(carg) +# define SU_C_EXP SU_ADDSFX(cexp) +# define SU_C_CONJ SU_ADDSFX(conj) +# define SU_C_SGN(x) (SU_SGN(SU_C_REAL(x)) + I * SU_SGN(SU_C_IMAG(x))) #endif -#define SUSINGLE float -#define SUDOUBLE double +#define SUSINGLE float +#define SUDOUBLE double #ifdef _SU_SINGLE_PRECISION -#define SUFLOAT SUSINGLE -#define SU_SOURCE_FFTW_PREFIX fftwf +# define SUFLOAT SUSINGLE +# define SU_SOURCE_FFTW_PREFIX fftwf #else -#define SUFLOAT SUDOUBLE -#define SU_SOURCE_FFTW_PREFIX fftw +# define SUFLOAT SUDOUBLE +# define SU_SOURCE_FFTW_PREFIX fftw #endif -#define SUPRIVATE static -#define SUSCOUNT uint64_t -#define SUSDIFF int64_t -#define SUBOOL int -#define SUFREQ double -#define SUSYMBOL int -#define SUBITS uint8_t /* Not exactly a bit */ +#define SUPRIVATE static +#define SUSCOUNT uint64_t +#define SUSDIFF int64_t +#define SUBOOL int +#define SUFREQ double +#define SUSYMBOL int +#define SUBITS uint8_t /* Not exactly a bit */ #ifdef __cplusplus -# define SUINLINE inline +# define SUINLINE inline #else -# define SUINLINE static inline +# define SUINLINE static inline #endif /* __cplusplus */ /* Perform casts in C and C++ */ #ifdef __cplusplus # define SUCAST(type, value) static_cast(value) #else -# define SUCAST(type, value) ((type) (value)) +# define SUCAST(type, value) ((type)(value)) #endif /* __cplusplus */ #define SU_ASFLOAT(value) SUCAST(SUFLOAT, value) +#define SUIMM(imm) SU_ASFLOAT(imm) #define SU_NOSYMBOL '\0' -#define SU_EOS -1 +#define SU_EOS -1 + +#define SUSINGLE_FMT "%g" +#define SUSINGLE_SCANF_FMT "%f" +#define SUSINGLE_PRECISION_FMT "%.8f" + +#define SUDOUBLE_FMT "%lg" +#define SUDOUBLE_SCANF_FMT "%lf" +#define SUDOUBLE_PRECISION_FMT "%.16lf" #ifdef _SU_SINGLE_PRECISION -# define SUFLOAT_FMT "%g" -# define SUFLOAT_PRECISION_FMT "%.15f" -# define SUFLOAT_SCANF_FMT "%f" +# define SUFLOAT_FMT SUSINGLE_FMT +# define SUFLOAT_PRECISION_FMT SUSINGLE_PRECISION_FMT +# define SUFLOAT_SCANF_FMT SUSINGLE_SCANF_FMT # define SU_ADDSFX(token) JOIN(token, f) #else -# define SUFLOAT_FMT "%lg" -# define SUFLOAT_PRECISION_FMT "%.15lf" -# define SUFLOAT_SCANF_FMT "%lf" +# define SUFLOAT_FMT SUDOUBLE_FMT +# define SUFLOAT_PRECISION_FMT SUDOUBLE_PRECISION_FMT +# define SUFLOAT_SCANF_FMT SUDOUBLE_SCANF_FMT # define SU_ADDSFX(token) token #endif #define SU_FALSE 0 -#define SU_TRUE 1 - -#define SU_SQRT2 1.41421356237 -#define SU_COS SU_ADDSFX(cos) -#define SU_ACOS SU_ADDSFX(acos) -#define SU_SIN SU_ADDSFX(sin) -#define SU_ASIN SU_ADDSFX(asin) -#define SU_TAN SU_ADDSFX(tan) -#define SU_LOG SU_ADDSFX(log10) -#define SU_LN SU_ADDSFX(log) -#define SU_EXP SU_ADDSFX(exp) -#define SU_POW SU_ADDSFX(pow) -#define SU_ABS SU_ADDSFX(fabs) -#define SU_SQRT SU_ADDSFX(sqrt) -#define SU_FLOOR SU_ADDSFX(floor) -#define SU_CEIL SU_ADDSFX(ceil) -#define SU_ROUND SU_ADDSFX(round) -#define SU_COSH SU_ADDSFX(cosh) -#define SU_ACOSH SU_ADDSFX(acosh) -#define SU_FMOD SU_ADDSFX(fmod) -#define SU_ATAN2 SU_ADDSFX(atan2) -#define SU_MODF SU_ADDSFX(modf) - -#ifdef __GNUC__ +#define SU_TRUE 1 + +#define SU_SQRT2 1.41421356237 +#define SU_COS SU_ADDSFX(cos) +#define SU_ACOS SU_ADDSFX(acos) +#define SU_SIN SU_ADDSFX(sin) +#define SU_ASIN SU_ADDSFX(asin) +#define SU_TAN SU_ADDSFX(tan) +#define SU_LOG SU_ADDSFX(log10) +#define SU_LN SU_ADDSFX(log) +#define SU_EXP SU_ADDSFX(exp) +#define SU_POW SU_ADDSFX(pow) +#define SU_ABS SU_ADDSFX(fabs) +#define SU_SQRT SU_ADDSFX(sqrt) +#define SU_FLOOR SU_ADDSFX(floor) +#define SU_CEIL SU_ADDSFX(ceil) +#define SU_ROUND SU_ADDSFX(round) +#define SU_COSH SU_ADDSFX(cosh) +#define SU_ACOSH SU_ADDSFX(acosh) +#define SU_FMOD SU_ADDSFX(fmod) +#define SU_ATAN2 SU_ADDSFX(atan2) +#define SU_MODF SU_ADDSFX(modf) + +/* Extended functions with extra precision */ +#define SU_SQRTX(x) SU_ASFLOAT(sqrt(x)) +#define SU_COSX(x) SU_ASFLOAT(cos(x)) +#define SU_SINX(x) SU_ASFLOAT(sin(x)) + +#define SU_POWX(x, y) pow(x, y) + +#ifdef __APPLE__ +# define SU_SINCOS SU_ADDSFX(__sincos) +#elif defined(__GNUC__) # define SU_SINCOS SU_ADDSFX(sincos) #else # define SU_SINCOS(phi, sinptr, cosptr) \ - do { \ - *(sinptr) = SU_SIN(phi); \ - *(cosptr) = SU_COS(phi); \ - } while(0) -#endif /* __GNUC__ */ + do { \ + *(sinptr) = SU_SIN(phi); \ + *(cosptr) = SU_COS(phi); \ + } while (0) +#endif /* __APPLE__ */ #define SU_SPLPF_ALPHA(tau) (1.f - SU_EXP(-1.f / (tau))) #define SU_SPLPF_FEED(y, x, alpha) y += (alpha) * ((x) - (y)) -#define SU_VALID isfinite +#define SU_VALID isfinite #define SU_C_VALID(x) (SU_VALID(SU_C_REAL(x)) && SU_VALID(SU_C_IMAG(x))) #define SU_SGN(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) #define SU_MOD(x, d) SU_FMOD(x, d) -#define SU_SQR(x) ((x) * (x)) -#define SU_CUBE(x) (SU_SQR(x) * (x)) +#define SU_SQR(x) ((x) * (x)) +#define SU_CUBE(x) (SU_SQR(x) * (x)) #define SU_RAD2DEG(rad) ((rad) * (180 / PI)) #define SU_DEG2RAD(rad) ((rad) * (PI / 180)) @@ -174,11 +203,11 @@ #define sufeq(a, b, tol) (sufcmp(a, b, tol) == 0) #define sufreleq(a, b, tol) (sufrelcmp(a, b, tol) == 0) -#define SUFLOAT_THRESHOLD SU_ADDSFX(1e-15) +#define SUFLOAT_THRESHOLD SU_ADDSFX(1e-15) #define SUFLOAT_MIN_REF_MAG SUFLOAT_THRESHOLD -#define SUFLOAT_MIN_REF_DB -300 -#define SUFLOAT_MAX_REF_MAG 1 -#define SUFLOAT_MAX_REF_DB 0 +#define SUFLOAT_MIN_REF_DB -300 +#define SUFLOAT_MAX_REF_MAG 1 +#define SUFLOAT_MAX_REF_DB 0 #define SUFLOAT_EQUAL(a, b) (SU_ABS(a - b) <= SUFLOAT_THRESHOLD) #define SU_MAX(a, b) ((a) > (b) ? (a) : (b)) @@ -201,8 +230,8 @@ /* Symbol manipulation */ #define SU_FROMSYM(x) ((x) - '0') -#define SU_TOSYM(x) ((x) + '0') -#define SU_ISSYM(x) ((x) >= '0') +#define SU_TOSYM(x) ((x) + '0') +#define SU_ISSYM(x) ((x) >= '0') /* Inline functions */ @@ -226,7 +255,7 @@ su_c_awgn(void) SUFLOAT SQ = SU_SQRT(-SU_LN(U1)); SUFLOAT PH = 2 * PI * U2; - return SQ * (SU_COS(PH) + I * SU_SIN(PH)); + return SQ * (SU_COS(PH) + I * SU_SIN(PH)); } #endif /* _SIGUTILS_TYPES_H */ diff --git a/sigutils/version.c b/sigutils/version.c index ed192e6..12caa34 100644 --- a/sigutils/version.c +++ b/sigutils/version.c @@ -21,7 +21,7 @@ #ifndef SIGUTILS_PKGVERSION # define SIGUTILS_PKGVERSION \ - "custom build on " __DATE__ " at " __TIME__ " (" __VERSION__ ")" + "custom build on " __DATE__ " at " __TIME__ " (" __VERSION__ ")" #endif /* SIGUTILS_BUILD_STRING */ unsigned int @@ -47,23 +47,35 @@ sigutils_abi_check(unsigned int abi) { if (abi != SIGUTILS_ABI_VERSION) { fprintf(stderr, "*** SIGUTILS CRITICAL LIBRARY ERROR ***\n"); - fprintf(stderr, "Expected ABI version (v%u) is incompatible with current\n", abi); - fprintf(stderr, "sigutils ABI version (v%u).\n\n", SIGUTILS_ABI_VERSION); + fprintf( + stderr, + "Expected ABI version (v%u) is incompatible with current\n", + abi); + fprintf(stderr, "sigutils ABI version (v%u).\n\n", (unsigned) SIGUTILS_ABI_VERSION); if (abi < SIGUTILS_ABI_VERSION) { - fprintf(stderr, "The current sigutils ABI version is too new compared to\n"); + fprintf( + stderr, + "The current sigutils ABI version is too new compared to\n"); fprintf(stderr, "the version expected by the user software. Please\n"); fprintf(stderr, "update your software or rebuild it with an updated\n"); fprintf(stderr, "version of sigutils' development files\n\n"); } else { - fprintf(stderr, "The current sigutils ABI version is too old compared to\n"); - fprintf(stderr, "the version expected by the user software. This usually\n"); - fprintf(stderr, "happens when the user software is installed in an older\n"); - fprintf(stderr, "system without fixing its dependencies. Please verify\n"); + fprintf( + stderr, + "The current sigutils ABI version is too old compared to\n"); + fprintf( + stderr, + "the version expected by the user software. This usually\n"); + fprintf( + stderr, + "happens when the user software is installed in an older\n"); + fprintf( + stderr, + "system without fixing its dependencies. Please verify\n"); fprintf(stderr, "your installation and try again.\n"); } abort(); } } - diff --git a/sigutils/version.h b/sigutils/version.h index 53984bf..96c08b6 100644 --- a/sigutils/version.h +++ b/sigutils/version.h @@ -1,5 +1,4 @@ /* - Copyright (C) 2020 Gonzalo José Carracedo Carballal This program is free software: you can redistribute it and/or modify @@ -14,7 +13,6 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see - */ #ifndef _SIGUTILS_VERSION @@ -38,15 +36,14 @@ extern "C" { /* API version macros */ #define SIGUTILS_VERSION_MAJOR 0 -#define SIGUTILS_VERSION_MINOR 2 +#define SIGUTILS_VERSION_MINOR 3 #define SIGUTILS_VERSION_PATCH 0 /* ABI version macros */ -#define SIGUTILS_ABI_VERSION 1 - +#define SIGUTILS_ABI_VERSION 1 /* Utility macros */ -#define __SU_VN(num, shift) ((uint32_t) ((uint8_t) (num)) << (shift)) +#define __SU_VN(num, shift) ((uint32_t)((uint8_t)(num)) << (shift)) #define SU_VER(major, minor, patch) \ (__SU_VN(major, 16) | __SU_VN(minor, 8) | __SU_VN(patch, 0)) @@ -57,15 +54,13 @@ extern "C" { #define SIGUTILS_API_VERSION \ SU_VER(SIGUTILS_VERSION_MAJOR, SIGUTILS_VERSION_MINOR, 0) -#define SIGUTILS_VERSION_STRING \ - STRINGIFY(SIGUTILS_VERSION_MAJOR) "." \ - STRINGIFY(SIGUTILS_VERSION_MINOR) "." \ - STRINGIFY(SIGUTILS_VERSION_PATCH) - +#define SIGUTILS_VERSION_STRING \ + STRINGIFY(SIGUTILS_VERSION_MAJOR) \ + "." STRINGIFY(SIGUTILS_VERSION_MINOR) "." STRINGIFY(SIGUTILS_VERSION_PATCH) unsigned int sigutils_abi_version(void); -const char *sigutils_api_version(void); -const char *sigutils_pkgversion(void); +const char *sigutils_api_version(void); +const char *sigutils_pkgversion(void); void sigutils_abi_check(unsigned int); @@ -76,4 +71,3 @@ void sigutils_abi_check(unsigned int); #endif /* __cplusplus */ #endif /* _SIGUTILS_VERSION */ - diff --git a/src/main.c b/src/main.c index 2aabc68..5e4e62f 100644 --- a/src/main.c +++ b/src/main.c @@ -3,21 +3,19 @@ * Creation date: Thu Oct 20 22:56:46 2016 */ -#include -#include -#include #include #include -#include - -#include -#include -#include +#include #include +#include +#include #include - +#include #include - +#include +#include +#include +#include #include #include @@ -28,25 +26,15 @@ SUPRIVATE su_test_entry_t test_list[] = { SU_TEST_ENTRY(su_test_agc_steady_rising), SU_TEST_ENTRY(su_test_agc_steady_falling), SU_TEST_ENTRY(su_test_pll), - SU_TEST_ENTRY(su_test_block), - SU_TEST_ENTRY(su_test_block_plugging), - SU_TEST_ENTRY(su_test_block_flow_control), - SU_TEST_ENTRY(su_test_tuner), SU_TEST_ENTRY(su_test_costas_lock), SU_TEST_ENTRY(su_test_costas_bpsk), SU_TEST_ENTRY(su_test_costas_qpsk), SU_TEST_ENTRY(su_test_costas_qpsk_noisy), - SU_TEST_ENTRY(su_test_costas_block), - SU_TEST_ENTRY(su_test_rrc_block), - SU_TEST_ENTRY(su_test_rrc_block_with_if), SU_TEST_ENTRY(su_test_clock_recovery), SU_TEST_ENTRY(su_test_clock_recovery_noisy), - SU_TEST_ENTRY(su_test_cdr_block), SU_TEST_ENTRY(su_test_channel_detector_qpsk), SU_TEST_ENTRY(su_test_channel_detector_qpsk_noisy), SU_TEST_ENTRY(su_test_channel_detector_real_capture), - SU_TEST_ENTRY(su_test_diff_codec_binary), - SU_TEST_ENTRY(su_test_diff_codec_quaternary), SU_TEST_ENTRY(su_test_specttuner_two_tones), SU_TEST_ENTRY(su_test_mat_file_regular), SU_TEST_ENTRY(su_test_mat_file_streaming), @@ -64,16 +52,39 @@ help(const char *argv0) "to run. If neither test_start nor test_end is passed, all tests will\n" "be executed\n\n"); fprintf(stderr, "Options:\n\n"); - fprintf(stderr, " -d, --dump Dump tests results as MATLAB files\n"); - fprintf(stderr, " -w, --wav Dump tests results as WAV files\n"); - fprintf(stderr, " -R, --raw Dump tests results as raw (I/Q) files\n"); - fprintf(stderr, " -c, --count Print number of tests and exit\n"); - fprintf(stderr, " -s, --buffer-size=S Sets the signal buffer size for unit\n"); - fprintf(stderr, " tests. Default is %d samples\n", SU_TEST_SIGNAL_BUFFER_SIZE); - fprintf(stderr, " -r, --sample-rate=r For WAV files, set the sampling frequency.\n"); - fprintf(stderr, " Default is %d samples per second\n", SU_SIGBUF_SAMPLING_FREQUENCY_DEFAULT); - fprintf(stderr, " -l, --list Provides a list of available unit tests\n"); - fprintf(stderr, " with their corresponding test ID and exit\n"); + fprintf( + stderr, + " -d, --dump Dump tests results as MATLAB files\n"); + fprintf( + stderr, + " -w, --wav Dump tests results as WAV files\n"); + fprintf( + stderr, + " -R, --raw Dump tests results as raw (I/Q) files\n"); + fprintf( + stderr, + " -c, --count Print number of tests and exit\n"); + fprintf( + stderr, + " -s, --buffer-size=S Sets the signal buffer size for unit\n"); + fprintf( + stderr, + " tests. Default is %d samples\n", + SU_TEST_SIGNAL_BUFFER_SIZE); + fprintf( + stderr, + " -r, --sample-rate=r For WAV files, set the sampling " + "frequency.\n"); + fprintf( + stderr, + " Default is %d samples per second\n", + SU_SIGBUF_SAMPLING_FREQUENCY_DEFAULT); + fprintf( + stderr, + " -l, --list Provides a list of available unit tests\n"); + fprintf( + stderr, + " with their corresponding test ID and exit\n"); fprintf(stderr, " -v, --version Print sigutils version\n"); fprintf(stderr, " -h, --help This help\n\n"); fprintf(stderr, "(c) 2020 Gonzalo J. Caracedo \n"); @@ -88,7 +99,8 @@ version(void) fprintf(stderr, "Copyright © 2020 Gonzalo José Carracedo Carballal\n"); fprintf( stderr, - "License GPLv3+: GNU GPL version 3 or later \n"); + "License GPLv3+: GNU GPL version 3 or later " + "\n"); } SUPRIVATE void @@ -98,10 +110,10 @@ list(const char *argv0) unsigned int i; for (i = 0; i < test_count; ++i) { - printf(" %3d %s\n", i, test_list[i].name); + printf(" %3u %s\n", i, test_list[i].name); } - printf("%s: %d unit tests available\n", argv0, test_count); + printf("%s: %u unit tests available\n", argv0, test_count); } SUPRIVATE struct option long_options[] = { @@ -114,13 +126,12 @@ SUPRIVATE struct option long_options[] = { {"count", no_argument, NULL, 'c'}, {"list", no_argument, NULL, 'l'}, {"version", no_argument, NULL, 'v'}, - {NULL, 0, NULL, 0} -}; + {NULL, 0, NULL, 0}}; extern int optind; int -main (int argc, char *argv[], char *envp[]) +main(int argc, char *argv[]) { unsigned int test_count = sizeof(test_list) / sizeof(test_list[0]); unsigned int test_start = 0; @@ -130,10 +141,11 @@ main (int argc, char *argv[], char *envp[]) int c; int index; - while ((c = getopt_long(argc, argv, "Rdhclws:r:v", long_options, &index)) != -1) { + while ((c = getopt_long(argc, argv, "Rdhclws:r:v", long_options, &index)) + != -1) { switch (c) { case 'c': - printf("%s: %d unit tests available\n", argv[0], test_count); + printf("%s: %u unit tests available\n", argv[0], test_count); exit(EXIT_FAILURE); case 'd': @@ -157,7 +169,7 @@ main (int argc, char *argv[], char *envp[]) exit(EXIT_SUCCESS); case 's': - if (sscanf(optarg, "%llu", ¶ms.buffer_size) < 0) { + if (sscanf(optarg, "%" SCNu64, ¶ms.buffer_size) < 0) { fprintf(stderr, "%s: invalid buffer size `%s'\n", argv[0], optarg); help(argv[0]); exit(EXIT_SUCCESS); @@ -165,7 +177,7 @@ main (int argc, char *argv[], char *envp[]) break; case 'r': - if (sscanf(optarg, "%llu", ¶ms.fs) < 0) { + if (sscanf(optarg, "%" SCNu64, ¶ms.fs) < 0) { fprintf(stderr, "%s: invalid sampling rate `%s'\n", argv[0], optarg); help(argv[0]); exit(EXIT_SUCCESS); @@ -189,13 +201,17 @@ main (int argc, char *argv[], char *envp[]) if (!su_lib_init()) { fprintf(stderr, "%s: failed to initialize sigutils library\n", argv[0]); - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); } if (argc - optind >= 1) { if (sscanf(argv[optind++], "%u", &test_start) < 1) { - fprintf(stderr, "%s: invalid test start `%s'\n", argv[0], argv[optind - 1]); - exit (EXIT_FAILURE); + fprintf( + stderr, + "%s: invalid test start `%s'\n", + argv[0], + argv[optind - 1]); + exit(EXIT_FAILURE); } test_end = test_start; @@ -204,14 +220,14 @@ main (int argc, char *argv[], char *envp[]) if (argc - optind >= 1) { if (sscanf(argv[optind++], "%u", &test_end) < 1) { fprintf(stderr, "%s: invalid test end\n", argv[0]); - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); } } if (argc - optind >= 1) { fprintf(stderr, "%s: too many arguments\n", argv[0]); help(argv[0]); - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); } result = su_test_run( @@ -223,4 +239,3 @@ main (int argc, char *argv[], char *envp[]) return !result; } - diff --git a/src/tests/agc.c b/src/tests/agc.c index ed2f6a8..bcdc039 100644 --- a/src/tests/agc.c +++ b/src/tests/agc.c @@ -17,17 +17,15 @@ */ -#include -#include -#include - -#include -#include -#include #include +#include +#include #include - +#include #include +#include +#include +#include #include "test_list.h" #include "test_param.h" @@ -78,17 +76,17 @@ su_test_agc_transient(su_test_context_t *ctx) /* Initialize */ SU_TEST_ASSERT(buffer = su_test_buffer_new(SU_TEST_SIGNAL_BUFFER_SIZE)); - agc_params.delay_line_size = 10; + agc_params.delay_line_size = 10; agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; + agc_params.fast_rise_t = 2; + agc_params.fast_fall_t = 4; - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; + agc_params.slow_rise_t = 20; + agc_params.slow_fall_t = 40; - agc_params.threshold = SU_DB(2e-2); + agc_params.threshold = SU_DB(2e-2); - agc_params.hang_max = 30; + agc_params.hang_max = 30; if (!su_agc_init(&agc, &agc_params)) goto done; @@ -96,18 +94,17 @@ su_test_agc_transient(su_test_context_t *ctx) /* Create a spike */ for (p = 0; p < SU_TEST_SIGNAL_BUFFER_SIZE; ++p) { t = p - SU_TEST_SIGNAL_BUFFER_SIZE / 2; - buffer[p] = 1e-2 * rand() / (double) RAND_MAX; + buffer[p] = 1e-2 * rand() / (double)RAND_MAX; buffer[p] += SU_EXP(-t * t); } if (ctx->params->dump_fmt) { - SU_TEST_ASSERT( - su_test_buffer_dump_matlab( - buffer, - SU_TEST_SIGNAL_BUFFER_SIZE, - "spike.m", - "spike")); + SU_TEST_ASSERT(su_test_buffer_dump_matlab( + buffer, + SU_TEST_SIGNAL_BUFFER_SIZE, + "spike.m", + "spike")); } SU_TEST_TICK(ctx); @@ -126,12 +123,11 @@ su_test_agc_transient(su_test_context_t *ctx) if (buffer != NULL) { if (ctx->params->dump_fmt) { - SU_TEST_ASSERT( - su_test_buffer_dump_matlab( - buffer, - SU_TEST_SIGNAL_BUFFER_SIZE, - "corrected.m", - "corrected")); + SU_TEST_ASSERT(su_test_buffer_dump_matlab( + buffer, + SU_TEST_SIGNAL_BUFFER_SIZE, + "corrected.m", + "corrected")); } free(buffer); @@ -145,7 +141,6 @@ su_test_agc_steady_rising(su_test_context_t *ctx) { SUBOOL ok = SU_FALSE; SUFLOAT *buffer = NULL; - SUFLOAT t; su_agc_t agc = su_agc_INITIALIZER; su_ncqo_t ncqo = su_ncqo_INITIALIZER; struct su_agc_params agc_params = su_agc_params_INITIALIZER; @@ -155,18 +150,18 @@ su_test_agc_steady_rising(su_test_context_t *ctx) /* Initialize */ SU_TEST_ASSERT(buffer = su_test_buffer_new(SU_TEST_SIGNAL_BUFFER_SIZE)); - agc_params.delay_line_size = 10; + agc_params.delay_line_size = 10; agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; + agc_params.fast_rise_t = 2; + agc_params.fast_fall_t = 4; - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; + agc_params.slow_rise_t = 20; + agc_params.slow_fall_t = 40; - agc_params.threshold = SU_DB(2e-2); + agc_params.threshold = SU_DB(2e-2); - agc_params.hang_max = 30; - agc_params.slope_factor = 0; + agc_params.hang_max = 30; + agc_params.slope_factor = 0; SU_TEST_ASSERT(su_agc_init(&agc, &agc_params)); @@ -174,19 +169,17 @@ su_test_agc_steady_rising(su_test_context_t *ctx) /* Create a rising sinusoid */ for (p = 0; p < SU_TEST_SIGNAL_BUFFER_SIZE; ++p) { - t = p - SU_TEST_SIGNAL_BUFFER_SIZE / 2; - buffer[p] = 1e-2 * rand() / (double) RAND_MAX; - - buffer[p] += 0.2 * floor(1 + 5 * p / SU_TEST_SIGNAL_BUFFER_SIZE) * su_ncqo_read_i(&ncqo); + buffer[p] = 1e-2 * rand() / (double)RAND_MAX; + buffer[p] += 0.2 * floor(1 + 5 * p / SU_TEST_SIGNAL_BUFFER_SIZE) + * su_ncqo_read_i(&ncqo); } if (ctx->params->dump_fmt) { - SU_TEST_ASSERT( - su_test_buffer_dump_matlab( - buffer, - SU_TEST_SIGNAL_BUFFER_SIZE, - "steady.m", - "steady")); + SU_TEST_ASSERT(su_test_buffer_dump_matlab( + buffer, + SU_TEST_SIGNAL_BUFFER_SIZE, + "steady.m", + "steady")); } SU_TEST_TICK(ctx); @@ -197,14 +190,13 @@ su_test_agc_steady_rising(su_test_context_t *ctx) } /* TODO: Improve levels */ - SU_TEST_ASSERT( - su_test_check_peak( - ctx, - buffer, - SU_TEST_SIGNAL_BUFFER_SIZE, - 2 * SU_TEST_AGC_WINDOW, - SU_AGC_RESCALE * 0.9 , - SU_AGC_RESCALE * 1.1)); + SU_TEST_ASSERT(su_test_check_peak( + ctx, + buffer, + SU_TEST_SIGNAL_BUFFER_SIZE, + 2 * SU_TEST_AGC_WINDOW, + SU_AGC_RESCALE * 0.9, + SU_AGC_RESCALE * 1.1)); ok = SU_TRUE; @@ -215,12 +207,11 @@ su_test_agc_steady_rising(su_test_context_t *ctx) if (buffer != NULL) { if (ctx->params->dump_fmt) { - SU_TEST_ASSERT( - su_test_buffer_dump_matlab( - buffer, - SU_TEST_SIGNAL_BUFFER_SIZE, - "corrected.m", - "corrected")); + SU_TEST_ASSERT(su_test_buffer_dump_matlab( + buffer, + SU_TEST_SIGNAL_BUFFER_SIZE, + "corrected.m", + "corrected")); } free(buffer); @@ -235,7 +226,6 @@ su_test_agc_steady_falling(su_test_context_t *ctx) SUBOOL ok = SU_FALSE; SUFLOAT *input = NULL; SUFLOAT *output = NULL; - SUFLOAT t; su_agc_t agc = su_agc_INITIALIZER; su_ncqo_t ncqo = su_ncqo_INITIALIZER; struct su_agc_params agc_params = su_agc_params_INITIALIZER; @@ -246,18 +236,18 @@ su_test_agc_steady_falling(su_test_context_t *ctx) /* Initialize */ SU_TEST_ASSERT(input = su_test_ctx_getf(ctx, "x")); SU_TEST_ASSERT(output = su_test_ctx_getf(ctx, "y")); - agc_params.delay_line_size = 10; + agc_params.delay_line_size = 10; agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; + agc_params.fast_rise_t = 2; + agc_params.fast_fall_t = 4; - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; + agc_params.slow_rise_t = 20; + agc_params.slow_fall_t = 40; - agc_params.threshold = SU_DB(2e-2); + agc_params.threshold = SU_DB(2e-2); - agc_params.hang_max = 30; - agc_params.slope_factor = 0; + agc_params.hang_max = 30; + agc_params.slope_factor = 0; SU_TEST_ASSERT(su_agc_init(&agc, &agc_params)); @@ -265,10 +255,9 @@ su_test_agc_steady_falling(su_test_context_t *ctx) /* Create a falling sinusoid */ for (p = 0; p < ctx->params->buffer_size; ++p) { - t = p - ctx->params->buffer_size / 2; - input[p] = 1e-2 * rand() / (double) RAND_MAX; - - input[p] += 0.2 * floor(5 - 5 * p / ctx->params->buffer_size) * su_ncqo_read_i(&ncqo); + input[p] = 1e-2 * rand() / (double)RAND_MAX; + input[p] += 0.2 * floor(5 - 5 * p / ctx->params->buffer_size) + * su_ncqo_read_i(&ncqo); } SU_TEST_TICK(ctx); @@ -279,14 +268,13 @@ su_test_agc_steady_falling(su_test_context_t *ctx) } /* TODO: Improve levels */ - SU_TEST_ASSERT( - su_test_check_peak( - ctx, - input, - ctx->params->buffer_size, - 2 * SU_TEST_AGC_WINDOW, - SU_AGC_RESCALE * 0.9 , - SU_AGC_RESCALE * 1.1)); + SU_TEST_ASSERT(su_test_check_peak( + ctx, + input, + ctx->params->buffer_size, + 2 * SU_TEST_AGC_WINDOW, + SU_AGC_RESCALE * 0.9, + SU_AGC_RESCALE * 1.1)); ok = SU_TRUE; @@ -297,4 +285,3 @@ su_test_agc_steady_falling(su_test_context_t *ctx) return ok; } - diff --git a/src/tests/block.c b/src/tests/block.c index 4c7123c..23c6076 100644 --- a/src/tests/block.c +++ b/src/tests/block.c @@ -17,874 +17,19 @@ */ -#include -#include -#include - -#include -#include -#include #include +#include +#include #include - +#include #include +#include +#include +#include #include "test_list.h" #include "test_param.h" -SUBOOL -su_test_block(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *block = NULL; - su_block_port_t port = su_block_port_INITIALIZER; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - SUCOMPLEX samp = 0; - - SU_TEST_START(ctx); - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - block = su_block_new("agc", &agc_params); - SU_TEST_ASSERT(block != NULL); - - /* Plug block to the reading port */ - SU_TEST_ASSERT(su_block_port_plug(&port, block, 0)); - - /* Try to read (this must fail) */ - SU_TEST_ASSERT(su_block_port_read(&port, &samp, 1) == SU_BLOCK_PORT_READ_ERROR_ACQUIRE); - - ok = SU_TRUE; -done: - SU_TEST_END(ctx); - - if (su_block_port_is_plugged(&port)) - su_block_port_unplug(&port); - - if (block != NULL) - su_block_destroy(block); - - return ok; -} - -SUBOOL -su_test_block_plugging(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *agc_block = NULL; - su_block_t *wav_block = NULL; - su_block_port_t port = su_block_port_INITIALIZER; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - SUCOMPLEX buffer[17]; /* Prime number on purpose */ - SUCOMPLEX *rx = NULL; - SUFLOAT real = 0; - int i; - unsigned int j = 0; - SUSDIFF got; - - SU_TEST_START(ctx); - - SU_TEST_ASSERT(rx = su_test_ctx_getc(ctx, "rx")); - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - agc_block = su_block_new("agc", &agc_params); - SU_TEST_ASSERT(agc_block != NULL); - - wav_block = su_block_new("wavfile", "test.wav"); - SU_TEST_ASSERT(wav_block != NULL); - - /* Plug wav file to AGC */ - SU_TEST_ASSERT(su_block_plug(wav_block, 0, 0, agc_block)); - - /* Plug AGC to the reading port */ - SU_TEST_ASSERT(su_block_port_plug(&port, agc_block, 0)); - - /* Try to read (this must work) */ - do { - got = su_block_port_read(&port, buffer, 17); - SU_TEST_ASSERT(got >= 0); - - if (ctx->params->dump_fmt && j + got <= ctx->params->buffer_size) - for (i = 0; i < got; ++i) - rx[i + j] = buffer[i]; - - j += got; - } while (got > 0); - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - if (su_block_port_is_plugged(&port)) - su_block_port_unplug(&port); - - if (agc_block != NULL) - su_block_destroy(agc_block); - - if (wav_block != NULL) - su_block_destroy(wav_block); - - return ok; -} - -struct su_test_block_flow_control_params { - su_block_port_t *port; - su_test_context_t *ctx; - SUCOMPLEX *readbuf; - SUSCOUNT buffer_size; - SUBOOL oddity; - SUBOOL ok; -}; - -SUPRIVATE void * -su_test_block_flow_control_reader_thread(void *private) -{ - struct timespec wait_period; - struct su_test_block_flow_control_params *params = - (struct su_test_block_flow_control_params *) private; - SUSCOUNT p; - SUSCOUNT rem; - SUSDIFF got; - su_test_context_t *ctx = params->ctx; - SUBOOL ok = SU_FALSE; - - /* Read sleep period */ - wait_period.tv_sec = SU_TEST_BLOCK_READ_WAIT_MS / 1000; - wait_period.tv_nsec = (SU_TEST_BLOCK_READ_WAIT_MS * 1000000) % 1000000000; - - /* Populate buffer */ - p = 0; - while (p < params->buffer_size) { - rem = params->buffer_size - p; - - got = su_block_port_read(params->port, params->readbuf + p, rem); - SU_TEST_ASSERT(got >= 0); - p += got; - - if (params->oddity) - nanosleep(&wait_period, NULL); - - params->oddity = !params->oddity; - } - - ok = SU_TRUE; - -done: - params->ok = ok; - - return NULL; -} - -SUBOOL -su_test_block_flow_control(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *siggen_block = NULL; - su_block_port_t port_1 = su_block_port_INITIALIZER; - su_block_port_t port_2 = su_block_port_INITIALIZER; - SUCOMPLEX *readbuf_1 = NULL; - SUCOMPLEX *readbuf_2 = NULL; - pthread_t thread_1; - pthread_t thread_2; - SUBOOL thread_1_running = SU_FALSE; - SUBOOL thread_2_running = SU_FALSE; - struct su_test_block_flow_control_params thread_1_params; - struct su_test_block_flow_control_params thread_2_params; - SUSCOUNT i; - - SU_TEST_START(ctx); - - /* Create reading buffers */ - SU_TEST_ASSERT(readbuf_1 = su_test_ctx_getc(ctx, "thread1_buf")); - SU_TEST_ASSERT(readbuf_2 = su_test_ctx_getc(ctx, "thread2_buf")); - - /* Casts are mandatory here */ - siggen_block = su_block_new( - "siggen", - "sawtooth", - (SUFLOAT) SU_TEST_BLOCK_SAWTOOTH_WIDTH, - (SUSCOUNT) SU_TEST_BLOCK_SAWTOOTH_WIDTH, - (SUSCOUNT) 0, - "null", - (SUFLOAT) 0, - (SUSCOUNT) 0, - (SUSCOUNT) 0); - - SU_TEST_ASSERT(siggen_block != NULL); - - /* Set barrier flow controller in its only port */ - SU_TEST_ASSERT( - su_block_set_flow_controller( - siggen_block, - 0, - SU_FLOW_CONTROL_KIND_BARRIER)); - - /* Plug ports to siggen */ - SU_TEST_ASSERT(su_block_port_plug(&port_1, siggen_block, 0)); - SU_TEST_ASSERT(su_block_port_plug(&port_2, siggen_block, 0)); - - /* Create thread params */ - thread_1_params.ctx = ctx; - thread_1_params.port = &port_1; - thread_1_params.readbuf = readbuf_1; - thread_1_params.buffer_size = ctx->params->buffer_size; - thread_1_params.oddity = SU_FALSE; - - thread_2_params.ctx = ctx; - thread_2_params.port = &port_2; - thread_2_params.readbuf = readbuf_2; - thread_2_params.buffer_size = ctx->params->buffer_size; - thread_2_params.oddity = SU_TRUE; - - - /* Spawn both threads */ - SU_TEST_ASSERT( - pthread_create( - &thread_1, - NULL, - su_test_block_flow_control_reader_thread, - &thread_1_params) != -1); - thread_1_running = SU_TRUE; - - SU_TEST_ASSERT( - pthread_create( - &thread_2, - NULL, - su_test_block_flow_control_reader_thread, - &thread_2_params) != -1); - thread_2_running = SU_TRUE; - - pthread_join(thread_1, NULL); - thread_1_running = SU_FALSE; - - pthread_join(thread_2, NULL); - thread_2_running = SU_FALSE; - - /* Check that everything went fine */ - SU_TEST_ASSERT(thread_1_params.ok); - SU_TEST_ASSERT(thread_2_params.ok); - - /* Both buffers must hold exactly the same contents */ - for (i = 0; i < ctx->params->buffer_size; ++i) - SU_TEST_ASSERT(thread_1_params.readbuf[i] == thread_2_params.readbuf[i]); - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - /* - * To prevent segmentation faults, we free memory if both threads - * are halted. - */ - if (!thread_1_running && !thread_2_running) { - - if (su_block_port_is_plugged(&port_1)) - su_block_port_unplug(&port_1); - - if (su_block_port_is_plugged(&port_2)) - su_block_port_unplug(&port_2); - - if (siggen_block != NULL) - su_block_destroy(siggen_block); - } - - return ok; -} - - -SUBOOL -su_test_tuner(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *agc_block = NULL; - su_block_t *tuner_block = NULL; - su_block_t *wav_block = NULL; - su_block_port_t port = su_block_port_INITIALIZER; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - SUCOMPLEX buffer[17]; /* Prime number on purpose */ - SUCOMPLEX *rx = NULL; - SUFLOAT samp = 0; - int i; - unsigned int j = 0; - SUSDIFF got; - - /* Block properties */ - int *samp_rate; - SU_TEST_START(ctx); - - SU_TEST_ASSERT(rx = su_test_ctx_getc(ctx, "rx")); - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - wav_block = su_block_new("wavfile", "test.wav"); - SU_TEST_ASSERT(wav_block != NULL); - - samp_rate = su_block_get_property_ref( - wav_block, - SU_PROPERTY_TYPE_INTEGER, - "samp_rate"); - SU_TEST_ASSERT(samp_rate != NULL); - SU_TEST_ASSERT(*samp_rate == 8000); - - SU_INFO("Wav file opened, sample rate: %d\n", *samp_rate); - - tuner_block = su_block_new( - "tuner", - SU_ABS2NORM_FREQ(*samp_rate, 910), /* Center frequency (910 Hz) */ - SU_ABS2NORM_FREQ(*samp_rate, 468), /* Signal is 468 baud */ - SU_ABS2NORM_FREQ(*samp_rate, 2000), /* Move signal to 2 KHz */ - 500); /* 500 coefficients */ - SU_TEST_ASSERT(tuner_block != NULL); - - agc_block = su_block_new("agc", &agc_params); - SU_TEST_ASSERT(agc_block != NULL); - - /* Plug wav file to tuner */ - SU_TEST_ASSERT(su_block_plug(wav_block, 0, 0, tuner_block)); - - /* Plug tuner to AGC */ - SU_TEST_ASSERT(su_block_plug(tuner_block, 0, 0, agc_block)); - - /* Plug AGC to the reading port */ - SU_TEST_ASSERT(su_block_port_plug(&port, agc_block, 0)); - - /* Try to read (this must work) */ - do { - got = su_block_port_read(&port, buffer, 17); - SU_TEST_ASSERT(got >= 0); - - if (ctx->params->dump_fmt && j + got <= ctx->params->buffer_size) - for (i = 0; i < got; ++i) - rx[i + j] = buffer[i]; - - j += got; - } while (got > 0); - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - if (su_block_port_is_plugged(&port)) - su_block_port_unplug(&port); - - if (agc_block != NULL) - su_block_destroy(agc_block); - - if (tuner_block != NULL) - su_block_destroy(tuner_block); - - if (wav_block != NULL) - su_block_destroy(wav_block); - - return ok; -} - -SUBOOL -su_test_costas_block(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *costas_block = NULL; - su_block_t *agc_block = NULL; - su_block_t *wav_block = NULL; - su_block_port_t port = su_block_port_INITIALIZER; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - SUCOMPLEX buffer[17]; /* Prime number on purpose */ - SUCOMPLEX *rx = NULL; - SUFLOAT *freq = NULL; - SUFLOAT samp = 0; - int i; - unsigned int j = 0; - SUSDIFF got; - - /* Signal properties */ - const SUFLOAT baud = 468; - const SUFLOAT arm_bw = .5 * baud; - const unsigned int arm_order = 10; - const SUFLOAT loop_bw = 1e-1 * baud; - const unsigned int sample_count = 8000 * 59; - /* Block properties */ - int *samp_rate; - SUFLOAT *f; - - unsigned int *size; - - SU_TEST_START(ctx); - - SU_TEST_ASSERT(freq = su_test_ctx_getf_w_size(ctx, "freq", sample_count)); - SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", sample_count)); - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - wav_block = su_block_new("wavfile", "test.wav"); - SU_TEST_ASSERT(wav_block != NULL); - - samp_rate = su_block_get_property_ref( - wav_block, - SU_PROPERTY_TYPE_INTEGER, - "samp_rate"); - SU_TEST_ASSERT(samp_rate != NULL); - SU_TEST_ASSERT(*samp_rate == 8000); - - SU_INFO("Wav file opened, sample rate: %d\n", *samp_rate); - - agc_block = su_block_new("agc", &agc_params); - SU_TEST_ASSERT(agc_block != NULL); - - costas_block = su_block_new( - "costas", - SU_COSTAS_KIND_QPSK, - SU_ABS2NORM_FREQ(*samp_rate, 900), - SU_ABS2NORM_FREQ(*samp_rate, arm_bw), - arm_order, - SU_ABS2NORM_FREQ(*samp_rate, loop_bw)); - SU_TEST_ASSERT(costas_block != NULL); - - f = su_block_get_property_ref( - costas_block, - SU_PROPERTY_TYPE_FLOAT, - "f"); - SU_TEST_ASSERT(f != NULL); - SU_INFO( - "Costas loop created, initial frequency: %lg Hz\n", - SU_NORM2ABS_FREQ(*samp_rate, *f)); - - /* Plug wav file directly to AGC (there should be a tuner before this) */ - SU_TEST_ASSERT(su_block_plug(wav_block, 0, 0, agc_block)); - - /* Plug AGC to Costas loop */ - SU_TEST_ASSERT(su_block_plug(agc_block, 0, 0, costas_block)); - - /* Plug Costas loop to the reading port */ - SU_TEST_ASSERT(su_block_port_plug(&port, costas_block, 0)); - - /* Try to read (this must work) */ - while (j < sample_count) { - got = su_block_port_read(&port, buffer, 1); - SU_TEST_ASSERT(got >= 0); - - if (ctx->params->dump_fmt) - for (i = 0; i < got; ++i) { - freq[i + j] = *f; - rx[i + j] = buffer[i]; - } - - if ((j % (17 * 25)) == 0) - SU_INFO("Center frequency: %lg Hz\r", SU_NORM2ABS_FREQ(*samp_rate, *f)); - j += got; - } - - SU_INFO("\n"); - SU_TEST_ASSERT(SU_NORM2ABS_FREQ(*samp_rate, *f) > 909 && - SU_NORM2ABS_FREQ(*samp_rate, *f) < 911); - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - if (su_block_port_is_plugged(&port)) - su_block_port_unplug(&port); - - if (costas_block != NULL) - su_block_destroy(costas_block); - - if (agc_block != NULL) - su_block_destroy(agc_block); - - if (wav_block != NULL) - su_block_destroy(wav_block); - - return ok; -} - -SUBOOL -su_test_rrc_block(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *costas_block = NULL; - su_block_t *agc_block = NULL; - su_block_t *rrc_block = NULL; - su_block_t *wav_block = NULL; - su_block_port_t port = su_block_port_INITIALIZER; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - SUCOMPLEX buffer[17]; /* Prime number on purpose */ - SUCOMPLEX *rx = NULL; - SUFLOAT *freq = NULL; - SUFLOAT samp = 0; - int i; - unsigned int j = 0; - SUSDIFF got; - - /* Signal properties */ - const SUFLOAT baud = 468; - const SUFLOAT arm_bw = 2 * baud; - const unsigned int arm_order = 3; - const SUFLOAT loop_bw = 1e-1 * baud; - const unsigned int sample_count = 8000 * 59; - /* Block properties */ - int *samp_rate; - SUFLOAT *f; - SUFLOAT *gain; - unsigned int *size; - - SU_TEST_START(ctx); - - SU_TEST_ASSERT(freq = su_test_ctx_getf_w_size(ctx, "freq", sample_count)); - SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", sample_count)); - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - wav_block = su_block_new("wavfile", "test.wav"); - SU_TEST_ASSERT(wav_block != NULL); - - samp_rate = su_block_get_property_ref( - wav_block, - SU_PROPERTY_TYPE_INTEGER, - "samp_rate"); - SU_TEST_ASSERT(samp_rate != NULL); - SU_TEST_ASSERT(*samp_rate == 8000); - - SU_INFO("Wav file opened, sample rate: %d\n", *samp_rate); - - agc_block = su_block_new("agc", &agc_params); - SU_TEST_ASSERT(agc_block != NULL); - - rrc_block = su_block_new( - "rrc", - (unsigned int) (4. * 8000. / (SUFLOAT) baud), - SU_T2N_FLOAT(8000, 1. / 468), - 0.75); - SU_TEST_ASSERT(rrc_block != NULL); - - costas_block = su_block_new( - "costas", - SU_COSTAS_KIND_QPSK, - SU_ABS2NORM_FREQ(*samp_rate, 900), - SU_ABS2NORM_FREQ(*samp_rate, arm_bw), - arm_order, - SU_ABS2NORM_FREQ(*samp_rate, loop_bw)); - SU_TEST_ASSERT(costas_block != NULL); - - f = su_block_get_property_ref( - costas_block, - SU_PROPERTY_TYPE_FLOAT, - "f"); - SU_TEST_ASSERT(f != NULL); - - gain = su_block_get_property_ref( - rrc_block, - SU_PROPERTY_TYPE_FLOAT, - "gain"); - SU_TEST_ASSERT(gain != NULL); - - SU_INFO( - "Costas loop created, initial frequency: %lg Hz\n", - SU_NORM2ABS_FREQ(*samp_rate, *f)); - - SU_INFO("RRC filter gain: %lg\n", *gain); - - /* Plug wav file directly to AGC (there should be a tuner before this) */ - SU_TEST_ASSERT(su_block_plug(wav_block, 0, 0, agc_block)); - - /* Plug AGC to Costas loop */ - SU_TEST_ASSERT(su_block_plug(agc_block, 0, 0, costas_block)); - - /* Plug Costas loop to RRC filter */ - SU_TEST_ASSERT(su_block_plug(costas_block, 0, 0, rrc_block)); - - /* Plug RRC filter to reading port */ - SU_TEST_ASSERT(su_block_port_plug(&port, rrc_block, 0)); - - /* Try to read (this must work) */ - while (j < sample_count) { - got = su_block_port_read(&port, buffer, 1); - SU_TEST_ASSERT(got >= 0); - - if (ctx->params->dump_fmt) - for (i = 0; i < got; ++i) { - freq[i + j] = *f; - rx[i + j] = buffer[i]; - } - - if ((j % (17 * 25)) == 0) - SU_INFO("Center frequency: %lg Hz\r", SU_NORM2ABS_FREQ(*samp_rate, *f)); - j += got; - } - - SU_INFO("\n"); - SU_TEST_ASSERT(SU_NORM2ABS_FREQ(*samp_rate, *f) > 909 && - SU_NORM2ABS_FREQ(*samp_rate, *f) < 911); - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - if (su_block_port_is_plugged(&port)) - su_block_port_unplug(&port); - - if (rrc_block != NULL) - su_block_destroy(rrc_block); - - if (costas_block != NULL) - su_block_destroy(costas_block); - - if (agc_block != NULL) - su_block_destroy(agc_block); - - if (wav_block != NULL) - su_block_destroy(wav_block); - - return ok; -} - -SUBOOL -su_test_rrc_block_with_if(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *rrc_block = NULL; - su_block_t *costas_block = NULL; - su_block_t *agc_block = NULL; - su_block_t *tuner_block = NULL; - su_block_t *wav_block = NULL; - su_block_port_t port = su_block_port_INITIALIZER; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - SUCOMPLEX buffer[17]; /* Prime number on purpose */ - SUFLOAT samp = 0; - SUFLOAT *freq = NULL; - SUCOMPLEX *rx = NULL; - int i; - unsigned int j = 0; - SUSDIFF got; - - /* Signal properties */ - const SUFLOAT baud = 468; - const SUFLOAT arm_bw = 2 * baud; - const unsigned int arm_order = 3; - const SUFLOAT loop_bw = 1e-1 * baud; - const unsigned int sample_count = 8000 * 59; - const SUFLOAT if_off = 4000; /* IF: 1000 Hz */ - const SUFLOAT fc = 912; /* FC: 912 Hz */ - /* Block properties */ - int *samp_rate; - SUFLOAT *f; - SUFLOAT *gain; - SUFLOAT *taps; - unsigned int *size; - - SU_TEST_START(ctx); - - SU_TEST_ASSERT(freq = su_test_ctx_getf_w_size(ctx, "freq", sample_count)); - SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", sample_count)); - - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 1000; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - wav_block = su_block_new("wavfile", "test.wav"); - SU_TEST_ASSERT(wav_block != NULL); - - samp_rate = su_block_get_property_ref( - wav_block, - SU_PROPERTY_TYPE_INTEGER, - "samp_rate"); - SU_TEST_ASSERT(samp_rate != NULL); - SU_TEST_ASSERT(*samp_rate == 8000); - - SU_INFO("Wav file opened, sample rate: %d\n", *samp_rate); - - tuner_block = su_block_new( - "tuner", - SU_ABS2NORM_FREQ(*samp_rate, fc), /* Center frequency */ - SU_ABS2NORM_FREQ(*samp_rate, baud), /* Signal is 468 baud */ - SU_ABS2NORM_FREQ(*samp_rate, if_off), /* Move signal to 2 KHz */ - (unsigned int) (6 * SU_T2N_FLOAT(*samp_rate, 1. / baud))); - SU_TEST_ASSERT(tuner_block != NULL); - - size = su_block_get_property_ref( - tuner_block, - SU_PROPERTY_TYPE_INTEGER, - "size"); - SU_TEST_ASSERT(size != NULL); - - taps = su_block_get_property_ref( - tuner_block, - SU_PROPERTY_TYPE_FLOAT, - "taps"); - SU_TEST_ASSERT(taps != NULL); - - agc_block = su_block_new("agc", &agc_params); - SU_TEST_ASSERT(agc_block != NULL); - - costas_block = su_block_new( - "costas", - SU_COSTAS_KIND_QPSK, - SU_ABS2NORM_FREQ(*samp_rate, if_off), - SU_ABS2NORM_FREQ(*samp_rate, arm_bw), - arm_order, - SU_ABS2NORM_FREQ(*samp_rate, loop_bw)); - SU_TEST_ASSERT(costas_block != NULL); - - f = su_block_get_property_ref( - costas_block, - SU_PROPERTY_TYPE_FLOAT, - "f"); - SU_TEST_ASSERT(f != NULL); - - rrc_block = su_block_new( - "rrc", - (unsigned int) (6 * SU_T2N_FLOAT(*samp_rate, 1. / baud)), - SU_T2N_FLOAT(*samp_rate, 1. / baud), - 1); - SU_TEST_ASSERT(rrc_block != NULL); - - gain = su_block_get_property_ref( - rrc_block, - SU_PROPERTY_TYPE_FLOAT, - "gain"); - SU_TEST_ASSERT(gain != NULL); - - *gain = .707; - SU_INFO( - "Costas loop created, initial frequency: %lg Hz\n", - SU_NORM2ABS_FREQ(*samp_rate, *f)); - - SU_INFO("RRC filter gain: %lg\n", *gain); - - /* Plug wav file directly to tuner */ - SU_TEST_ASSERT(su_block_plug(wav_block, 0, 0, tuner_block)); - - /* Plug tuner to AGC */ - SU_TEST_ASSERT(su_block_plug(tuner_block, 0, 0, agc_block)); - - /* Plug AGC to Costas loop */ - SU_TEST_ASSERT(su_block_plug(agc_block, 0, 0, costas_block)); - - /* Plug Costas loop to RRC filter */ - SU_TEST_ASSERT(su_block_plug(costas_block, 0, 0, rrc_block)); - - /* Plug RRC filter to reading port */ - SU_TEST_ASSERT(su_block_port_plug(&port, rrc_block, 0)); - - /* Try to read (this must work) */ - while (j < sample_count) { - got = su_block_port_read(&port, buffer, 1); - SU_TEST_ASSERT(got >= 0); - - if (ctx->params->dump_fmt) - for (i = 0; i < got; ++i) { - freq[i + j] = *f; - rx[i + j] = buffer[i]; - } - - if ((j % (17 * 25)) == 0) - SU_INFO("Center frequency: %lg Hz\r", SU_NORM2ABS_FREQ(*samp_rate, *f)); - j += got; - } - - SU_INFO("\n"); - SU_TEST_ASSERT(SU_NORM2ABS_FREQ(*samp_rate, *f) < 1.01 * if_off && - SU_NORM2ABS_FREQ(*samp_rate, *f) > 0.99 * if_off); - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - if (su_block_port_is_plugged(&port)) - su_block_port_unplug(&port); - - if (rrc_block != NULL) - su_block_destroy(rrc_block); - - if (costas_block != NULL) - su_block_destroy(costas_block); - - if (agc_block != NULL) - su_block_destroy(agc_block); - - if (tuner_block != NULL) { - if (ctx->params->dump_fmt && taps != NULL && size != NULL) { - ok = ok && su_test_ctx_dumpf(ctx, "bpf", taps, *size); - } - su_block_destroy(tuner_block); - } - - if (wav_block != NULL) - su_block_destroy(wav_block); - - return ok; -} - SUPRIVATE SUFLOAT su_test_cdr_block_symbol_uncertainty(SUCOMPLEX symbol) { @@ -892,235 +37,9 @@ su_test_cdr_block_symbol_uncertainty(SUCOMPLEX symbol) unsigned int i = 0; SUFLOAT dist = INFINITY; - for (i = 0; i < sizeof (symbols) / sizeof (SUCOMPLEX); ++i) + for (i = 0; i < sizeof(symbols) / sizeof(SUCOMPLEX); ++i) if (SU_C_ABS(symbol - symbols[i]) < dist) dist = SU_C_ABS(symbol - symbols[i]); return dist; } - -SUBOOL -su_test_cdr_block(su_test_context_t *ctx) -{ - SUBOOL ok = SU_FALSE; - su_block_t *cdr_block = NULL; - su_block_t *costas_block = NULL; - su_block_t *agc_block = NULL; - su_block_t *rrc_block = NULL; - su_block_t *wav_block = NULL; - su_block_port_t port = su_block_port_INITIALIZER; - struct su_agc_params agc_params = su_agc_params_INITIALIZER; - SUCOMPLEX buffer[17]; /* Prime number on purpose */ - SUCOMPLEX *rx = NULL; - SUFLOAT *freq = NULL; - SUFLOAT *unc = NULL; - SUFLOAT samp = 0; - int i; - unsigned int j = 0; - SUSCOUNT uncp = 0; - SUSDIFF got; - - /* Signal properties */ - const SUFLOAT baud = 468; - const SUFLOAT arm_bw = 2 * baud; - const SUSCOUNT arm_order = 3; - const SUFLOAT loop_bw = 1e-1 * baud; - const SUSCOUNT sample_count = 8000 * 59; - const SUSCOUNT unc_measure_size = 100; - - /* Block properties */ - int *samp_rate; - SUFLOAT *f; - SUFLOAT *gain; - SUFLOAT *bmax, *bmin, *beta, *alpha, *bnor; - unsigned int *size; - - SU_TEST_START(ctx); - - SU_TEST_ASSERT(freq = su_test_ctx_getf_w_size(ctx, "freq", sample_count)); - SU_TEST_ASSERT(unc = su_test_ctx_getf_w_size( - ctx, - "unc", - SU_CEIL(sample_count / (SUFLOAT) unc_measure_size))); - SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", sample_count)); - - agc_params.delay_line_size = 10; - agc_params.mag_history_size = 10; - agc_params.fast_rise_t = 2; - agc_params.fast_fall_t = 4; - - agc_params.slow_rise_t = 20; - agc_params.slow_fall_t = 40; - - agc_params.threshold = SU_DB(2e-2); - - agc_params.hang_max = 30; - agc_params.slope_factor = 0; - - wav_block = su_block_new("wavfile", "test.wav"); - SU_TEST_ASSERT(wav_block != NULL); - - samp_rate = su_block_get_property_ref( - wav_block, - SU_PROPERTY_TYPE_INTEGER, - "samp_rate"); - SU_TEST_ASSERT(samp_rate != NULL); - SU_TEST_ASSERT(*samp_rate == 8000); - - SU_INFO("Wav file opened, sample rate: %d\n", *samp_rate); - - agc_block = su_block_new("agc", &agc_params); - SU_TEST_ASSERT(agc_block != NULL); - - rrc_block = su_block_new( - "rrc", - (unsigned int) (4. * 8000. / (SUFLOAT) baud), - SU_T2N_FLOAT(8000, 1. / baud), - 0.25); - SU_TEST_ASSERT(rrc_block != NULL); - - costas_block = su_block_new( - "costas", - SU_COSTAS_KIND_QPSK, - SU_ABS2NORM_FREQ(*samp_rate, 910), - SU_ABS2NORM_FREQ(*samp_rate, arm_bw), - arm_order, - SU_ABS2NORM_FREQ(*samp_rate, loop_bw)); - SU_TEST_ASSERT(costas_block != NULL); - - cdr_block = su_block_new( - "cdr", - (SUFLOAT) 1., - SU_ABS2NORM_BAUD(*samp_rate, baud), - (SUSCOUNT) 15); - SU_TEST_ASSERT(costas_block != NULL); - - beta = su_block_get_property_ref( - cdr_block, - SU_PROPERTY_TYPE_FLOAT, - "beta"); - SU_TEST_ASSERT(beta != NULL); - - alpha = su_block_get_property_ref( - cdr_block, - SU_PROPERTY_TYPE_FLOAT, - "alpha"); - SU_TEST_ASSERT(alpha != NULL); - - bnor = su_block_get_property_ref( - cdr_block, - SU_PROPERTY_TYPE_FLOAT, - "bnor"); - SU_TEST_ASSERT(bnor != NULL); - - bmax = su_block_get_property_ref( - cdr_block, - SU_PROPERTY_TYPE_FLOAT, - "bmax"); - SU_TEST_ASSERT(bmax != NULL); - - bmin = su_block_get_property_ref( - cdr_block, - SU_PROPERTY_TYPE_FLOAT, - "bmin"); - SU_TEST_ASSERT(bmin != NULL); - - f = su_block_get_property_ref( - costas_block, - SU_PROPERTY_TYPE_FLOAT, - "f"); - SU_TEST_ASSERT(f != NULL); - - gain = su_block_get_property_ref( - rrc_block, - SU_PROPERTY_TYPE_FLOAT, - "gain"); - SU_TEST_ASSERT(gain != NULL); - - *gain = 5; - *beta = 0; - *alpha *= .75; - - *bmin = SU_ABS2NORM_BAUD(*samp_rate, baud - 10); - *bmax = SU_ABS2NORM_BAUD(*samp_rate, baud + 10); - - SU_INFO( - "Costas loop created, initial frequency: %lg Hz\n", - SU_NORM2ABS_FREQ(*samp_rate, *f)); - - SU_INFO("RRC filter gain: %lg\n", *gain); - - /* Plug wav file directly to AGC (there should be a tuner before this) */ - SU_TEST_ASSERT(su_block_plug(wav_block, 0, 0, agc_block)); - - /* Plug AGC to Costas loop */ - SU_TEST_ASSERT(su_block_plug(agc_block, 0, 0, costas_block)); - - /* Plug Costas loop to RRC filter */ - SU_TEST_ASSERT(su_block_plug(costas_block, 0, 0, rrc_block)); - - /* Plug RRC filter to CDR */ - SU_TEST_ASSERT(su_block_plug(rrc_block, 0, 0, cdr_block)); - - /* Plug CDR to reading port */ - SU_TEST_ASSERT(su_block_port_plug(&port, cdr_block, 0)); - - /* Try to read (this must work) */ - unc[uncp] = 0; - - while (j < sample_count && (j == 0 || got > 0)) { - got = su_block_port_read(&port, buffer, 1); - SU_TEST_ASSERT(got >= 0); - - if (ctx->params->dump_fmt) - for (i = 0; i < got; ++i) { - freq[i + j] = *f; - rx[i + j] = buffer[i]; - unc[uncp] += - su_test_cdr_block_symbol_uncertainty(buffer[i]) / unc_measure_size; - if (((i + j + 1) % unc_measure_size) == 0) - unc[++uncp] = 0; - } - - if ((j % (17 * 25)) == 0) - SU_INFO( - "L: %5.2lf Hz, B: %5.2lf baud\r", - SU_NORM2ABS_FREQ(*samp_rate, *f), - SU_NORM2ABS_FREQ(*samp_rate, *bnor)); - j += got; - } - - SU_INFO("\n"); - SU_TEST_ASSERT(su_test_ctx_resize_buf(ctx, "rx", j)); - SU_TEST_ASSERT(su_test_ctx_resize_buf(ctx, "freq", j)); - SU_TEST_ASSERT(su_test_ctx_resize_buf(ctx, "unc", uncp + 1)); - - SU_TEST_ASSERT(SU_NORM2ABS_FREQ(*samp_rate, *f) > 909 && - SU_NORM2ABS_FREQ(*samp_rate, *f) < 911); - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - if (su_block_port_is_plugged(&port)) - su_block_port_unplug(&port); - - if (cdr_block != NULL) - su_block_destroy(cdr_block); - - if (rrc_block != NULL) - su_block_destroy(rrc_block); - - if (costas_block != NULL) - su_block_destroy(costas_block); - - if (agc_block != NULL) - su_block_destroy(agc_block); - - if (wav_block != NULL) - su_block_destroy(wav_block); - - return ok; -} - diff --git a/src/tests/clock.c b/src/tests/clock.c index a3ee8b5..1ffaea1 100644 --- a/src/tests/clock.c +++ b/src/tests/clock.c @@ -17,17 +17,16 @@ */ -#include -#include -#include - -#include -#include -#include #include -#include #include +#include +#include +#include +#include #include +#include +#include +#include #include "test_list.h" #include "test_param.h" @@ -59,48 +58,45 @@ __su_test_clock_recovery(su_test_context_t *ctx, SUBOOL noisy) unsigned int msgbuf; unsigned int rx_delay; - unsigned int rx_buf = 0; su_ncqo_t ncqo = su_ncqo_INITIALIZER; su_costas_t costas = su_costas_INITIALIZER; su_iir_filt_t mf = su_iir_filt_INITIALIZER; su_clock_detector_t cd = su_clock_detector_INITIALIZER; unsigned int p = 0; - unsigned int t = 0; unsigned int sym; unsigned int n = 0; unsigned int rx_count = 0; unsigned int rx_size; - int permutations = 0; SU_TEST_START_TICKLESS(ctx); /* Initialize some parameters */ symbol_period = SU_TEST_COSTAS_SYMBOL_PERIOD; filter_period = SU_TEST_MF_SYMBOL_SPAN * symbol_period; /* Span: 6 symbols */ - sync_period = 1 * 4096; /* Number of samples to allow loop to synchronize */ - message = 0x414c4f48; /* Some greeting message */ - rx_delay = filter_period + sync_period - symbol_period / 2; - rx_size = SU_CEIL((SUFLOAT) (ctx->params->buffer_size - rx_delay) - / symbol_period); + sync_period = 1 * 4096; /* Number of samples to allow loop to synchronize */ + message = 0x414c4f48; /* Some greeting message */ + rx_delay = filter_period + sync_period - symbol_period / 2; + rx_size = + SU_CEIL((SUFLOAT)(ctx->params->buffer_size - rx_delay) / symbol_period); if (noisy) - N0 = SU_MAG_RAW(-56) * symbol_period * 4; + N0 = SU_MAG_RAW(-56) * symbol_period * 4; else - N0 = SU_MAG_RAW(-70) * symbol_period * 4; + N0 = SU_MAG_RAW(-70) * symbol_period * 4; - phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ + phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ /* Initialize buffers */ - SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); + SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); SU_TEST_ASSERT(carrier = su_test_ctx_getc(ctx, "carrier")); - SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); - SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); - SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); - SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", rx_size)); - SU_TEST_ASSERT(baud = su_test_ctx_getc(ctx, "baud")); - SU_TEST_ASSERT(data = su_test_ctx_getc(ctx, "data")); - SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); + SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); + SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); + SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); + SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", rx_size)); + SU_TEST_ASSERT(baud = su_test_ctx_getc(ctx, "baud")); + SU_TEST_ASSERT(data = su_test_ctx_getc(ctx, "data")); + SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); /* * In noisy test we assume we are on lock, we just want to retrieve @@ -109,9 +105,8 @@ __su_test_clock_recovery(su_test_context_t *ctx, SUBOOL noisy) SU_TEST_ASSERT(su_costas_init( &costas, SU_COSTAS_KIND_QPSK, - noisy ? - SU_TEST_COSTAS_SIGNAL_FREQ : - SU_TEST_COSTAS_SIGNAL_FREQ + .05 * SU_TEST_COSTAS_BANDWIDTH, + noisy ? SU_TEST_COSTAS_SIGNAL_FREQ + : SU_TEST_COSTAS_SIGNAL_FREQ + .05 * SU_TEST_COSTAS_BANDWIDTH, 6 * SU_TEST_COSTAS_BANDWIDTH, 3, 2e-1 * SU_TEST_COSTAS_BANDWIDTH)); @@ -121,18 +116,10 @@ __su_test_clock_recovery(su_test_context_t *ctx, SUBOOL noisy) SU_INFO("Initial frequency error: %lg\n", costas.ncqo.fnor - ncqo.fnor); #ifndef SU_TEST_COSTAS_USE_RRC - SU_TEST_ASSERT( - su_iir_rrc_init( - &mf, - filter_period, - symbol_period, - 1)); + SU_TEST_ASSERT(su_iir_rrc_init(&mf, filter_period, symbol_period, 1)); #else SU_TEST_ASSERT( - su_iir_brickwall_init( - &mf, - filter_period, - SU_TEST_COSTAS_BANDWIDTH)); + su_iir_brickwall_init(&mf, filter_period, SU_TEST_COSTAS_BANDWIDTH)); #endif /* Send data */ @@ -142,19 +129,19 @@ __su_test_clock_recovery(su_test_context_t *ctx, SUBOOL noisy) for (p = 0; p < ctx->params->buffer_size; ++p) { if (p >= sync_period) { if (p % symbol_period == 0) { - if (n == 32) - n = 0; - msgbuf = message >> n; - sym = msgbuf & 3; - n += 2; - bbs = symbol_period * symbols[sym]; - } else { - bbs = 0; - } + if (n == 32) + n = 0; + msgbuf = message >> n; + sym = msgbuf & 3; + n += 2; + bbs = symbol_period * symbols[sym]; } else { - /* Send first symbol to synchronize */ - bbs = symbols[1]; + bbs = 0; } + } else { + /* Send first symbol to synchronize */ + bbs = symbols[1]; + } data[p] = bbs; input[p] = su_iir_filt_feed(&mf, data[p]); @@ -167,23 +154,19 @@ __su_test_clock_recovery(su_test_context_t *ctx, SUBOOL noisy) SU_TEST_TICK(ctx); SU_TEST_ASSERT( - su_clock_detector_init( - &cd, - 1, - 1.2 / (SU_TEST_COSTAS_SYMBOL_PERIOD), - 15)); + su_clock_detector_init(&cd, 1, 1.2 / (SU_TEST_COSTAS_SYMBOL_PERIOD), 15)); SU_INFO("Symbol period hint: %lg\n", 1. / cd.bnor); /* Feed the loop and perform demodulation */ for (p = 0; p < ctx->params->buffer_size; ++p) { - (void) su_ncqo_step(&ncqo); - su_costas_feed(&costas, tx[p]); + (void)su_ncqo_step(&ncqo); + su_costas_feed(&costas, tx[p]); carrier[p] = su_ncqo_get(&costas.ncqo); - output[p] = su_iir_filt_feed(&mf, costas.y); - lock[p] = costas.lock; - omgerr[p] = costas.ncqo.fnor - ncqo.fnor; - baud[p] = cd.e + I * cd.bnor; + output[p] = su_iir_filt_feed(&mf, costas.y); + lock[p] = costas.lock; + omgerr[p] = costas.ncqo.fnor - ncqo.fnor; + baud[p] = cd.e + I * cd.bnor; if (p >= rx_delay) { /* Send sample to clock detector */ diff --git a/src/tests/codec.c b/src/tests/codec.c deleted file mode 100644 index 9546a96..0000000 --- a/src/tests/codec.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - - Copyright (C) 2016 Gonzalo José Carracedo Carballal - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, version 3. - - 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 Lesser 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 - - -*/ - -#include -#include -#include - -#include - -#include "test_list.h" -#include "test_param.h" - -SUPRIVATE char -su_test_symbol_to_char(SUSYMBOL sym) -{ - switch (sym) { - case SU_NOSYMBOL: - return ' '; - - case SU_EOS: - return '%'; - - default: - return sym; - } -} - -SUBOOL -su_test_diff_codec_generic( - su_test_context_t *ctx, - unsigned int bits, - SUBOOL sign) -{ - su_codec_t *encoder = NULL; - su_codec_t *decoder = NULL; - SUSYMBOL syms[SU_TEST_ENCODER_NUM_SYMS + 1] = {}; - SUSYMBOL encoded, decoded; - SUSCOUNT len; - unsigned int i; - - SUBOOL ok = SU_FALSE; - - SU_TEST_START(ctx); - - /* Initialize symbol list */ - for (i = 0; i < SU_TEST_ENCODER_NUM_SYMS; ++i) - syms[i] = SU_TOSYM(rand() & ((1 << bits) - 1)); - syms[i] = SU_EOS; - - /* Create differential codec, 1 bit */ - SU_TEST_ASSERT(encoder = su_codec_new("diff", bits, sign)); - SU_TEST_ASSERT(decoder = su_codec_new("diff", bits, sign)); - - /* Set encode mode */ - su_codec_set_direction(encoder, SU_CODEC_DIRECTION_FORWARDS); - su_codec_set_direction(decoder, SU_CODEC_DIRECTION_BACKWARDS); - - len = sizeof(syms) / sizeof(syms[0]); - for (i = 0; i < len; ++i) { - encoded = su_codec_feed(encoder, syms[i]); - decoded = su_codec_feed(decoder, encoded); - - SU_INFO( - "'%c' --> ENCODER --> '%c' --> DECODER --> '%c'\n", - su_test_symbol_to_char(syms[i]), - su_test_symbol_to_char(encoded), - su_test_symbol_to_char(decoded)); - - if (i > 0) - SU_TEST_ASSERT(syms[i] == decoded); - } - - ok = SU_TRUE; - -done: - SU_TEST_END(ctx); - - if (encoder != NULL) - su_codec_destroy(encoder); - if (decoder != NULL) - su_codec_destroy(decoder); - - return ok; -} - -SUBOOL -su_test_diff_codec_binary(su_test_context_t *ctx) -{ - return su_test_diff_codec_generic(ctx, 1, SU_FALSE); -} - -SUBOOL -su_test_diff_codec_quaternary(su_test_context_t *ctx) -{ - return su_test_diff_codec_generic(ctx, 2, SU_FALSE); -} - diff --git a/src/tests/costas.c b/src/tests/costas.c index 8111550..23c0f04 100644 --- a/src/tests/costas.c +++ b/src/tests/costas.c @@ -17,17 +17,15 @@ */ -#include -#include -#include - -#include -#include -#include #include +#include +#include #include - +#include #include +#include +#include +#include #include "test_list.h" #include "test_param.h" @@ -43,7 +41,6 @@ su_test_costas_lock(su_test_context_t *ctx) SUFLOAT *omgerr = NULL; SUFLOAT *lock = NULL; SUFLOAT N0; - SUFLOAT t; SUFLOAT Ef = 0; su_ncqo_t ncqo = su_ncqo_INITIALIZER; su_costas_t costas = su_costas_INITIALIZER; @@ -52,12 +49,12 @@ su_test_costas_lock(su_test_context_t *ctx) SU_TEST_START_TICKLESS(ctx); /* Initialize buffers */ - SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); + SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); SU_TEST_ASSERT(carrier = su_test_ctx_getc(ctx, "carrier")); - SU_TEST_ASSERT(phierr = su_test_ctx_getf(ctx, "pe")); - SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); - SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); - SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); + SU_TEST_ASSERT(phierr = su_test_ctx_getf(ctx, "pe")); + SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); + SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); + SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); N0 = 5e-1; @@ -69,7 +66,6 @@ su_test_costas_lock(su_test_context_t *ctx) 1, /* Disable arm filter */ 1e-2)); - su_ncqo_init(&ncqo, SU_TEST_COSTAS_SIGNAL_FREQ); /* Build noisy signal */ @@ -86,12 +82,12 @@ su_test_costas_lock(su_test_context_t *ctx) /* Feed the PLL and save phase value */ for (p = 0; p < ctx->params->buffer_size; ++p) { - (void) su_ncqo_read(&ncqo); /* Used to compute phase errors */ + (void)su_ncqo_read(&ncqo); /* Used to compute phase errors */ su_costas_feed(&costas, input[p]); carrier[p] = su_ncqo_get(&costas.ncqo); - output[p] = costas.y; - phierr[p] = su_ncqo_get_phase(&costas.ncqo) - su_ncqo_get_phase(&ncqo); - lock[p] = costas.lock; + output[p] = costas.y; + phierr[p] = su_ncqo_get_phase(&costas.ncqo) - su_ncqo_get_phase(&ncqo); + lock[p] = costas.lock; if (phierr[p] < 0 || phierr[p] > 2 * PI) { phierr[p] -= 2 * PI * floor(phierr[p] / (2 * PI)); @@ -154,34 +150,31 @@ su_test_costas_bpsk(su_test_context_t *ctx) unsigned int t = 0; unsigned int bit; unsigned int rx_count = 0; - unsigned int tx_count = 0; unsigned int rx_size; - unsigned int tx_size; SU_TEST_START_TICKLESS(ctx); /* Initialize some parameters */ symbol_period = SU_TEST_COSTAS_SYMBOL_PERIOD; filter_period = SU_TEST_MF_SYMBOL_SPAN * symbol_period; - sync_period = 4096; /* Number of samples to allow loop to synchronize */ - message = 0x414c4f48; /* Some greeting message */ - rx_delay = filter_period + sync_period; - rx_size = SU_CEIL((SUFLOAT) (ctx->params->buffer_size - rx_delay) - / symbol_period); - tx_size = SU_CEIL((SUFLOAT) ctx->params->buffer_size / symbol_period); - N0 = .1; /* Noise amplitude */ - phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ + sync_period = 4096; /* Number of samples to allow loop to synchronize */ + message = 0x414c4f48; /* Some greeting message */ + rx_delay = filter_period + sync_period; + rx_size = + SU_CEIL((SUFLOAT)(ctx->params->buffer_size - rx_delay) / symbol_period); + N0 = .1; /* Noise amplitude */ + phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ /* Initialize buffers */ - SU_TEST_ASSERT(data = su_test_ctx_getf(ctx, "data")); - SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); - SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); + SU_TEST_ASSERT(data = su_test_ctx_getf(ctx, "data")); + SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); + SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); SU_TEST_ASSERT(carrier = su_test_ctx_getc(ctx, "carrier")); - SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); - SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); - SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); - SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); - SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", rx_size)); + SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); + SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); + SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); + SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); + SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", rx_size)); SU_TEST_ASSERT(su_costas_init( &costas, @@ -194,12 +187,7 @@ su_test_costas_bpsk(su_test_context_t *ctx) su_ncqo_init(&ncqo, SU_TEST_COSTAS_SIGNAL_FREQ); /* Create Root-Raised-Cosine filter. We will use this to reduce ISI */ - SU_TEST_ASSERT( - su_iir_rrc_init( - &mf, - filter_period, - symbol_period, - 0.35)); + SU_TEST_ASSERT(su_iir_rrc_init(&mf, filter_period, symbol_period, 0.35)); /* Send data */ msgbuf = message; @@ -208,15 +196,15 @@ su_test_costas_bpsk(su_test_context_t *ctx) for (p = 0; p < ctx->params->buffer_size; ++p) { if (p >= sync_period) { if (p % symbol_period == 0) { - bit = msgbuf & 1; - msgbuf >>= 1; - bbs = symbol_period * symbols[bit]; - } else { - bbs = 0; - } + bit = msgbuf & 1; + msgbuf >>= 1; + bbs = symbol_period * symbols[bit]; } else { - bbs = symbols[1]; + bbs = 0; } + } else { + bbs = symbols[1]; + } data[p] = bbs; input[p] = su_iir_filt_feed(&mf, data[p]); @@ -230,12 +218,12 @@ su_test_costas_bpsk(su_test_context_t *ctx) /* Feed the loop and perform demodulation */ for (p = 0; p < ctx->params->buffer_size; ++p) { - (void) su_ncqo_step(&ncqo); + (void)su_ncqo_step(&ncqo); su_costas_feed(&costas, tx[p]); carrier[p] = su_ncqo_get(&costas.ncqo); - output[p] = su_iir_filt_feed(&mf, costas.y); - lock[p] = costas.lock; - omgerr[p] = costas.ncqo.fnor - ncqo.fnor; + output[p] = su_iir_filt_feed(&mf, costas.y); + lock[p] = costas.lock; + omgerr[p] = costas.ncqo.fnor - ncqo.fnor; if (p % symbol_period == 0) { if (p >= rx_delay) { @@ -265,9 +253,9 @@ su_test_costas_bpsk(su_test_context_t *ctx) su_costas_finalize(&costas); - if (ctx->params->dump_fmt) - if (mf.x_size > 0) - ok = ok && su_test_ctx_dumpf(ctx, "mf", mf.b, mf.x_size); + if (ctx->params->dump_fmt) + if (mf.x_size > 0) + ok = ok && su_test_ctx_dumpf(ctx, "mf", mf.b, mf.x_size); su_iir_filt_finalize(&mf); @@ -304,7 +292,6 @@ su_test_rotcompare(uint32_t original, uint32_t recv) { unsigned char msgsym[16]; unsigned char map[4] = {0, 1, 2, 3}; - unsigned char tmp; unsigned int n; unsigned int i, j, k; int count = 0; @@ -364,8 +351,6 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) SUCOMPLEX *tx = NULL; SUCOMPLEX *data = NULL; SUCOMPLEX bbs = 1; - SUCOMPLEX symsamp = 0; - SUFLOAT mean_baud = 0; SUCOMPLEX symbols[] = {1, I, -1, -I}; SUCOMPLEX phi0 = 1; @@ -394,27 +379,27 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) /* Initialize some parameters */ symbol_period = SU_TEST_COSTAS_SYMBOL_PERIOD; filter_period = SU_TEST_MF_SYMBOL_SPAN * symbol_period; /* Span: 6 symbols */ - sync_period = 1 * 4096; /* Number of samples to allow loop to synchronize */ - message = 0x414c4f48; /* Some greeting message */ - rx_delay = filter_period + sync_period - symbol_period / 2; - rx_size = SU_CEIL((SUFLOAT) (ctx->params->buffer_size - rx_delay) - / symbol_period); + sync_period = 1 * 4096; /* Number of samples to allow loop to synchronize */ + message = 0x414c4f48; /* Some greeting message */ + rx_delay = filter_period + sync_period - symbol_period / 2; + rx_size = + SU_CEIL((SUFLOAT)(ctx->params->buffer_size - rx_delay) / symbol_period); if (noisy) - N0 = SU_MAG_RAW(-56) * symbol_period * 4; + N0 = SU_MAG_RAW(-56) * symbol_period * 4; else - N0 = SU_MAG_RAW(-70) * symbol_period * 4; + N0 = SU_MAG_RAW(-70) * symbol_period * 4; - phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ + phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ /* Initialize buffers */ - SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); + SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); SU_TEST_ASSERT(carrier = su_test_ctx_getc(ctx, "carrier")); - SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); - SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); - SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); - SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", rx_size)); - SU_TEST_ASSERT(data = su_test_ctx_getc(ctx, "data")); - SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); + SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); + SU_TEST_ASSERT(output = su_test_ctx_getc(ctx, "y")); + SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); + SU_TEST_ASSERT(rx = su_test_ctx_getc_w_size(ctx, "rx", rx_size)); + SU_TEST_ASSERT(data = su_test_ctx_getc(ctx, "data")); + SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); /* * In noisy test we assume we are on lock, we just want to retrieve @@ -423,9 +408,8 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) SU_TEST_ASSERT(su_costas_init( &costas, SU_COSTAS_KIND_QPSK, - noisy ? - SU_TEST_COSTAS_SIGNAL_FREQ : - SU_TEST_COSTAS_SIGNAL_FREQ + .05 * SU_TEST_COSTAS_BANDWIDTH, + noisy ? SU_TEST_COSTAS_SIGNAL_FREQ + : SU_TEST_COSTAS_SIGNAL_FREQ + .05 * SU_TEST_COSTAS_BANDWIDTH, 6 * SU_TEST_COSTAS_BANDWIDTH, 3, 2e-1 * SU_TEST_COSTAS_BANDWIDTH)); @@ -435,18 +419,10 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) SU_INFO("Initial frequency error: %lg\n", costas.ncqo.fnor - ncqo.fnor); #ifndef SU_TEST_COSTAS_USE_RRC - SU_TEST_ASSERT( - su_iir_rrc_init( - &mf, - filter_period, - symbol_period, - 1)); + SU_TEST_ASSERT(su_iir_rrc_init(&mf, filter_period, symbol_period, 1)); #else SU_TEST_ASSERT( - su_iir_brickwall_init( - &mf, - filter_period, - SU_TEST_COSTAS_BANDWIDTH)); + su_iir_brickwall_init(&mf, filter_period, SU_TEST_COSTAS_BANDWIDTH)); #endif /* Send data */ @@ -456,19 +432,19 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) for (p = 0; p < ctx->params->buffer_size; ++p) { if (p >= sync_period) { if (p % symbol_period == 0) { - if (n == 32) - n = 0; - msgbuf = message >> n; - sym = msgbuf & 3; - n += 2; - bbs = symbol_period * symbols[sym]; - } else { - bbs = 0; - } + if (n == 32) + n = 0; + msgbuf = message >> n; + sym = msgbuf & 3; + n += 2; + bbs = symbol_period * symbols[sym]; } else { - /* Send first symbol to synchronize */ - bbs = symbols[1]; + bbs = 0; } + } else { + /* Send first symbol to synchronize */ + bbs = symbols[1]; + } data[p] = bbs; input[p] = su_iir_filt_feed(&mf, data[p]); @@ -482,11 +458,11 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) /* Feed the loop and perform demodulation */ for (p = 0; p < ctx->params->buffer_size; ++p) { - (void) su_ncqo_step(&ncqo); + (void)su_ncqo_step(&ncqo); su_costas_feed(&costas, tx[p]); - carrier[p] = su_ncqo_get(&costas.ncqo); + carrier[p] = su_ncqo_get(&costas.ncqo); output[p] = su_iir_filt_feed(&mf, costas.y); - lock[p] = costas.lock; + lock[p] = costas.lock; omgerr[p] = costas.ncqo.fnor - ncqo.fnor; if (p >= rx_delay) { @@ -494,7 +470,7 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) t = (p - rx_delay) / symbol_period; sym = su_test_costas_qpsk_decision(output[p]); if (t < 32) - rx_buf |= sym << (2 * t); + rx_buf |= (uint64_t) sym << (2 * t); rx[rx_count++] = output[p]; } @@ -503,14 +479,9 @@ __su_test_costas_qpsk(su_test_context_t *ctx, SUBOOL noisy) permutations = su_test_rotcompare(rx_buf, message); - SU_INFO( - "RX: 0x%x in %d samples\n", - rx_buf, - ctx->params->buffer_size); + SU_INFO("RX: 0x%x in %d samples\n", rx_buf, ctx->params->buffer_size); SU_TEST_ASSERT(permutations != -1); - SU_INFO( - "RX: message decoded after %d permutations\n", - permutations); + SU_INFO("RX: message decoded after %d permutations\n", permutations); ok = SU_TRUE; done: @@ -542,4 +513,3 @@ su_test_costas_qpsk_noisy(su_test_context_t *ctx) { return __su_test_costas_qpsk(ctx, SU_TRUE); } - diff --git a/src/tests/detect.c b/src/tests/detect.c index 9806d9e..9e06ecf 100644 --- a/src/tests/detect.c +++ b/src/tests/detect.c @@ -17,17 +17,16 @@ */ +#include +#include +#include +#include #include #include #include -#include -#include #include #include - -#include -#include -#include +#include #include "test_list.h" #include "test_param.h" @@ -61,7 +60,6 @@ __su_test_channel_detector_qpsk(su_test_context_t *ctx, SUBOOL noisy) unsigned int p = 0; unsigned int sym; unsigned int n = 0; - unsigned int i; struct sigutils_channel *channel; SU_TEST_START_TICKLESS(ctx); @@ -69,16 +67,16 @@ __su_test_channel_detector_qpsk(su_test_context_t *ctx, SUBOOL noisy) /* Initialize some parameters */ symbol_period = SU_TEST_COSTAS_SYMBOL_PERIOD; filter_period = SU_TEST_MF_SYMBOL_SPAN * symbol_period; /* Span: 6 symbols */ - message = 0x414c4f48; /* Some greeting message */ + message = 0x414c4f48; /* Some greeting message */ if (noisy) - N0 = SU_POWER_MAG(-10); + N0 = SU_POWER_MAG(-10); else - N0 = SU_POWER_MAG(-20); + N0 = SU_POWER_MAG(-20); - sigma = sqrt(N0 / 2); + sigma = sqrt(N0 / 2); - phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ + phi0 = SU_C_EXP(I * M_PI / 4); /* Phase offset */ /* Initialize channel detector */ params.samp_rate = 250000; @@ -86,11 +84,11 @@ __su_test_channel_detector_qpsk(su_test_context_t *ctx, SUBOOL noisy) params.window_size = 4096; /* Initialize buffers */ - SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); - SU_TEST_ASSERT(data = su_test_ctx_getc(ctx, "data")); - SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); + SU_TEST_ASSERT(input = su_test_ctx_getc(ctx, "x")); + SU_TEST_ASSERT(data = su_test_ctx_getc(ctx, "data")); + SU_TEST_ASSERT(tx = su_test_ctx_getc(ctx, "tx")); SU_TEST_ASSERT( - fft = su_test_ctx_getf_w_size(ctx, "spectrogram", params.window_size)); + fft = su_test_ctx_getf_w_size(ctx, "spectrogram", params.window_size)); SU_TEST_ASSERT(detector = su_channel_detector_new(¶ms)); @@ -98,18 +96,10 @@ __su_test_channel_detector_qpsk(su_test_context_t *ctx, SUBOOL noisy) su_ncqo_init(&ncqo, SU_TEST_CHANNEL_DETECTOR_SIGNAL_FREQ); #ifndef SU_TEST_COSTAS_USE_RRC - SU_TEST_ASSERT( - su_iir_rrc_init( - &mf, - filter_period, - symbol_period, - 1)); + SU_TEST_ASSERT(su_iir_rrc_init(&mf, filter_period, symbol_period, 1)); #else SU_TEST_ASSERT( - su_iir_brickwall_init( - &mf, - filter_period, - SU_TEST_COSTAS_BANDWIDTH)); + su_iir_brickwall_init(&mf, filter_period, SU_TEST_COSTAS_BANDWIDTH)); #endif /* Create QPSK signal */ @@ -117,10 +107,10 @@ __su_test_channel_detector_qpsk(su_test_context_t *ctx, SUBOOL noisy) SU_INFO("Modulating 0x%x in QPSK...\n", msgbuf); SU_INFO(" Noise: %lg dBFS\n", SU_POWER_DB(N0)); SU_INFO(" Window size: %d samples\n", params.window_size); - SU_INFO(" Baudrate at fs=%d: %lg\n", - params.samp_rate, - SU_NORM2ABS_BAUD(params.samp_rate, 1. / symbol_period)); - + SU_INFO( + " Baudrate at fs=%d: %lg\n", + params.samp_rate, + SU_NORM2ABS_BAUD(params.samp_rate, 1. / symbol_period)); for (p = 0; p < ctx->params->buffer_size; ++p) { if (p % symbol_period == 0) { @@ -142,8 +132,8 @@ __su_test_channel_detector_qpsk(su_test_context_t *ctx, SUBOOL noisy) SU_TEST_TICK(ctx); SU_INFO( - "Frequency step: %lg Hz\n", - (double) params.samp_rate / (double) params.window_size); + "Frequency step: %lg Hz\n", + (double)params.samp_rate / (double)params.window_size); SU_INFO( " Will need %d samples before performing a detection\n", su_channel_detector_get_req_samples(detector)); @@ -160,10 +150,9 @@ __su_test_channel_detector_qpsk(su_test_context_t *ctx, SUBOOL noisy) SU_TEST_CHANNEL_DETECTOR_SIGNAL_FREQ))); SU_INFO("Channel found by detector:\n"); - SU_INFO(" Actual frequency: %lg Hz\n", - SU_NORM2ABS_FREQ( - params.samp_rate, - SU_TEST_CHANNEL_DETECTOR_SIGNAL_FREQ)); + SU_INFO( + " Actual frequency: %lg Hz\n", + SU_NORM2ABS_FREQ(params.samp_rate, SU_TEST_CHANNEL_DETECTOR_SIGNAL_FREQ)); SU_INFO(" Detected frequency: %lg Hz\n", channel->fc); SU_INFO(" Bandwidth: %lg Hz\n", channel->bw); SU_INFO(" SNR: %lg dB\n", channel->snr); @@ -198,7 +187,7 @@ SUBOOL su_test_channel_detector_real_capture(su_test_context_t *ctx) { SUBOOL ok = SU_FALSE; - complex float *input = (complex float *) -1; /* Required by mmap */ + complex float *input = (complex float *)-1; /* Required by mmap */ SUCOMPLEX *fft; SUCOMPLEX *win; SUFLOAT *spect; @@ -237,17 +226,18 @@ su_test_channel_detector_real_capture(su_test_context_t *ctx) SU_TEST_ASSERT(stat(SU_CHANNEL_DETECTOR_SAMPLE_CAPTURE, &sbuf) != -1); - SU_TEST_ASSERT((fd = open( - SU_CHANNEL_DETECTOR_SAMPLE_CAPTURE, - O_RDONLY)) != -1); + SU_TEST_ASSERT( + (fd = open(SU_CHANNEL_DETECTOR_SAMPLE_CAPTURE, O_RDONLY)) != -1); - SU_TEST_ASSERT((input = (complex float *) mmap( - NULL, /* addr */ - sbuf.st_size, /* size */ - PROT_READ, /* prot */ - MAP_PRIVATE, /* flags */ - fd, /* fd */ - 0 /* offset */)) != (complex float *) -1); + SU_TEST_ASSERT( + (input = (complex float *)mmap( + NULL, /* addr */ + sbuf.st_size, /* size */ + PROT_READ, /* prot */ + MAP_PRIVATE, /* flags */ + fd, /* fd */ + 0 /* offset */)) + != (complex float *)-1); close(fd); /* We don't need this anymore */ fd = -1; @@ -271,16 +261,13 @@ su_test_channel_detector_real_capture(su_test_context_t *ctx) spmax = su_test_ctx_getf_w_size(ctx, "spmax", params.window_size)); SU_TEST_ASSERT( spmin = su_test_ctx_getf_w_size(ctx, "spmin", params.window_size)); - SU_TEST_ASSERT( - decim = su_test_ctx_getf_w_size(ctx, "decim", 1)); - SU_TEST_ASSERT( - fc = su_test_ctx_getf_w_size(ctx, "fc", 1)); + SU_TEST_ASSERT(decim = su_test_ctx_getf_w_size(ctx, "decim", 1)); + SU_TEST_ASSERT(fc = su_test_ctx_getf_w_size(ctx, "fc", 1)); SU_TEST_ASSERT( n0est = su_test_ctx_getf_w_size( ctx, "n0est", - samples / params.window_size - + !!(samples % params.window_size))); + samples / params.window_size + !!(samples % params.window_size))); SU_TEST_ASSERT(detector = su_channel_detector_new(¶ms)); @@ -300,24 +287,18 @@ su_test_channel_detector_real_capture(su_test_context_t *ctx) SU_TEST_TICK(ctx); for (i = 0; i < samples; ++i) { - SU_TEST_ASSERT( - su_channel_detector_feed( - detector, - SU_C_CONJ((SUCOMPLEX) input[i]))); /* Gqrx inverts the Q channel */ + SU_TEST_ASSERT(su_channel_detector_feed( + detector, + SU_C_CONJ((SUCOMPLEX)input[i]))); /* Gqrx inverts the Q channel */ if ((i % params.window_size) == 0) n0est[j++] = detector->N0; } /* Print results */ - su_channel_detector_get_channel_list( - detector, - &channel_list, - &channel_count); + su_channel_detector_get_channel_list(detector, &channel_list, &channel_count); - SU_INFO( - "Computed noise floor: %lg dB\n", - SU_POWER_DB(detector->N0)); + SU_INFO("Computed noise floor: %lg dB\n", SU_POWER_DB(detector->N0)); for (i = 0; i < channel_count; ++i) if (channel_list[i] != NULL) if (SU_CHANNEL_IS_VALID(channel_list[i])) { @@ -361,10 +342,8 @@ su_test_channel_detector_real_capture(su_test_context_t *ctx) SU_TEST_ASSERT( acorr = su_test_ctx_getf_w_size(ctx, "acorr", params.window_size)); - SU_TEST_ASSERT( - fft = su_test_ctx_getc_w_size(ctx, "fft", params.window_size)); - SU_TEST_ASSERT( - win = su_test_ctx_getc_w_size(ctx, "win", params.window_size)); + SU_TEST_ASSERT(fft = su_test_ctx_getc_w_size(ctx, "fft", params.window_size)); + SU_TEST_ASSERT(win = su_test_ctx_getc_w_size(ctx, "win", params.window_size)); SU_TEST_ASSERT(baud_det = su_channel_detector_new(¶ms)); @@ -379,10 +358,10 @@ su_test_channel_detector_real_capture(su_test_context_t *ctx) (req / (params.samp_rate)) % 60); for (i = 0; i < samples; ++i) - SU_TEST_ASSERT( - su_channel_detector_feed( - baud_det, - SU_C_CONJ((SUCOMPLEX) input[i % samples]))); /* Gqrx inverts the Q channel */ + SU_TEST_ASSERT(su_channel_detector_feed( + baud_det, + SU_C_CONJ( + (SUCOMPLEX)input[i % samples]))); /* Gqrx inverts the Q channel */ *decim = baud_det->params.decimation; for (i = 0; i < params.window_size; ++i) { @@ -402,10 +381,10 @@ su_test_channel_detector_real_capture(su_test_context_t *ctx) SU_TEST_ASSERT(nonlinear_baud_det = su_channel_detector_new(¶ms)); for (i = 0; i < samples; ++i) - SU_TEST_ASSERT( - su_channel_detector_feed( - nonlinear_baud_det, - SU_C_CONJ((SUCOMPLEX) input[i % samples]))); /* Gqrx inverts the Q channel */ + SU_TEST_ASSERT(su_channel_detector_feed( + nonlinear_baud_det, + SU_C_CONJ( + (SUCOMPLEX)input[i % samples]))); /* Gqrx inverts the Q channel */ if (nonlinear_baud_det->baud == 0) SU_INFO(" Not enough certainty to estimate baudrate\n"); @@ -434,5 +413,3 @@ su_test_channel_detector_real_capture(su_test_context_t *ctx) return ok; } - - diff --git a/src/tests/filt.c b/src/tests/filt.c index 1e86cb2..86bd9a5 100644 --- a/src/tests/filt.c +++ b/src/tests/filt.c @@ -17,20 +17,18 @@ */ -#include -#include -#include - -#include -#include -#include #include +#include +#include #include - +#include #include +#include +#include +#include -#include "test_param.h" #include "test_list.h" +#include "test_param.h" SUBOOL su_test_butterworth_lpf(su_test_context_t *ctx) @@ -54,27 +52,35 @@ su_test_butterworth_lpf(su_test_context_t *ctx) su_ncqo_init(&ncqo, 1); for (p = 0; p < ctx->params->buffer_size; ++p) - hi[p] = SU_C_REAL(su_iir_filt_feed( - &lpf, - su_ncqo_read(&ncqo))); + hi[p] = SU_C_REAL(su_iir_filt_feed(&lpf, su_ncqo_read(&ncqo))); if (ctx->params->dump_fmt) { - printf(" hi pp: " SUFLOAT_FMT "\n", su_test_buffer_pp(hi, SU_TEST_SIGNAL_BUFFER_SIZE)); - printf(" hi mean: " SUFLOAT_FMT "\n", su_test_buffer_mean(hi, SU_TEST_SIGNAL_BUFFER_SIZE)); - printf(" hi std: " SUFLOAT_FMT "\n", su_test_buffer_std(hi, SU_TEST_SIGNAL_BUFFER_SIZE)); + printf( + " hi pp: " SUFLOAT_FMT "\n", + su_test_buffer_pp(hi, SU_TEST_SIGNAL_BUFFER_SIZE)); + printf( + " hi mean: " SUFLOAT_FMT "\n", + su_test_buffer_mean(hi, SU_TEST_SIGNAL_BUFFER_SIZE)); + printf( + " hi std: " SUFLOAT_FMT "\n", + su_test_buffer_std(hi, SU_TEST_SIGNAL_BUFFER_SIZE)); } su_ncqo_set_freq(&ncqo, .125); for (p = 0; p < ctx->params->buffer_size; ++p) - lo[p] = SU_C_REAL(su_iir_filt_feed( - &lpf, - su_ncqo_read(&ncqo))); + lo[p] = SU_C_REAL(su_iir_filt_feed(&lpf, su_ncqo_read(&ncqo))); if (ctx->params->dump_fmt) { - printf(" lo pp: " SUFLOAT_FMT "\n", su_test_buffer_pp(lo, SU_TEST_SIGNAL_BUFFER_SIZE)); - printf(" lo mean: " SUFLOAT_FMT "\n", su_test_buffer_mean(lo, SU_TEST_SIGNAL_BUFFER_SIZE)); - printf(" lo std: " SUFLOAT_FMT "\n", su_test_buffer_std(lo, SU_TEST_SIGNAL_BUFFER_SIZE)); + printf( + " lo pp: " SUFLOAT_FMT "\n", + su_test_buffer_pp(lo, SU_TEST_SIGNAL_BUFFER_SIZE)); + printf( + " lo mean: " SUFLOAT_FMT "\n", + su_test_buffer_mean(lo, SU_TEST_SIGNAL_BUFFER_SIZE)); + printf( + " lo std: " SUFLOAT_FMT "\n", + su_test_buffer_std(lo, SU_TEST_SIGNAL_BUFFER_SIZE)); } ok = SU_TRUE; @@ -86,5 +92,3 @@ su_test_butterworth_lpf(su_test_context_t *ctx) return ok; } - - diff --git a/src/tests/mat.c b/src/tests/mat.c index f11e9ed..6484b53 100644 --- a/src/tests/mat.c +++ b/src/tests/mat.c @@ -17,11 +17,10 @@ */ - #include -#include "test_param.h" #include "test_list.h" +#include "test_param.h" SUBOOL su_test_mat_file_regular(su_test_context_t *ctx) diff --git a/src/tests/ncqo.c b/src/tests/ncqo.c index c8ab5a5..734555e 100644 --- a/src/tests/ncqo.c +++ b/src/tests/ncqo.c @@ -17,20 +17,18 @@ */ -#include -#include -#include - -#include -#include -#include #include +#include +#include #include - +#include #include +#include +#include +#include -#include "test_param.h" #include "test_list.h" +#include "test_param.h" SUBOOL su_test_ncqo(su_test_context_t *ctx) @@ -50,25 +48,23 @@ su_test_ncqo(su_test_context_t *ctx) for (p = 0; p < SU_TEST_SIGNAL_BUFFER_SIZE; ++p) buffer[p] = su_ncqo_read_i(&ncqo); - SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); + SU_TEST_ASSERT(SUFLOAT_EQUAL( + su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), + 0)); SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 2)); + SUFLOAT_EQUAL(su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 2)); /* Test quadrature signal */ for (p = 0; p < SU_TEST_SIGNAL_BUFFER_SIZE; ++p) buffer[p] = su_ncqo_read_q(&ncqo); - SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); + SU_TEST_ASSERT(SUFLOAT_EQUAL( + su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), + 0)); SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); + SUFLOAT_EQUAL(su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); /* Modify phase */ su_ncqo_set_phase(&ncqo, PI / 2); @@ -77,25 +73,23 @@ su_test_ncqo(su_test_context_t *ctx) for (p = 0; p < SU_TEST_SIGNAL_BUFFER_SIZE; ++p) buffer[p] = su_ncqo_read_i(&ncqo); - SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); + SU_TEST_ASSERT(SUFLOAT_EQUAL( + su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), + 0)); SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); + SUFLOAT_EQUAL(su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); /* Test quadrature signal */ for (p = 0; p < SU_TEST_SIGNAL_BUFFER_SIZE; ++p) buffer[p] = su_ncqo_read_q(&ncqo); - SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 0)); + SU_TEST_ASSERT(SUFLOAT_EQUAL( + su_test_buffer_mean(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), + 0)); SU_TEST_ASSERT( - SUFLOAT_EQUAL( - su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 2)); + SUFLOAT_EQUAL(su_test_buffer_pp(buffer, SU_TEST_SIGNAL_BUFFER_SIZE), 2)); /* Test constant signal */ su_ncqo_set_phase(&ncqo, 0); @@ -117,4 +111,3 @@ su_test_ncqo(su_test_context_t *ctx) return ok; } - diff --git a/src/tests/pll.c b/src/tests/pll.c index 50482cb..740adbc 100644 --- a/src/tests/pll.c +++ b/src/tests/pll.c @@ -17,17 +17,15 @@ */ -#include -#include -#include - -#include -#include -#include #include +#include +#include #include - +#include #include +#include +#include +#include #include "test_list.h" #include "test_param.h" @@ -41,7 +39,6 @@ su_test_pll(su_test_context_t *ctx) SUFLOAT *phierr = NULL; SUFLOAT *lock = NULL; - SUFLOAT t; su_ncqo_t ncqo = su_ncqo_INITIALIZER; su_pll_t pll = su_pll_INITIALIZER; unsigned int p = 0; @@ -49,20 +46,19 @@ su_test_pll(su_test_context_t *ctx) SU_TEST_START_TICKLESS(ctx); /* Initialize */ - SU_TEST_ASSERT(input = su_test_ctx_getf(ctx, "x")); + SU_TEST_ASSERT(input = su_test_ctx_getf(ctx, "x")); SU_TEST_ASSERT(omgerr = su_test_ctx_getf(ctx, "oe")); SU_TEST_ASSERT(phierr = su_test_ctx_getf(ctx, "pe")); - SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); + SU_TEST_ASSERT(lock = su_test_ctx_getf(ctx, "lock")); - SU_TEST_ASSERT(su_pll_init(&pll, - SU_TEST_PLL_SIGNAL_FREQ * 0.5, - SU_TEST_PLL_BANDWIDTH)); + SU_TEST_ASSERT( + su_pll_init(&pll, SU_TEST_PLL_SIGNAL_FREQ * 0.5, SU_TEST_PLL_BANDWIDTH)); su_ncqo_init(&ncqo, SU_TEST_PLL_SIGNAL_FREQ); /* Create a falling sinusoid */ for (p = 0; p < ctx->params->buffer_size; ++p) { - input[p] = 0 * (0.5 - rand() / (double) RAND_MAX); + input[p] = 0 * (0.5 - rand() / (double)RAND_MAX); input[p] += su_ncqo_read_i(&ncqo); } @@ -73,11 +69,11 @@ su_test_pll(su_test_context_t *ctx) /* Feed the PLL and save phase value */ for (p = 0; p < ctx->params->buffer_size; ++p) { - (void) su_ncqo_read_i(&ncqo); /* Used to compute phase errors */ + (void)su_ncqo_read_i(&ncqo); /* Used to compute phase errors */ su_pll_feed(&pll, input[p]); - input[p] = su_ncqo_get_i(&pll.ncqo); + input[p] = su_ncqo_get_i(&pll.ncqo); phierr[p] = su_ncqo_get_phase(&pll.ncqo) - su_ncqo_get_phase(&ncqo); - lock[p] = pll.lock; + lock[p] = pll.lock; if (phierr[p] < 0 || phierr[p] > 2 * PI) { phierr[p] -= 2 * PI * floor(phierr[p] / (2 * PI)); @@ -96,5 +92,3 @@ su_test_pll(su_test_context_t *ctx) return ok; } - - diff --git a/src/tests/specttuner.c b/src/tests/specttuner.c index aefd7fc..76d5adb 100644 --- a/src/tests/specttuner.c +++ b/src/tests/specttuner.c @@ -17,15 +17,13 @@ */ +#include +#include +#include #include #include #include -#include -#include - -#include - #include "test_list.h" #include "test_param.h" @@ -38,10 +36,11 @@ SUPRIVATE SUBOOL su_specttuner_append( const su_specttuner_channel_t *channel, void *private, - const SUCOMPLEX *data, /* This pointer remains valid until the next call to feed */ + const SUCOMPLEX *data, /* This pointer remains valid until + the next call to feed */ SUSCOUNT size) { - struct su_specttuner_context *ctx = (struct su_specttuner_context *) private; + struct su_specttuner_context *ctx = (struct su_specttuner_context *)private; memcpy(ctx->output + ctx->p, data, size * sizeof(SUCOMPLEX)); ctx->p += size; @@ -67,7 +66,7 @@ su_test_specttuner_two_tones(su_test_context_t *ctx) struct sigutils_specttuner_params st_params = sigutils_specttuner_params_INITIALIZER; struct sigutils_specttuner_channel_params ch_params = - sigutils_specttuner_channel_params_INITIALIZER; + sigutils_specttuner_channel_params_INITIALIZER; struct su_specttuner_context out_ctx; su_specttuner_channel_t *ch = NULL; su_specttuner_t *st = NULL; @@ -101,9 +100,9 @@ su_test_specttuner_two_tones(su_test_context_t *ctx) for (p = 0; p < ctx->params->buffer_size; ++p) input[p] = su_ncqo_read(&lo1) + su_ncqo_read(&lo2); - /*input[p] - = .25 * (su_ncqo_read(&lo1) + su_ncqo_read(&lo2)) - + SU_TEST_SPECTTUNER_N0 * su_c_awgn();*/ + /*input[p] + = .25 * (su_ncqo_read(&lo1) + su_ncqo_read(&lo2)) + + SU_TEST_SPECTTUNER_N0 * su_c_awgn();*/ /* Define channel */ memset(output, 0, sizeof(SUCOMPLEX) * ctx->params->buffer_size); @@ -113,8 +112,8 @@ su_test_specttuner_two_tones(su_test_context_t *ctx) ch_params.privdata = &out_ctx; ch_params.on_data = su_specttuner_append; - ch_params.bw = SU_NORM2ANG_FREQ( - SU_ABS2NORM_FREQ(SU_TEST_SPECTTUNER_SAMP_RATE, 100)); + ch_params.bw = + SU_NORM2ANG_FREQ(SU_ABS2NORM_FREQ(SU_TEST_SPECTTUNER_SAMP_RATE, 100)); ch_params.f0 = SU_NORM2ANG_FREQ( SU_ABS2NORM_FREQ(SU_TEST_SPECTTUNER_SAMP_RATE, SU_TEST_SPECTTUNER_FREQ1)); diff --git a/src/tests/test_list.h b/src/tests/test_list.h index cefe79f..ce0de52 100644 --- a/src/tests/test_list.h +++ b/src/tests/test_list.h @@ -36,16 +36,6 @@ SUBOOL su_test_agc_steady_falling(su_test_context_t *ctx); /* PLL tests */ SUBOOL su_test_pll(su_test_context_t *ctx); -/* Block tests */ -SUBOOL su_test_block(su_test_context_t *ctx); -SUBOOL su_test_block_plugging(su_test_context_t *ctx); -SUBOOL su_test_block_flow_control(su_test_context_t *ctx); -SUBOOL su_test_tuner(su_test_context_t *ctx); -SUBOOL su_test_costas_block(su_test_context_t *ctx); -SUBOOL su_test_rrc_block(su_test_context_t *ctx); -SUBOOL su_test_rrc_block_with_if(su_test_context_t *ctx); -SUBOOL su_test_cdr_block(su_test_context_t *ctx); - /* Costas loop related tests */ SUBOOL su_test_costas_lock(su_test_context_t *ctx); SUBOOL su_test_costas_bpsk(su_test_context_t *ctx); @@ -61,10 +51,6 @@ SUBOOL su_test_channel_detector_qpsk(su_test_context_t *ctx); SUBOOL su_test_channel_detector_qpsk_noisy(su_test_context_t *ctx); SUBOOL su_test_channel_detector_real_capture(su_test_context_t *ctx); -/* Encoder tests */ -SUBOOL su_test_diff_codec_binary(su_test_context_t *ctx); -SUBOOL su_test_diff_codec_quaternary(su_test_context_t *ctx); - /* Spectral tuner tests */ SUBOOL su_test_specttuner_two_tones(su_test_context_t *ctx); diff --git a/src/tests/test_param.h b/src/tests/test_param.h index 1c1395a..c1471b6 100644 --- a/src/tests/test_param.h +++ b/src/tests/test_param.h @@ -22,7 +22,7 @@ /* Block-related params */ #define SU_TEST_BLOCK_SAWTOOTH_WIDTH 119 -#define SU_TEST_BLOCK_READ_WAIT_MS 25 +#define SU_TEST_BLOCK_READ_WAIT_MS 25 /* Preferred matched filter span (in symbol periods) */ #define SU_TEST_MF_SYMBOL_SPAN 6 @@ -42,27 +42,27 @@ /* PLL params */ #define SU_TEST_PLL_SIGNAL_FREQ 0.025 -#define SU_TEST_PLL_BANDWIDTH (1e-4) +#define SU_TEST_PLL_BANDWIDTH (1e-4) /* Channel detector params */ #define SU_TEST_USE_ACTUAL_CAPTURE #ifdef SU_TEST_USE_ACTUAL_CAPTURE -#define SU_CHANNEL_DETECTOR_SAMPLE_CAPTURE \ - "gqrx_20170219_185002_1545346100_250000_fc.raw" +# define SU_CHANNEL_DETECTOR_SAMPLE_CAPTURE \ + "gqrx_20170219_185002_1545346100_250000_fc.raw" #else -#define SU_CHANNEL_DETECTOR_SAMPLE_CAPTURE \ - "su_test_channel_detector_qpsk/tx-complex.raw" +# define SU_CHANNEL_DETECTOR_SAMPLE_CAPTURE \ + "su_test_channel_detector_qpsk/tx-complex.raw" #endif /* Encoder parameters */ #define SU_TEST_ENCODER_NUM_SYMS 32 /* Spectral tuner */ -#define SU_TEST_SPECTTUNER_FREQ1 200. -#define SU_TEST_SPECTTUNER_FREQ2 1000. +#define SU_TEST_SPECTTUNER_FREQ1 200. +#define SU_TEST_SPECTTUNER_FREQ2 1000. #define SU_TEST_SPECTTUNER_SAMP_RATE 8000. -#define SU_TEST_SPECTTUNER_N0 2e-2 +#define SU_TEST_SPECTTUNER_N0 2e-2 #endif /* _SRC_TEST_PARAM */ diff --git a/testutil/common.c b/testutil/common.c index e66c1a7..36565d8 100644 --- a/testutil/common.c +++ b/testutil/common.c @@ -20,6 +20,8 @@ #include #include #include +#include + #include "test.h" void @@ -32,24 +34,25 @@ su_test_context_update_times(su_test_context_t *ctx) /* Hours */ if (diff.tv_sec >= 3600) { ctx->elapsed_time = (diff.tv_sec + 1e-6 * diff.tv_usec) / 3600; - ctx->time_units = SU_TIME_UNITS_HOUR; + ctx->time_units = SU_TIME_UNITS_HOUR; } else if (diff.tv_sec >= 60) { ctx->elapsed_time = (diff.tv_sec + 1e-6 * diff.tv_usec) / 60; - ctx->time_units = SU_TIME_UNITS_MIN; + ctx->time_units = SU_TIME_UNITS_MIN; } else if (diff.tv_sec >= 1) { ctx->elapsed_time = diff.tv_sec + 1e-6 * diff.tv_usec; - ctx->time_units = SU_TIME_UNITS_SEC; + ctx->time_units = SU_TIME_UNITS_SEC; } else if (diff.tv_usec >= 1000) { ctx->elapsed_time = 1e-3 * diff.tv_usec; - ctx->time_units = SU_TIME_UNITS_MSEC; + ctx->time_units = SU_TIME_UNITS_MSEC; } else { ctx->elapsed_time = diff.tv_usec; - ctx->time_units = SU_TIME_UNITS_USEC; + ctx->time_units = SU_TIME_UNITS_USEC; } } const char * -su_test_context_time_units(const su_test_context_t *ctx) { +su_test_context_time_units(const su_test_context_t *ctx) +{ switch (ctx->time_units) { case SU_TIME_UNITS_HOUR: return "hour"; @@ -76,13 +79,13 @@ su_test_context_time_units(const su_test_context_t *ctx) { SUFLOAT * su_test_buffer_new(unsigned int size) { - return calloc(size, sizeof (SUFLOAT)); + return calloc(size, sizeof(SUFLOAT)); } SUCOMPLEX * su_test_complex_buffer_new(unsigned int size) { - return calloc(size, sizeof (SUCOMPLEX)); + return calloc(size, sizeof(SUCOMPLEX)); } SUFLOAT @@ -127,8 +130,6 @@ su_test_buffer_peak(const SUFLOAT *buffer, unsigned int size) SUFLOAT su_test_buffer_pp(const SUFLOAT *buffer, unsigned int size) { - SUFLOAT size_inv = 1. / size; - SUFLOAT result = 0.; SUFLOAT min = INFINITY; SUFLOAT max = -INFINITY; @@ -158,10 +159,10 @@ su_test_complex_buffer_dump_raw( for (i = 0; i < size; ++i) { val = SU_C_REAL(buffer[i]); - if (fwrite(&val, sizeof (float), 1, fp) < 1) + if (fwrite(&val, sizeof(float), 1, fp) < 1) goto fail; val = SU_C_IMAG(buffer[i]); - if (fwrite(&val, sizeof (float), 1, fp) < 1) + if (fwrite(&val, sizeof(float), 1, fp) < 1) goto fail; } @@ -191,7 +192,7 @@ su_test_buffer_dump_raw( for (i = 0; i < size; ++i) { val = buffer[i]; - if (fwrite(&val, sizeof (float), 1, fp) < 1) + if (fwrite(&val, sizeof(float), 1, fp) < 1) goto fail; } @@ -228,15 +229,16 @@ su_test_complex_buffer_dump_matlab( goto fail; if (fprintf( - fp, - SUFLOAT_PRECISION_FMT " + " SUFLOAT_PRECISION_FMT "i", - SU_C_REAL(buffer[i]), - SU_C_IMAG(buffer[i])) < 0) + fp, + SUFLOAT_PRECISION_FMT " + " SUFLOAT_PRECISION_FMT "i", + SU_C_REAL(buffer[i]), + SU_C_IMAG(buffer[i])) + < 0) goto fail; } if (fprintf(fp, "\n];\n") < 0) - goto fail; + goto fail; fclose(fp); @@ -275,7 +277,7 @@ su_test_buffer_dump_matlab( } if (fprintf(fp, "\n];\n") < 0) - goto fail; + goto fail; fclose(fp); @@ -359,7 +361,7 @@ su_test_context_reset(su_test_context_t *ctx) if (ctx->pool != NULL) su_sigbuf_pool_destroy(ctx->pool); - memset(ctx, 0, sizeof (su_test_context_t)); + memset(ctx, 0, sizeof(su_test_context_t)); ctx->time_units = SU_TIME_UNITS_UNDEFINED; } @@ -367,7 +369,7 @@ su_test_context_reset(su_test_context_t *ctx) SUPRIVATE const char * su_test_dump_format_to_string(enum sigutils_dump_format fmt) { - switch(fmt) { + switch (fmt) { case SU_DUMP_FORMAT_NONE: return "none"; @@ -433,7 +435,7 @@ su_test_run( if ((test_list[i].cb)(&ctx)) ++success; else { - printf("[t:%3d] TEST FAILED\n", i); + printf("[t:%3u] TEST FAILED\n", i); } if (params->dump_fmt) { @@ -447,11 +449,11 @@ su_test_run( ++count; -next_test: + next_test: su_test_context_reset(&ctx); } - printf("%d tests run, %d failed\n", count, count - success); + printf("%u tests run, %u failed\n", count, count - success); return count == success; } diff --git a/testutil/poolhelper.c b/testutil/poolhelper.c index d98ff8f..d42812d 100644 --- a/testutil/poolhelper.c +++ b/testutil/poolhelper.c @@ -17,11 +17,12 @@ */ -#include #include +#include +#include #include #include -#include + #include "test.h" #ifdef _SU_SINGLE_PRECISION @@ -51,16 +52,13 @@ su_sigbuf_pool_helper_dump_matlab( if (is_complex) result = su_test_complex_buffer_dump_matlab( - (const SUCOMPLEX *) data, + (const SUCOMPLEX *)data, size, filename, name); else - result = su_test_buffer_dump_matlab( - (const SUFLOAT *) data, - size, - filename, - name); + result = + su_test_buffer_dump_matlab((const SUFLOAT *)data, size, filename, name); free(filename); @@ -82,68 +80,59 @@ su_sigbuf_pool_dump_matlab(const su_sigbuf_pool_t *pool) time_t now; if ((filename = strbuild("%s.m", pool->name)) == NULL) { - SU_ERROR("Failed to build main script file name\n"); - goto fail; - } - - if ((fp = fopen(filename, "w")) == NULL) { - SU_ERROR("Cannot create main script `%s': %s\n", filename, strerror(errno)); - goto fail; - } - - free(filename); - filename = NULL; - - time(&now); - - SU_SYSCALL_ASSERT( - fprintf( - fp, - "%% Autogenerated MATLAB script for sigbuf pool `%s'\n", - pool->name)); - SU_SYSCALL_ASSERT( - fprintf( - fp, - "%% File generated on %s", - ctime(&now))); - - FOR_EACH_PTR(this, pool, sigbuf) { - if (!su_sigbuf_pool_helper_dump_matlab( - this->buffer, - this->size, - this->is_complex, - pool->name, - this->name)) - goto fail; - - SU_SYSCALL_ASSERT( - fprintf( - fp, - "%% %s: %s buffer, %lu elements\n", - this->name, - this->is_complex ? "complex" : "float", - this->size)); - SU_SYSCALL_ASSERT( - fprintf( - fp, - "source('%s/%s.m');\n\n", - pool->name, - this->name)); - } - - fclose(fp); - fp = NULL; - - return SU_TRUE; - - fail: - if (filename != NULL) - free(filename); - - if (fp != NULL) - fclose(fp); - - return SU_FALSE; + SU_ERROR("Failed to build main script file name\n"); + goto fail; + } + + if ((fp = fopen(filename, "w")) == NULL) { + SU_ERROR("Cannot create main script `%s': %s\n", filename, strerror(errno)); + goto fail; + } + + free(filename); + filename = NULL; + + time(&now); + + SU_SYSCALL_ASSERT(fprintf( + fp, + "%% Autogenerated MATLAB script for sigbuf pool `%s'\n", + pool->name)); + SU_SYSCALL_ASSERT(fprintf(fp, "%% File generated on %s", ctime(&now))); + + FOR_EACH_PTR(this, pool, sigbuf) + { + if (!su_sigbuf_pool_helper_dump_matlab( + this->buffer, + this->size, + this->is_complex, + pool->name, + this->name)) + goto fail; + + SU_SYSCALL_ASSERT(fprintf( + fp, + "%% %s: %s buffer, %lu elements\n", + this->name, + this->is_complex ? "complex" : "float", + this->size)); + SU_SYSCALL_ASSERT( + fprintf(fp, "source('%s/%s.m');\n\n", pool->name, this->name)); + } + + fclose(fp); + fp = NULL; + + return SU_TRUE; + +fail: + if (filename != NULL) + free(filename); + + if (fp != NULL) + fclose(fp); + + return SU_FALSE; } SUBOOL @@ -170,14 +159,11 @@ su_sigbuf_pool_helper_dump_raw( if (is_complex) result = su_test_complex_buffer_dump_raw( - (const SUCOMPLEX *) data, + (const SUCOMPLEX *)data, size, filename); else - result = su_test_buffer_dump_raw( - (const SUFLOAT *) data, - size, - filename); + result = su_test_buffer_dump_raw((const SUFLOAT *)data, size, filename); free(filename); @@ -196,12 +182,12 @@ su_sigbuf_pool_dump_raw(const su_sigbuf_pool_t *pool) su_sigbuf_t *this; FOR_EACH_PTR(this, pool, sigbuf) - if (!su_sigbuf_pool_helper_dump_raw( - this->buffer, - this->size, - this->is_complex, - pool->name, - this->name)) + if (!su_sigbuf_pool_helper_dump_raw( + this->buffer, + this->size, + this->is_complex, + pool->name, + this->name)) goto fail; return SU_TRUE; @@ -225,7 +211,6 @@ su_sigbuf_pool_helper_dump_wav( SF_INFO info; SUSCOUNT samples = 0; SUSCOUNT written = 0; - unsigned int i; info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; info.channels = is_complex ? 2 : 1; @@ -245,8 +230,7 @@ su_sigbuf_pool_helper_dump_wav( samples = size * info.channels; /* UGLY HACK: WE ASSUME THAT A COMPLEX IS TWO DOUBLES */ - if ((written = sf_write(sf, (const SUFLOAT *) data, samples)) - != samples) { + if ((written = sf_write(sf, (const SUFLOAT *)data, samples)) != samples) { SU_ERROR("Write to `%s' failed: %lu/%lu\n", filename, written, samples); goto fail; } @@ -271,20 +255,17 @@ su_sigbuf_pool_dump_wav(const su_sigbuf_pool_t *pool) { su_sigbuf_t *this; - FOR_EACH_PTR(this, pool, sigbuf) { + FOR_EACH_PTR(this, pool, sigbuf) + { if (!su_sigbuf_pool_helper_dump_wav( - this->buffer, - this->size, - this->fs, - this->is_complex, - pool->name, - this->name)) + this->buffer, + this->size, + this->fs, + this->is_complex, + pool->name, + this->name)) return SU_FALSE; } return SU_TRUE; } - - - - diff --git a/testutil/sigbufpool.c b/testutil/sigbufpool.c index e963341..8950728 100644 --- a/testutil/sigbufpool.c +++ b/testutil/sigbufpool.c @@ -17,13 +17,14 @@ */ +#include #include #include #include #include -#include #include -#include +#include + #include "test.h" SUPRIVATE void @@ -43,12 +44,12 @@ su_sigbuf_new(const char *name, SUSCOUNT size, SUBOOL is_complex) { su_sigbuf_t *new = NULL; - if ((new = calloc(1, sizeof (su_sigbuf_t))) == NULL) + if ((new = calloc(1, sizeof(su_sigbuf_t))) == NULL) goto fail; - if ((new->buffer = calloc( - size, - is_complex ? sizeof (SUCOMPLEX) : sizeof (SUFLOAT))) == NULL) + if ((new->buffer = + calloc(size, is_complex ? sizeof(SUCOMPLEX) : sizeof(SUFLOAT))) + == NULL) goto fail; if ((new->name = strdup(name)) == NULL) @@ -85,9 +86,9 @@ su_sigbuf_resize(su_sigbuf_t *sbuf, SUSCOUNT size) if (size > 0) { if ((new_buffer = realloc( - sbuf->buffer, - size - * (sbuf->is_complex ? sizeof (SUCOMPLEX) : sizeof (SUFLOAT)))) == NULL) + sbuf->buffer, + size * (sbuf->is_complex ? sizeof(SUCOMPLEX) : sizeof(SUFLOAT)))) + == NULL) return SU_FALSE; sbuf->buffer = new_buffer; @@ -100,11 +101,10 @@ su_sigbuf_resize(su_sigbuf_t *sbuf, SUSCOUNT size) void su_sigbuf_pool_destroy(su_sigbuf_pool_t *pool) { - unsigned int i; su_sigbuf_t *this; FOR_EACH_PTR(this, pool, sigbuf) - su_sigbuf_destroy(this); + su_sigbuf_destroy(this); if (pool->sigbuf_list != NULL) free(pool->sigbuf_list); @@ -120,7 +120,7 @@ su_sigbuf_pool_new(const char *name) { su_sigbuf_pool_t *new = NULL; - if ((new = calloc(1, sizeof (su_sigbuf_pool_t))) == NULL) + if ((new = calloc(1, sizeof(su_sigbuf_pool_t))) == NULL) goto fail; if ((new->name = strdup(name)) == NULL) @@ -140,12 +140,11 @@ su_sigbuf_pool_new(const char *name) su_sigbuf_t * su_sigbuf_pool_lookup(su_sigbuf_pool_t *pool, const char *name) { - unsigned int i; su_sigbuf_t *this; FOR_EACH_PTR(this, pool, sigbuf) - if (strcmp(this->name, name) == 0) - return this; + if (strcmp(this->name, name) == 0) + return this; return NULL; } @@ -206,15 +205,21 @@ su_sigbuf_pool_get_fs(const su_sigbuf_pool_t *pool) } SUFLOAT * -su_sigbuf_pool_get_float(su_sigbuf_pool_t *pool, const char *name, SUSCOUNT size) +su_sigbuf_pool_get_float( + su_sigbuf_pool_t *pool, + const char *name, + SUSCOUNT size) { - return (SUFLOAT *) su_sigbuf_pool_get(pool, name, size, SU_FALSE); + return (SUFLOAT *)su_sigbuf_pool_get(pool, name, size, SU_FALSE); } SUCOMPLEX * -su_sigbuf_pool_get_complex(su_sigbuf_pool_t *pool, const char *name, SUSCOUNT size) +su_sigbuf_pool_get_complex( + su_sigbuf_pool_t *pool, + const char *name, + SUSCOUNT size) { - return (SUCOMPLEX *) su_sigbuf_pool_get(pool, name, size, SU_TRUE); + return (SUCOMPLEX *)su_sigbuf_pool_get(pool, name, size, SU_TRUE); } SUBOOL @@ -239,22 +244,24 @@ void su_sigbuf_pool_debug(const su_sigbuf_pool_t *pool) { su_sigbuf_t *this; - unsigned int i; + unsigned int i = 0; size_t allocation = 0; size_t total = 0; SU_INFO("Pool `%s' status:\n", pool->name); SU_INFO(" ID Buf name Type Size Allocation size\n"); SU_INFO("------------------------------------------------\n"); - FOR_EACH_PTR(this, pool, sigbuf) { - allocation = this->size * - (this->is_complex ? sizeof (SUCOMPLEX) : sizeof (SUFLOAT)); - SU_INFO("[%2d] %-10s %-7s %8d %8d bytes\n", - i, - this->name, - this->is_complex ? "COMPLEX" : "FLOAT", - this->size, - allocation); + FOR_EACH_PTR(this, pool, sigbuf) + { + allocation = + this->size * (this->is_complex ? sizeof(SUCOMPLEX) : sizeof(SUFLOAT)); + SU_INFO( + "[%2d] %-10s %-7s %8d %8d bytes\n", + ++i, + this->name, + this->is_complex ? "COMPLEX" : "FLOAT", + this->size, + allocation); total += allocation; } @@ -262,7 +269,6 @@ su_sigbuf_pool_debug(const su_sigbuf_pool_t *pool) SU_INFO("Total: %d bytes\n", total); } - SUBOOL su_sigbuf_pool_dump(const su_sigbuf_pool_t *pool, enum sigutils_dump_format f) { @@ -285,4 +291,3 @@ su_sigbuf_pool_dump(const su_sigbuf_pool_t *pool, enum sigutils_dump_format f) return SU_TRUE; } - diff --git a/testutil/test.h b/testutil/test.h index bbf6f33..0963faf 100644 --- a/testutil/test.h +++ b/testutil/test.h @@ -20,12 +20,10 @@ #ifndef _TEST_H #define _TEST_H -#include - -#include #include - -#include +#include +#include +#include #define SU_SIGBUF_SAMPLING_FREQUENCY_DEFAULT 8000 @@ -46,15 +44,15 @@ enum sigutils_test_time_units { }; struct sigutils_sigbuf { - char *name; /* Buffer name */ - SUSCOUNT fs; /* Sampling frequency */ - size_t size; /* Buffer size */ - SUBOOL is_complex; /* Buffer type */ + char *name; /* Buffer name */ + SUSCOUNT fs; /* Sampling frequency */ + size_t size; /* Buffer size */ + SUBOOL is_complex; /* Buffer type */ union { void *buffer; SUCOMPLEX *as_complex; - SUFLOAT *as_float; + SUFLOAT *as_float; }; }; @@ -89,7 +87,7 @@ struct sigutils_test_context { typedef struct sigutils_test_context su_test_context_t; -typedef SUBOOL (*su_test_cb_t) (su_test_context_t *); +typedef SUBOOL (*su_test_cb_t)(su_test_context_t *); struct sigutils_test_entry { const char *name; @@ -98,79 +96,81 @@ struct sigutils_test_entry { typedef struct sigutils_test_entry su_test_entry_t; -#define su_test_run_params_INITIALIZER \ -{ \ - SU_TEST_SIGNAL_BUFFER_SIZE, /* buffer_size */ \ - SU_SIGBUF_SAMPLING_FREQUENCY_DEFAULT, /* fs */ \ - SU_DUMP_FORMAT_NONE /* dump_fmt */ \ -} - -#define SU_TEST_ENTRY(name) { STRINGIFY(name), name } - -#define su_test_context_INITIALIZER \ -{ \ - NULL, /* params */ \ - NULL, /* entry */ \ - NULL, /* pool */ \ - 0, /* testno */ \ - {0, 0}, /* start */ \ - {0, 0}, /* end */ \ - 0, /* elapsed_time */ \ - SU_TIME_UNITS_UNDEFINED /* time units */ \ -} - -#define SU_SYSCALL_ASSERT(expr) \ - if ((expr) < 0) { \ - SU_ERROR( \ - "Operation `%s' failed (negative value returned)\n", \ - STRINGIFY(expr)); \ - goto fail; \ +#define su_test_run_params_INITIALIZER \ + { \ + SU_TEST_SIGNAL_BUFFER_SIZE, /* buffer_size */ \ + SU_SIGBUF_SAMPLING_FREQUENCY_DEFAULT, /* fs */ \ + SU_DUMP_FORMAT_NONE /* dump_fmt */ \ } -#define SU_TEST_START(ctx) \ - printf("[t:%3d] %s: start\n", \ - ctx->testno, \ - ctx->entry->name); \ - gettimeofday(&ctx->start, NULL); \ - -#define SU_TEST_START_TICKLESS(ctx) \ - printf("[t:%3d] %s: start\n", \ - ctx->testno, \ - ctx->entry->name); - -#define SU_TEST_TICK(ctx) \ - gettimeofday(&ctx->start, NULL) \ - - -#define SU_TEST_END(ctx) \ - gettimeofday(&(ctx)->end, NULL); \ - su_test_context_update_times(ctx); \ - printf("[t:%3d] %s: end (%g %s)\n", \ - ctx->testno, \ - ctx->entry->name, \ - ctx->elapsed_time, \ - su_test_context_time_units(ctx)); \ - -#define SU_TEST_ASSERT(cond) \ - if (!(cond)) { \ - printf("[t:%3d] %s: assertion failed\n", \ - ctx->testno, \ - ctx->entry->name); \ - printf("[t:%3d] %s: !(%s)\n", \ - ctx->testno, \ - ctx->entry->name, \ - STRINGIFY(cond)); \ - goto done; \ - } +#define SU_TEST_ENTRY(name) \ + { \ + STRINGIFY(name), name \ + } +#define su_test_context_INITIALIZER \ + { \ + NULL, /* params */ \ + NULL, /* entry */ \ + NULL, /* pool */ \ + 0, /* testno */ \ + {0, 0}, /* start */ \ + {0, 0}, /* end */ \ + 0, /* elapsed_time */ \ + SU_TIME_UNITS_UNDEFINED /* time units */ \ + } + +#define SU_SYSCALL_ASSERT(expr) \ + if ((expr) < 0) { \ + SU_ERROR( \ + "Operation `%s' failed (negative value returned)\n", \ + STRINGIFY(expr)); \ + goto fail; \ + } + +#define SU_TEST_START(ctx) \ + printf("[t:%3u] %s: start\n", ctx->testno, ctx->entry->name); \ + gettimeofday(&ctx->start, NULL); + +#define SU_TEST_START_TICKLESS(ctx) \ + printf("[t:%3u] %s: start\n", ctx->testno, ctx->entry->name); + +#define SU_TEST_TICK(ctx) gettimeofday(&ctx->start, NULL) + +#define SU_TEST_END(ctx) \ + gettimeofday(&(ctx)->end, NULL); \ + su_test_context_update_times(ctx); \ + printf( \ + "[t:%3u] %s: end (%g %s)\n", \ + ctx->testno, \ + ctx->entry->name, \ + ctx->elapsed_time, \ + su_test_context_time_units(ctx)); + +#define SU_TEST_ASSERT(cond) \ + if (!(cond)) { \ + printf("[t:%3u] %s: assertion failed\n", ctx->testno, ctx->entry->name); \ + printf( \ + "[t:%3u] %s: !(%s)\n", \ + ctx->testno, \ + ctx->entry->name, \ + STRINGIFY(cond)); \ + goto done; \ + } void su_test_context_update_times(su_test_context_t *ctx); const char *su_test_context_time_units(const su_test_context_t *ctx); -SUFLOAT *su_test_ctx_getf_w_size(su_test_context_t *ctx, const char *name, SUSCOUNT size); +SUFLOAT *su_test_ctx_getf_w_size( + su_test_context_t *ctx, + const char *name, + SUSCOUNT size); -SUCOMPLEX *su_test_ctx_getc_w_size(su_test_context_t *ctx, const char *name, SUSCOUNT size); +SUCOMPLEX *su_test_ctx_getc_w_size( + su_test_context_t *ctx, + const char *name, + SUSCOUNT size); SUFLOAT *su_test_ctx_getf(su_test_context_t *ctx, const char *name); @@ -229,10 +229,8 @@ SUBOOL su_test_ctx_dumpc( const SUCOMPLEX *data, SUSCOUNT size); -SUBOOL su_test_ctx_resize_buf( - su_test_context_t *ctx, - const char *name, - SUSCOUNT size); +SUBOOL +su_test_ctx_resize_buf(su_test_context_t *ctx, const char *name, SUSCOUNT size); void su_sigbuf_set_fs(su_sigbuf_t *sbuf, SUSCOUNT fs); diff --git a/util/compat-fcntl.h b/util/compat-fcntl.h new file mode 100644 index 0000000..ba582cb --- /dev/null +++ b/util/compat-fcntl.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_FCNTL_H +#define _UTIL_COMPAT_FCNTL_H + +#ifdef _WIN32 +# include "win32-fcntl.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_FCNTL_H */ diff --git a/util/compat-in.h b/util/compat-in.h new file mode 100644 index 0000000..749d972 --- /dev/null +++ b/util/compat-in.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_IN_H +#define _UTIL_COMPAT_IN_H + +#ifdef _WIN32 +# include "win32-in.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_IN_H */ \ No newline at end of file diff --git a/util/compat-inet.h b/util/compat-inet.h new file mode 100644 index 0000000..6b241e0 --- /dev/null +++ b/util/compat-inet.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_INET_H +#define _UTIL_COMPAT_INET_H + +#ifdef _WIN32 +# include "win32-inet.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_INET_H */ \ No newline at end of file diff --git a/util/compat-mman.h b/util/compat-mman.h new file mode 100644 index 0000000..b56ba44 --- /dev/null +++ b/util/compat-mman.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_MMAN_H +#define _UTIL_COMPAT_MMAN_H + +#ifdef _WIN32 +# include "win32-mman.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_MMAN_H */ \ No newline at end of file diff --git a/util/compat-netdb.h b/util/compat-netdb.h new file mode 100644 index 0000000..2f8b52f --- /dev/null +++ b/util/compat-netdb.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_NETDB_H +#define _UTIL_COMPAT_NETDB_H + +#ifdef _WIN32 +# include "win32-netdb.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_NETDB_H */ \ No newline at end of file diff --git a/util/compat-poll.h b/util/compat-poll.h new file mode 100644 index 0000000..206c564 --- /dev/null +++ b/util/compat-poll.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_POLL_H +#define _UTIL_COMPAT_POLL_H + +#ifdef _WIN32 +# include "win32-poll.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_POLL_H */ \ No newline at end of file diff --git a/util/compat-pwd.h b/util/compat-pwd.h new file mode 100644 index 0000000..9a1c38a --- /dev/null +++ b/util/compat-pwd.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_PWD_H +#define _UTIL_COMPAT_PWD_H + +#ifdef _WIN32 +# include "win32-pwd.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_PWD_H */ \ No newline at end of file diff --git a/util/compat-select.h b/util/compat-select.h new file mode 100644 index 0000000..282ec5b --- /dev/null +++ b/util/compat-select.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_SELECT_H +#define _UTIL_COMPAT_SELECT_H + +#ifdef _WIN32 +# include "win32-time.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_SELECT_H */ \ No newline at end of file diff --git a/util/compat-socket.h b/util/compat-socket.h new file mode 100644 index 0000000..09125ca --- /dev/null +++ b/util/compat-socket.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_SOCKET_H +#define _UTIL_COMPAT_SOCKET_H + +#ifdef _WIN32 +# include "win32-socket.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_SOCKET_H */ \ No newline at end of file diff --git a/util/compat-stat.h b/util/compat-stat.h new file mode 100644 index 0000000..cfe780a --- /dev/null +++ b/util/compat-stat.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_STAT_H +#define _UTIL_COMPAT_STAT_H + +#ifdef _WIN32 +# include "win32-stat.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_STAT_H */ \ No newline at end of file diff --git a/util/compat-statvfs.h b/util/compat-statvfs.h new file mode 100644 index 0000000..93ce848 --- /dev/null +++ b/util/compat-statvfs.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_STATVFS_H +#define _UTIL_COMPAT_STATVFS_H + +#ifdef _WIN32 +# include "win32-statvfs.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_STATVFS_H */ diff --git a/util/compat-stdlib.h b/util/compat-stdlib.h new file mode 100644 index 0000000..4a78205 --- /dev/null +++ b/util/compat-stdlib.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_STDLIB_H +#define _UTIL_COMPAT_STDLIB_H + +#ifdef _WIN32 +# include "win32-stdlib.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_STDLIB_H */ \ No newline at end of file diff --git a/util/compat-termios.h b/util/compat-termios.h new file mode 100644 index 0000000..5b36e63 --- /dev/null +++ b/util/compat-termios.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_TERMIOS_H +#define _UTIL_COMPAT_TERMIOS_H + +#ifdef _WIN32 +# include "win32-termios.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_TERMIOS_H */ \ No newline at end of file diff --git a/util/compat-time.h b/util/compat-time.h new file mode 100644 index 0000000..39389aa --- /dev/null +++ b/util/compat-time.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_TIME_H +#define _UTIL_COMPAT_TIME_H + +#ifdef _WIN32 +# include /* nanosleep() */ +# include /* rest of time.h (time(), ctime()) */ + +# include "win32-time.h" /* timersub() */ +#else +# include +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_TIME_H */ \ No newline at end of file diff --git a/util/compat-unistd.h b/util/compat-unistd.h new file mode 100644 index 0000000..7f3dd7f --- /dev/null +++ b/util/compat-unistd.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_COMPAT_UNISTD_H +#define _UTIL_COMPAT_UNISTD_H + +#ifdef _WIN32 +# include "win32-unistd.h" +#else +# include +#endif /* _WIN32 */ + +#endif /* _UTIL_COMPAT_UNISTD_H */ \ No newline at end of file diff --git a/util/util.c b/util/util.c index 2264117..70a7832 100644 --- a/util/util.c +++ b/util/util.c @@ -1,7 +1,6 @@ /* - Copyright (C) 2013 Gonzalo José Carracedo Carballal - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 3. @@ -14,37 +13,38 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see - */ +#include "util.h" + +#include +#include +#include #include #include -#include -#include -#include -#include +#include #include +#include -#include "util.h" - -#define STRBUILD_BSIZ 16 -#define DEBUG_BACKTRACE_NFUNCS 48 +#define STRBUILD_BSIZ 16 +#define DEBUG_BACKTRACE_NFUNCS 48 int saved_errno; -void errno_save () +void +errno_save() { saved_errno = errno; } -void errno_restore () +void +errno_restore() { errno = saved_errno; } /* Prototipos de funciones estaticas */ -static void xalloc_die (void); - +static void xalloc_die(void); int is_asciiz(const char *buf, int lbound, int ubound) @@ -60,252 +60,245 @@ is_asciiz(const char *buf, int lbound, int ubound) char * vstrbuild(const char *fmt, va_list ap) { - char *out; + char *out = NULL, *tmp = NULL; + char *result = NULL; + int size, zeroindex; int last; va_list copy; - + last = 0; - + if (fmt != NULL) { if (!*fmt) { - out = malloc(1); - out[0] = '\0'; - return out; + result = strdup(""); + goto done; } - + va_copy(copy, ap); size = vsnprintf(NULL, 0, fmt, copy) + 1; va_end(copy); - + if ((out = malloc(size)) == NULL) - return NULL; - + goto done; + va_copy(copy, ap); vsnprintf(out, size, fmt, copy); va_end(copy); - + for (;;) { if ((zeroindex = is_asciiz(out, last, size)) != 0) break; last = size; size += STRBUILD_BSIZ; - - out = realloc(out, size); /* Reasignamos */ - - va_copy (copy, ap); + + tmp = realloc(out, size); /* Reasignamos */ + if (tmp == NULL) + goto done; + + out = tmp; + + va_copy(copy, ap); vsnprintf(out, size, fmt, copy); - va_end (copy); + va_end(copy); } - } - else + + result = out; out = NULL; - - return out; -} + } +done: + if (out != NULL) + free(out); + + return result; +} /* Construye una cadena mediante el formato printf y devuelve un puntero a la cadena resultado. DEBES liberar tu mismo la salida. */ /* FIXME: Buscar alguna alternativa mas portable */ -char* -strbuild (const char *fmt, ...) +char * +strbuild(const char *fmt, ...) { char *out; va_list ap; - va_start (ap, fmt); - out = vstrbuild (fmt, ap); - va_end (ap); + va_start(ap, fmt); + out = vstrbuild(fmt, ap); + va_end(ap); return out; } /* Wrapper para malloc que autocomprueba el valor de retorno */ -void* -xmalloc (size_t size) +void * +xmalloc(size_t size) { - void* m; - - m = malloc (size); + void *m; + + m = malloc(size); if (m == NULL) - xalloc_die (); - + xalloc_die(); + return m; } /* Wrapper para realloc */ -void* -xrealloc (void* ptr, size_t new_size) +void * +xrealloc(void *ptr, size_t new_size) { - void* m; - - m = realloc (ptr, new_size); - + void *m; + + m = realloc(ptr, new_size); + if (m == NULL) - xalloc_die (); + xalloc_die(); return m; } - /* Wrapper para strdup */ char * -xstrdup (const char *str) +xstrdup(const char *str) { char *ret; - if (str != NULL) - { - ret = xmalloc (strlen (str) + 1); - strcpy (ret, str); - } - else + if (str != NULL) { + ret = xmalloc(strlen(str) + 1); + strcpy(ret, str); + } else ret = NULL; - + return ret; } /* Cuando nos quedamos sin memoria... */ static void -xalloc_die (void) +xalloc_die(void) { - abort (); + abort(); } /* Para manipular arrays de punteros */ int -ptr_list_append_check (void ***list, unsigned int *count, void *new) +ptr_list_append_check(void ***list, unsigned int *count, void *new) { - int i; + unsigned int i; void **reallocd_list; - + for (i = 0; i < *count; i++) if ((*list)[i] == NULL) break; - - if (i == *count) - { - if ((reallocd_list = xrealloc (*list, (1 + *count) * sizeof (void *))) == NULL) + + if (i == *count) { + if ((reallocd_list = xrealloc(*list, (1 + *count) * sizeof(void *))) + == NULL) return -1; - else - { + else { ++(*count); *list = reallocd_list; } } - + (*list)[i] = new; - + return i; } void -ptr_list_append (void ***list, unsigned int *count, void *new) +ptr_list_append(void ***list, unsigned int *count, void *new) { - (void) ptr_list_append_check (list, count, new); + (void)ptr_list_append_check(list, count, new); } int -ptr_list_remove_first (void ***list, unsigned int *count, void *ptr) +ptr_list_remove_first(void ***list, unsigned int *count, void *ptr) { - int i; + unsigned int i; int found; - + found = 0; - + for (i = 0; i < *count; i++) - if ((*list)[i] == ptr || ptr == NULL) - { + if ((*list)[i] == ptr || ptr == NULL) { (*list)[i] = NULL; found++; - + break; } - + return found; } - int -ptr_list_remove_all (void ***list, int *count, void *ptr) +ptr_list_remove_all(void ***list, int *count, void *ptr) { int i; int found; - + found = 0; - + for (i = 0; i < *count; i++) - if ((*list)[i] == ptr || ptr == NULL) - { + if ((*list)[i] == ptr || ptr == NULL) { (*list)[i] = NULL; found++; } - + return found; } - char * -str_append_char (char* source, char c) +str_append_char(char *source, char c) { int strsiz; char *nptr; - strsiz = source == NULL ? 1 : strlen (source) + 1; + strsiz = source == NULL ? 1 : strlen(source) + 1; - nptr = (char *) xrealloc ( (void *) source, strsiz + 1); + nptr = (char *)xrealloc((void *)source, strsiz + 1); if (nptr == NULL) return NULL; nptr[strsiz - 1] = c; - nptr[strsiz] = '\0'; + nptr[strsiz] = '\0'; return nptr; } char * -fread_line (FILE *fp) +fread_line(FILE *fp) { char c; char *line; int buffer_size; int n; - + line = NULL; - - for (buffer_size = n = 0; (c = fgetc (fp)) != EOF; n++) - { - if (c == '\r') - { + for (buffer_size = n = 0; (c = fgetc(fp)) != EOF; n++) { + if (c == '\r') { n--; continue; } - - if (c == '\n') - { + + if (c == '\n') { if (line == NULL) - line = xstrdup (""); - + line = xstrdup(""); + break; } - - if (buffer_size < (n + 1)) - { - if (buffer_size) - { + + if (buffer_size < (n + 1)) { + if (buffer_size) { buffer_size <<= 1; - line = xrealloc (line, buffer_size + 1); - } - else - { + line = xrealloc(line, buffer_size + 1); + } else { buffer_size = STRBUILD_BSIZ; - line = xmalloc (buffer_size + 1); + line = xmalloc(buffer_size + 1); } } @@ -314,159 +307,162 @@ fread_line (FILE *fp) if (line != NULL) line[n] = '\0'; - + return line; } /* Todo: this is interesting. Export if necessary */ struct strlist * -strlist_new (void) +strlist_new(void) { struct strlist *new; - - new = xmalloc (sizeof (struct strlist)); - - memset (new, 0, sizeof (struct strlist)); - + + new = xmalloc(sizeof(struct strlist)); + + memset(new, 0, sizeof(struct strlist)); + return new; } void -strlist_append_string (struct strlist *list, const char *string) +strlist_append_string(struct strlist *list, const char *string) { - ptr_list_append ((void ***) &list->strings_list, &list->strings_count, - xstrdup (string)); + ptr_list_append( + (void ***)&list->strings_list, + &list->strings_count, + xstrdup(string)); } void -strlist_walk (struct strlist *list, - void *data, - void (*walk) (const char *, void *)) +strlist_walk( + struct strlist *list, + void *data, + void (*walk)(const char *, void *)) { - int i; - + unsigned int i; + for (i = 0; i < list->strings_count; i++) if (list->strings_list[i] != NULL) - (walk) (list->strings_list[i], data); + (walk)(list->strings_list[i], data); } void -strlist_destroy (struct strlist *list) +strlist_destroy(struct strlist *list) { - int i; - + unsigned int i; + for (i = 0; i < list->strings_count; i++) if (list->strings_list[i] != NULL) - free (list->strings_list[i]); - + free(list->strings_list[i]); + if (list->strings_list != NULL) - free (list->strings_list); - - free (list); + free(list->strings_list); + + free(list); } int -strlist_have_element (const struct strlist *list, const char *string) +strlist_have_element(const struct strlist *list, const char *string) { - int i; - + unsigned int i; + for (i = 0; i < list->strings_count; i++) if (list->strings_list[i] != NULL) - if (strcmp (list->strings_list[i], string) == 0) + if (strcmp(list->strings_list[i], string) == 0) return 1; - + return 0; } void -strlist_cat (struct strlist *dest, const struct strlist *list) +strlist_cat(struct strlist *dest, const struct strlist *list) { - int i; - + unsigned int i; + for (i = 0; i < list->strings_count; i++) if (list->strings_list[i] != NULL) - strlist_append_string (dest, list->strings_list[i]); + strlist_append_string(dest, list->strings_list[i]); } void -strlist_union (struct strlist *dest, const struct strlist *list) +strlist_union(struct strlist *dest, const struct strlist *list) { - int i; - + unsigned int i; + for (i = 0; i < list->strings_count; i++) if (list->strings_list[i] != NULL) - if (!strlist_have_element (dest, list->strings_list[i])) - strlist_append_string (dest, list->strings_list[i]); + if (!strlist_have_element(dest, list->strings_list[i])) + strlist_append_string(dest, list->strings_list[i]); } void -strlist_debug (const struct strlist *list) +strlist_debug(const struct strlist *list) { - int i; - + unsigned int i; + for (i = 0; i < list->strings_count; i++) if (list->strings_list[i] != NULL) - fprintf (stderr, "%3d. %s\n", i, list->strings_list[i]); + fprintf(stderr, "%3u. %s\n", i, list->strings_list[i]); else - fprintf (stderr, "\n"); + fprintf(stderr, "\n"); } - -/* +/* Bit layout of returned byte: 8 4 0 MMMMDDDDD */ void -al_append_argument (arg_list_t* al, const char* arg) +al_append_argument(arg_list_t *al, const char *arg) { char *ptr; char **argl; - ptr = (char *) xstrdup (arg); + ptr = (char *)xstrdup(arg); - argl = (char **) xrealloc ( (void *) al->al_argv, sizeof (char *) * (al->al_argc + 1)); + argl = (char **)xrealloc( + (void *)al->al_argv, + sizeof(char *) * (al->al_argc + 1)); argl[al->al_argc++] = ptr; al->al_argv = argl; } -void -free_al (arg_list_t* al) +void +free_al(arg_list_t *al) { int i; for (i = 0; i < al->al_argc; i++) - free (al->al_argv[i]); + free(al->al_argv[i]); if (al->al_line != NULL) - free (al->al_line); - - free (al->al_argv); - free (al); -} + free(al->al_line); + free(al->al_argv); + free(al); +} -static arg_list_t * -__split_command (const char *line, char *separators, int fixed_sep_size) +static arg_list_t * +__split_command(const char *line, char *separators, int fixed_sep_size) { - int p, i; + size_t i; int split_flag; int escape_flag; char *nptr; char *this_argument; - arg_list_t* arg_info; + arg_list_t *arg_info; - arg_info = (arg_list_t *) xmalloc (sizeof (arg_list_t)); + arg_info = (arg_list_t *)xmalloc(sizeof(arg_list_t)); arg_info->al_argc = 0; arg_info->al_argv = NULL; arg_info->al_line = NULL; - + this_argument = NULL; split_flag = 1; @@ -475,41 +471,33 @@ __split_command (const char *line, char *separators, int fixed_sep_size) i = 0; if (!fixed_sep_size) - while (strchr (separators, line[i]) && line[i] != '\0') + while (strchr(separators, line[i]) && line[i] != '\0') i++; - for (; i < strlen (line); i++) - { - if (strchr (separators, line[i]) && split_flag && !escape_flag) - { - if (this_argument == NULL) - { + for (; i < strlen(line); i++) { + if (strchr(separators, line[i]) && split_flag && !escape_flag) { + if (this_argument == NULL) { if (fixed_sep_size) - al_append_argument (arg_info, ""); + al_append_argument(arg_info, ""); continue; - } - else - { - al_append_argument (arg_info, this_argument); + } else { + al_append_argument(arg_info, this_argument); - free (this_argument); + free(this_argument); this_argument = NULL; } - } - else if (line[i] == '"' && !escape_flag) + } else if (line[i] == '"' && !escape_flag) split_flag = !split_flag; else if (line[i] == '\\' && !escape_flag) escape_flag = 1; /* else if (line[i] == '#' && split_flag && !escape_flag) break; */ - else - { - nptr = str_append_char (this_argument, line[i]); + else { + nptr = str_append_char(this_argument, line[i]); - if (nptr == NULL) - { - free (this_argument); - free_al (arg_info); + if (nptr == NULL) { + free(this_argument); + free_al(arg_info); return NULL; } @@ -518,178 +506,168 @@ __split_command (const char *line, char *separators, int fixed_sep_size) } } - if (this_argument != NULL) - { - al_append_argument (arg_info, this_argument); - free (this_argument); + if (this_argument != NULL) { + al_append_argument(arg_info, this_argument); + free(this_argument); } return arg_info; } -arg_list_t * -csv_split_line (const char *line) +arg_list_t * +csv_split_line(const char *line) { - return __split_command (line, ",", 1); + return __split_command(line, ",", 1); } arg_list_t * -split_line (const char *line) +split_line(const char *line) { - return __split_command (line, " ", 0); + return __split_command(line, " ", 0); } int -lscanf_huge (const char *fmt, ...) +lscanf_huge(const char *fmt, ...) { char *line; int result; va_list ap; - - va_start (ap, fmt); - - if ((line = fread_line (stdin)) == NULL) - result = -1; - else - { - result = vsscanf (line, fmt, ap); - free (line); + + va_start(ap, fmt); + + if ((line = fread_line(stdin)) == NULL) + result = -1; + else { + result = vsscanf(line, fmt, ap); + free(line); } - - va_end (ap); - + + va_end(ap); + return result; } - int -lscanf (const char *fmt, ...) +lscanf(const char *fmt, ...) { char line[RECOMMENDED_LINE_SIZE]; int result; va_list ap; - - va_start (ap, fmt); - - if (fgets (line, RECOMMENDED_LINE_SIZE - 1, stdin) == NULL) - result = -1; + + va_start(ap, fmt); + + if (fgets(line, RECOMMENDED_LINE_SIZE - 1, stdin) == NULL) + result = -1; else - result = vsscanf (line, fmt, ap); - - va_end (ap); - + result = vsscanf(line, fmt, ap); + + va_end(ap); + return result; } char * -ltrim (const char *str) +ltrim(const char *str) { while (*str) - if (!isspace (*str)) + if (!isspace(*str)) break; else str++; - - return xstrdup (str); + + return xstrdup(str); } char * -rtrim (const char *str) +rtrim(const char *str) { - int i; char *copy; char *tail; - - copy = xstrdup (str); - - for (tail = copy + strlen (copy) - 1; (unsigned long) copy <= (unsigned long) tail; tail--) - { - if (!isspace (*tail)) + + copy = xstrdup(str); + + for (tail = copy + strlen(copy) - 1; (uintptr_t)copy <= (uintptr_t)tail; + tail--) { + if (!isspace(*tail)) break; *tail = '\0'; } - + return copy; } char * -trim (const char *str) +trim(const char *str) { - int i; char *copy; char *tail; while (*str) - if (!isspace (*str)) + if (!isspace(*str)) break; else str++; - - copy = xstrdup (str); - - for (tail = copy + strlen (copy) - 1; (unsigned long) copy <= (unsigned long) tail; tail--) - { - if (!isspace (*tail)) + + copy = xstrdup(str); + + for (tail = copy + strlen(copy) - 1; (uintptr_t)copy <= (uintptr_t)tail; + tail--) { + if (!isspace(*tail)) break; *tail = '\0'; } - + return copy; } -/* +/* Bit layout of returned byte: 8 4 0 MMMMDDDDD */ - + unsigned int -yday_to_daymonth (int yday, int year) +yday_to_daymonth(int yday, int year) { int monthdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int month = 0; - + yday--; - - if ((year % 4 == 0) && ((!(year % 100 == 0)) || (year % 400 == 0))) + + if ((year % 4 == 0) && ((!(year % 100 == 0)) || (year % 400 == 0))) monthdays[1] = 29; - - while (monthdays[month] <= yday) - { + + while (monthdays[month] <= yday) { yday -= monthdays[month++]; if (month == 12) return 0; } - + return yday | (month << 5); } char * -get_curr_ctime (void) +get_curr_ctime(void) { time_t now; char *text; - time (&now); - - text = ctime (&now); - + time(&now); + + text = ctime(&now); + text[24] = 0; - + return text; } void -grow_buf_init_loan( - grow_buf_t *buf, - const void *data, - size_t size, - size_t alloc) +grow_buf_init_loan(grow_buf_t *buf, const void *data, size_t size, size_t alloc) { - buf->buffer = (void *) data; - buf->alloc = alloc; - buf->size = size; - buf->ptr = 0; - buf->loan = 1; + buf->buffer = (void *)data; + buf->alloc = alloc; + buf->size = size; + buf->ptr = 0; + buf->loan = 1; } void @@ -736,7 +714,7 @@ grow_buf_alloc(grow_buf_t *buf, size_t size) buf->alloc = alloc; } - tmp = (char *) buf->buffer + buf->size; + tmp = (char *)buf->buffer + buf->size; buf->size = total_size; return tmp; @@ -802,7 +780,7 @@ grow_buf_append_printf(grow_buf_t *buf, const char *fmt, ...) ssize_t grow_buf_read(grow_buf_t *buf, void *data, size_t size) { - ssize_t avail = grow_buf_avail(buf); + size_t avail = grow_buf_avail(buf); if (size > avail) size = avail; @@ -871,7 +849,6 @@ grow_buf_shrink(grow_buf_t *buf) buf->ptr = 0; } - void grow_buf_clear(grow_buf_t *buf) { @@ -902,7 +879,7 @@ grow_buf_seek(grow_buf_t *buf, off_t offset, int whence) return -1; } - if (new_off < 0 || new_off > buf->size) { + if (new_off < 0 || (size_t)new_off > buf->size) { errno = EINVAL; return -1; } @@ -915,14 +892,8 @@ grow_buf_seek(grow_buf_t *buf, off_t offset, int whence) int grow_buf_transfer(grow_buf_t *dest, grow_buf_t *src) { - void *new = NULL; - - if ((new = grow_buf_alloc(dest, src->size)) == NULL) - return -1; - - memcpy(new, src->buffer, src->size); - grow_buf_seek(new, src->size, SEEK_CUR); - grow_buf_clear(src); + memcpy(dest, src, sizeof(grow_buf_t)); + memset(src, 0, sizeof(grow_buf_t)); return 0; } diff --git a/util/util.h b/util/util.h index c6166a4..ccf3166 100644 --- a/util/util.h +++ b/util/util.h @@ -1,7 +1,6 @@ /* - Copyright (C) 2013 Gonzalo José Carracedo Carballal - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 3. @@ -14,24 +13,23 @@ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see - */ #ifndef _UTIL_H #define _UTIL_H -#include -#include #include #include +#include +#include #include #include #ifdef linux -# include -# define TID_FUNC (int) syscall (224) +# include +# define TID_FUNC (int)syscall(224) #else -# define TID_FUNC (int) getpid () +# define TID_FUNC (int)getpid() #endif #define RECOMMENDED_LINE_SIZE 256 @@ -48,105 +46,114 @@ # define SIGN(x) (!(x < 0) - !(x > 0)) #endif -#define _JOIN(a, b) a ## b +#define _JOIN(a, b) a##b #define JOIN(a, b) _JOIN(a, b) #define _STRINGIFY(x) #x -#define STRINGIFY(x) _STRINGIFY (x) +#define STRINGIFY(x) _STRINGIFY(x) #define IN_BOUNDS(x, range) (((x) >= 0) && ((x) < (range))) -#define PTR_LIST(type, name) \ - type **name ## _list; \ - unsigned int name ## _count; - -#define PTR_LIST_PRIVATE(type, name) \ - SUPRIVATE type **name ## _list; \ - SUPRIVATE unsigned int name ## _count; - -#define PTR_LIST_CONST(type, name) \ - const type **name ## _list; \ - unsigned int name ## _count; - -#define PTR_LIST_LOCAL(type, name) \ - type **name ## _list = NULL; \ - unsigned int name ## _count = 0; - -#define PTR_LIST_EXTERN(type, name) \ - extern type **name ## _list; \ - extern unsigned int name ## _count; - -#define PTR_LIST_INIT(where, name) \ - where->name ## _list = NULL; \ - where->name ## _count = 0; - -#define PTR_LIST_APPEND(name, ptr) \ - ptr_list_append ((void ***) &JOIN (name, _list), \ - &JOIN (name, _count), ptr) - -#define PTR_LIST_APPEND_CHECK(name, ptr) \ - ptr_list_append_check ((void ***) &JOIN (name, _list), \ - &JOIN (name, _count), ptr) - -#define PTR_LIST_REMOVE(name, ptr) \ - ptr_list_remove_first ((void ***) &JOIN (name, _list), \ - &JOIN (name, _count), ptr) - -#define FOR_EACH_PTR_STANDALONE(this, name) \ - unsigned int JOIN (_idx_, __LINE__); \ - for (JOIN (_idx_, __LINE__) = 0; \ - JOIN (_idx_, __LINE__) < name ## _count; \ - JOIN (_idx_, __LINE__)++) \ - if ((this = name ## _list[ \ - JOIN (_idx_, __LINE__)]) != NULL) - -#define FOR_EACH_PTR(this, where, name) \ - unsigned int JOIN (_idx_, __LINE__); \ - for (JOIN (_idx_, __LINE__) = 0; \ - JOIN (_idx_, __LINE__) < where->name ## _count; \ - JOIN (_idx_, __LINE__)++) \ - if ((this = where->name ## _list[ \ - JOIN (_idx_, __LINE__)]) != NULL) - -# define __UNITS(x, wrdsiz) ((((x) + (wrdsiz - 1)) / wrdsiz)) -# define __ALIGN(x, wrdsiz) (__UNITS(x, wrdsiz) * wrdsiz) - - -struct strlist -{ - PTR_LIST (char, strings); +#define PTR_LIST(type, name) \ + type **name##_list; \ + unsigned int name##_count; + +#define PTR_LIST_PRIVATE(type, name) \ + SUPRIVATE type **name##_list; \ + SUPRIVATE unsigned int name##_count; + +#define PTR_LIST_CONST(type, name) \ + const type **name##_list; \ + unsigned int name##_count; + +#define PTR_LIST_PRIVATE_CONST(type, name) \ + SUPRIVATE const type **name##_list; \ + SUPRIVATE unsigned int name##_count; + +#define PTR_LIST_LOCAL(type, name) \ + type **name##_list = NULL; \ + unsigned int name##_count = 0; + +#define PTR_LIST_EXTERN(type, name) \ + extern type **name##_list; \ + extern unsigned int name##_count; + +#define PTR_LIST_INIT(where, name) \ + where->name##_list = NULL; \ + where->name##_count = 0; + +#define PTR_LIST_APPEND(name, ptr) \ + ptr_list_append((void ***)&JOIN(name, _list), &JOIN(name, _count), ptr) + +#define PTR_LIST_APPEND_CHECK(name, ptr) \ + ptr_list_append_check((void ***)&JOIN(name, _list), &JOIN(name, _count), ptr) + +#define PTR_LIST_REMOVE(name, ptr) \ + ptr_list_remove_first((void ***)&JOIN(name, _list), &JOIN(name, _count), ptr) + +#define FOR_EACH_PTR_STANDALONE(this, name) \ + unsigned int JOIN(_idx_, __LINE__); \ + for (JOIN(_idx_, __LINE__) = 0; JOIN(_idx_, __LINE__) < name##_count; \ + JOIN(_idx_, __LINE__)++) \ + if ((this = name##_list[JOIN(_idx_, __LINE__)]) != NULL) + +#define FOR_EACH_PTR(this, where, name) \ + unsigned int JOIN(_idx_, __LINE__); \ + for (JOIN(_idx_, __LINE__) = 0; JOIN(_idx_, __LINE__) < where->name##_count; \ + JOIN(_idx_, __LINE__)++) \ + if ((this = where->name##_list[JOIN(_idx_, __LINE__)]) != NULL) + +#define __UNITS(x, wrdsiz) ((((x) + (wrdsiz - 1)) / wrdsiz)) +#define __ALIGN(x, wrdsiz) (__UNITS(x, wrdsiz) * wrdsiz) + +#ifdef __GNUC__ +# define IGNORE_RESULT(type, expr) \ + do { \ + type ignored_val__ __attribute__((unused)); \ + ignored_val__ = expr; \ + } while (0) +#else +# define IGNORE_RESULT(type, expr) (void)expr +#endif /* __GNUC__ */ + +struct strlist { + PTR_LIST(char, strings); }; -typedef struct _al -{ - int al_argc; +typedef struct _al { + int al_argc; char **al_argv; - char *al_line; -} -arg_list_t; + char *al_line; +} arg_list_t; struct grow_buf { size_t ptr; size_t size; size_t alloc; - int loan; + int loan; union { - void *buffer; + void *buffer; unsigned char *bytes; }; }; typedef struct grow_buf grow_buf_t; -#define grow_buf_INITIALIZER {0, 0, 0, 0, {NULL}} +#define grow_buf_INITIALIZER \ + { \ + 0, 0, 0, 0, \ + { \ + NULL \ + } \ + } #define GROW_BUF_STRCAT(gbuf, str) grow_buf_append((gbuf), (str), strlen(str)) -void al_append_argument (arg_list_t *, const char*); -void free_al (arg_list_t *); +void al_append_argument(arg_list_t *, const char *); +void free_al(arg_list_t *); -arg_list_t *csv_split_line (const char *); -arg_list_t *split_line (const char *); +arg_list_t *csv_split_line(const char *); +arg_list_t *split_line(const char *); void grow_buf_init(grow_buf_t *buf); void grow_buf_init_loan( @@ -173,41 +180,40 @@ void grow_buf_clear(grow_buf_t *buf); size_t grow_buf_seek(grow_buf_t *buf, off_t offset, int whence); int grow_buf_transfer(grow_buf_t *dest, grow_buf_t *src); -void *xmalloc (size_t siz); -void *xrealloc (void *p, size_t siz); -char *xstrdup (const char *s); -int is_asciiz (const char *buf, int lbound, int ubound); -char *vstrbuild (const char *fmt, va_list ap); -char *strbuild (const char *fmt, ...); -char *str_append_char (char* source, char c); -char *fread_line (FILE *fp); -void ptr_list_append (void ***, unsigned int *, void *); -int ptr_list_append_check (void ***, unsigned int *, void *); -int ptr_list_remove_first (void ***, unsigned int *, void *); -int ptr_list_remove_all (void ***, int *, void *); - -void errno_save (void); -void errno_restore (void); - -struct strlist *strlist_new (void); -void strlist_append_string (struct strlist *, const char *); -void strlist_walk (struct strlist *, void *, void (*) (const char *, void *)); -void strlist_destroy (struct strlist *); -void strlist_debug (const struct strlist *); -void strlist_cat (struct strlist *, const struct strlist *); -void strlist_union (struct strlist *, const struct strlist *); -int strlist_have_element (const struct strlist *, const char *); -unsigned int yday_to_daymonth (int, int); - -char *trim (const char *); -char *rtrim (const char *); -char *ltrim (const char *); -int lscanf (const char *, ...); -int lscanf_huge (const char *, ...); +void *xmalloc(size_t siz); +void *xrealloc(void *p, size_t siz); +char *xstrdup(const char *s); +int is_asciiz(const char *buf, int lbound, int ubound); +char *vstrbuild(const char *fmt, va_list ap); +char *strbuild(const char *fmt, ...); +char *str_append_char(char *source, char c); +char *fread_line(FILE *fp); +void ptr_list_append(void ***, unsigned int *, void *); +int ptr_list_append_check(void ***, unsigned int *, void *); +int ptr_list_remove_first(void ***, unsigned int *, void *); +int ptr_list_remove_all(void ***, int *, void *); + +void errno_save(void); +void errno_restore(void); + +struct strlist *strlist_new(void); +void strlist_append_string(struct strlist *, const char *); +void strlist_walk(struct strlist *, void *, void (*)(const char *, void *)); +void strlist_destroy(struct strlist *); +void strlist_debug(const struct strlist *); +void strlist_cat(struct strlist *, const struct strlist *); +void strlist_union(struct strlist *, const struct strlist *); +int strlist_have_element(const struct strlist *, const char *); +unsigned int yday_to_daymonth(int, int); + +char *trim(const char *); +char *rtrim(const char *); +char *ltrim(const char *); +int lscanf(const char *, ...); +int lscanf_huge(const char *, ...); #ifdef __sun__ /* puto Solaris */ -int dprintf (int fd, const char *fmt, ...); +int dprintf(int fd, const char *fmt, ...); #endif #endif /* _UTIL_H */ - diff --git a/util/win32-fcntl.c b/util/win32-fcntl.c new file mode 100644 index 0000000..fd50946 --- /dev/null +++ b/util/win32-fcntl.c @@ -0,0 +1,38 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + 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 Lesser 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 + +*/ + +#include "win32-fcntl.h" + +#include "win32-socket.h" + +/* WARN: EXTREMELY ADHOC */ +int +fcntl(int fd, int cmd, ... /* arg */) +{ + switch (cmd) { + case F_GETFL: { + /* Assume suscan just wants whatever flags the fd has and add O_NONBLOCK + * to them, so it doesn't matter what this returns */ + return 0; + } break; + case F_SETFL: { + /* Assume suscan always wants to set fd to non blocking mode */ + u_long iMode = 0; + int iResult = ioctlsocket(fd, FIONBIO, &iMode); + if (iResult != NO_ERROR) + return -1; + } break; + } + return 0; +} \ No newline at end of file diff --git a/util/win32-fcntl.h b/util/win32-fcntl.h new file mode 100644 index 0000000..b954eda --- /dev/null +++ b/util/win32-fcntl.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_FCNTL_H +#define _UTIL_FCNTL_H + +#define _O_BINARY 0x8000 /* Input and output is not translated. */ + +#define F_GETFL 3 /* Get file flags */ +#define F_SETFL 4 /* Set file flags */ + +#define O_NONBLOCK 0x4000 /* Non blocking I/O (POSIX style) */ + +#include + +int fcntl(int fd, int cmd, ... /* arg */); + +#endif /* _UTIL_FCNTL_H */ \ No newline at end of file diff --git a/util/win32-in.h b/util/win32-in.h new file mode 100644 index 0000000..a65ba3c --- /dev/null +++ b/util/win32-in.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_IN_H +#define _UTIL_IN_H + +#define WIN32_LEAN_AND_MEAN +#include +#include + +/* for gods sake microsoft */ +#ifdef interface +# undef interface +#endif /* interface */ + +#endif /* _UTIL_IN_H */ \ No newline at end of file diff --git a/util/win32-inet.h b/util/win32-inet.h new file mode 100644 index 0000000..8238b2f --- /dev/null +++ b/util/win32-inet.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_INET_H +#define _UTIL_INET_H + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#define getsockopt(sockfd, level, optname, optval, optLen) \ + getsockopt(sockfd, level, optname, (char *)optval, optLen) + +#ifdef interface +# undef interface +#endif /* interface */ + +#endif /* _UTIL_INET_H */ \ No newline at end of file diff --git a/util/win32-mman.c b/util/win32-mman.c new file mode 100644 index 0000000..23308de --- /dev/null +++ b/util/win32-mman.c @@ -0,0 +1,201 @@ +// Source: https://github.com/klauspost/mman-win32 (unlicensed) + +/* + Copyright (C) 2012 Klaus Post + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + 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 Lesser 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 + +*/ + +#include "win32-mman.h" + +#include +#include +#include + +#ifndef FILE_MAP_EXECUTE +# define FILE_MAP_EXECUTE 0x0020 +#endif /* FILE_MAP_EXECUTE */ + +static int +__map_mman_error(const DWORD err, const int deferr) +{ + if (err == 0) + return 0; + // TODO: implement + return err; +} + +static DWORD +__map_mmap_prot_page(const int prot) +{ + DWORD protect = 0; + + if (prot == PROT_NONE) + return protect; + + if ((prot & PROT_EXEC) != 0) { + protect = + ((prot & PROT_WRITE) != 0) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; + } else { + protect = ((prot & PROT_WRITE) != 0) ? PAGE_READWRITE : PAGE_READONLY; + } + + return protect; +} + +static DWORD +__map_mmap_prot_file(const int prot) +{ + DWORD desiredAccess = 0; + + if (prot == PROT_NONE) + return desiredAccess; + + if ((prot & PROT_READ) != 0) + desiredAccess |= FILE_MAP_READ; + if ((prot & PROT_WRITE) != 0) + desiredAccess |= FILE_MAP_WRITE; + if ((prot & PROT_EXEC) != 0) + desiredAccess |= FILE_MAP_EXECUTE; + + return desiredAccess; +} + +void * +mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) +{ + HANDLE fm, h; + + void *map = MAP_FAILED; + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4293) +#endif + + const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) + ? (DWORD)off + : (DWORD)(off & 0xFFFFFFFFL); + const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) + ? (DWORD)0 + : (DWORD)((off >> 32) & 0xFFFFFFFFL); + const DWORD protect = __map_mmap_prot_page(prot); + const DWORD desiredAccess = __map_mmap_prot_file(prot); + + const off_t maxSize = off + (off_t)len; + + const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) + ? (DWORD)maxSize + : (DWORD)(maxSize & 0xFFFFFFFFL); + const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) + ? (DWORD)0 + : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + + errno = 0; + + if (len == 0 + /* Unsupported flag combinations */ + || (flags & MAP_FIXED) != 0 + /* Usupported protection combinations */ + || prot == PROT_EXEC) { + errno = EINVAL; + return MAP_FAILED; + } + + h = ((flags & MAP_ANONYMOUS) == 0) ? (HANDLE)_get_osfhandle(fildes) + : INVALID_HANDLE_VALUE; + + if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE) { + errno = EBADF; + return MAP_FAILED; + } + + fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL); + + if (fm == NULL) { + errno = __map_mman_error(GetLastError(), EPERM); + return MAP_FAILED; + } + + map = + MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len); + + CloseHandle(fm); + + if (map == NULL) { + errno = __map_mman_error(GetLastError(), EPERM); + return MAP_FAILED; + } + + return map; +} + +int +munmap(void *addr, size_t len) +{ + if (UnmapViewOfFile(addr)) + return 0; + + errno = __map_mman_error(GetLastError(), EPERM); + + return -1; +} + +int +mprotect(void *addr, size_t len, int prot) +{ + DWORD newProtect = __map_mmap_prot_page(prot); + DWORD oldProtect = 0; + + if (VirtualProtect(addr, len, newProtect, &oldProtect)) + return 0; + + errno = __map_mman_error(GetLastError(), EPERM); + + return -1; +} + +int +msync(void *addr, size_t len, int flags) +{ + if (FlushViewOfFile(addr, len)) + return 0; + + errno = __map_mman_error(GetLastError(), EPERM); + + return -1; +} + +int +mlock(const void *addr, size_t len) +{ + if (VirtualLock((LPVOID)addr, len)) + return 0; + + errno = __map_mman_error(GetLastError(), EPERM); + + return -1; +} + +int +munlock(const void *addr, size_t len) +{ + if (VirtualUnlock((LPVOID)addr, len)) + return 0; + + errno = __map_mman_error(GetLastError(), EPERM); + + return -1; +} \ No newline at end of file diff --git a/util/win32-mman.h b/util/win32-mman.h new file mode 100644 index 0000000..4dfa3cb --- /dev/null +++ b/util/win32-mman.h @@ -0,0 +1,68 @@ +// Source: https://github.com/klauspost/mman-win32 (unlicensed) + +/* + Copyright (C) 2012 Klaus Post + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + 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 Lesser 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 + +*/ + +#ifndef _SYS_MMAN_H_ +#define _SYS_MMAN_H_ + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. +# define _WIN32_WINNT \ + 0x0501 // Change this to the appropriate value to target other versions of + // Windows. +#endif + +/* All the headers include this file. */ +#ifndef _MSC_VER +# include <_mingw.h> +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MAP_FILE 0 +#define MAP_SHARED 1 +#define MAP_PRIVATE 2 +#define MAP_TYPE 0xf +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS + +#define MAP_FAILED ((void *)-1) + +/* Flags for msync. */ +#define MS_ASYNC 1 +#define MS_SYNC 2 +#define MS_INVALIDATE 4 + +void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); +int munmap(void *addr, size_t len); +int mprotect(void *addr, size_t len, int prot); +int msync(void *addr, size_t len, int flags); +int mlock(const void *addr, size_t len); +int munlock(const void *addr, size_t len); + +#ifdef __cplusplus +}; +#endif + +#endif /* _SYS_MMAN_H_ */ \ No newline at end of file diff --git a/util/win32-netdb.h b/util/win32-netdb.h new file mode 100644 index 0000000..be7a336 --- /dev/null +++ b/util/win32-netdb.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_NETDB_H +#define _UTIL_NETDB_H + +#define WIN32_LEAN_AND_MEAN +#include +#include + +/* for gods sake microsoft */ +#ifdef interface +# undef interface +#endif /* interface */ + +#endif /* _UTIL_NETDB_H */ \ No newline at end of file diff --git a/util/win32-poll.c b/util/win32-poll.c new file mode 100644 index 0000000..ac27ffe --- /dev/null +++ b/util/win32-poll.c @@ -0,0 +1,329 @@ +/* + * Public domain + * + * poll(2) emulation for Windows + * + * This emulates just-enough poll functionality on Windows to work in the + * context of the openssl(1) program. This is not a replacement for + * POSIX.1-2001 poll(2), though it may come closer than I care to admit. + * + * Dongsheng Song + * Brent Cook + */ + +#include "win32-poll.h" + +#include +#include +#include +#include + +static int +conn_is_closed(int fd) +{ + char buf[1]; + int ret = recv(fd, buf, 1, MSG_PEEK); + if (ret == -1) { + switch (WSAGetLastError()) { + case WSAECONNABORTED: + case WSAECONNRESET: + case WSAENETRESET: + case WSAESHUTDOWN: + return 1; + } + } + return 0; +} + +static int +conn_has_oob_data(int fd) +{ + char buf[1]; + return (recv(fd, buf, 1, MSG_PEEK | MSG_OOB) == 1); +} + +static int +is_socket(int fd) +{ + if (fd < 3) + return 0; + WSANETWORKEVENTS events; + return (WSAEnumNetworkEvents((SOCKET)fd, NULL, &events) == 0); +} + +static int +compute_select_revents( + int fd, + short events, + fd_set *rfds, + fd_set *wfds, + fd_set *efds) +{ + int rc = 0; + + if ((events & (POLLIN | POLLRDNORM | POLLRDBAND)) && FD_ISSET(fd, rfds)) { + if (conn_is_closed(fd)) + rc |= POLLHUP; + else + rc |= POLLIN | POLLRDNORM; + } + + if ((events & (POLLOUT | POLLWRNORM | POLLWRBAND)) && FD_ISSET(fd, wfds)) + rc |= POLLOUT; + + if (FD_ISSET(fd, efds)) { + if (conn_is_closed(fd)) + rc |= POLLHUP; + else if (conn_has_oob_data(fd)) + rc |= POLLRDBAND | POLLPRI; + } + + return rc; +} + +static int +compute_wait_revents(HANDLE h, short events, int object, int wait_rc) +{ + int rc = 0; + INPUT_RECORD record; + DWORD num_read; + + /* + * Assume we can always write to file handles (probably a bad + * assumption but works for now, at least it doesn't block). + */ + if (events & (POLLOUT | POLLWRNORM)) + rc |= POLLOUT; + + /* + * Check if this handle was signaled by WaitForMultipleObjects + */ + if (wait_rc >= WAIT_OBJECT_0 && (object == (wait_rc - WAIT_OBJECT_0)) + && (events & (POLLIN | POLLRDNORM))) { + /* + * Check if this file is stdin, and if so, if it is a console. + */ + if (h == GetStdHandle(STD_INPUT_HANDLE) + && PeekConsoleInput(h, &record, 1, &num_read) == 1) { + /* + * Handle the input console buffer differently, + * since it can signal on other events like + * window and mouse, but read can still block. + */ + if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown) { + rc |= POLLIN; + } else { + /* + * Flush non-character events from the + * console buffer. + */ + ReadConsoleInput(h, &record, 1, &num_read); + } + } else { + rc |= POLLIN; + } + } + + return rc; +} + +static int +wsa_select_errno(int err) +{ + switch (err) { + case WSAEINTR: + case WSAEINPROGRESS: + errno = EINTR; + break; + case WSAEFAULT: + /* + * Windows uses WSAEFAULT for both resource allocation failures + * and arguments not being contained in the user's address + * space. So, we have to choose EFAULT or ENOMEM. + */ + errno = EFAULT; + break; + case WSAEINVAL: + errno = EINVAL; + break; + case WSANOTINITIALISED: + errno = EPERM; + break; + case WSAENETDOWN: + errno = ENOMEM; + break; + } + return -1; +} + +int +poll(struct pollfd *pfds, nfds_t nfds, int timeout_ms) +{ + nfds_t i; + int timespent_ms, looptime_ms; + + /* + * select machinery + */ + fd_set rfds, wfds, efds; + int rc; + int num_sockets; + + /* + * wait machinery + */ + DWORD wait_rc; + HANDLE handles[FD_SETSIZE]; + int num_handles; + + if (pfds == NULL) { + errno = EINVAL; + return -1; + } + + if (nfds <= 0) { + return 0; + } + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + num_sockets = 0; + num_handles = 0; + + for (i = 0; i < nfds; i++) { + if ((int)pfds[i].fd < 0) + continue; + + if (is_socket(pfds[i].fd)) { + if (num_sockets >= FD_SETSIZE) { + errno = EINVAL; + return -1; + } + + FD_SET(pfds[i].fd, &efds); + + if (pfds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND)) { + FD_SET(pfds[i].fd, &rfds); + } + + if (pfds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { + FD_SET(pfds[i].fd, &wfds); + } + num_sockets++; + + } else { + if (num_handles >= FD_SETSIZE) { + errno = EINVAL; + return -1; + } + + handles[num_handles++] = (HANDLE)_get_osfhandle(pfds[i].fd); + } + } + + /* + * Determine if the files, pipes, sockets, consoles, etc. have signaled. + * + * Do this by alternating a loop between WaitForMultipleObjects for + * non-sockets and and select for sockets. + * + * I tried to implement this all in terms of WaitForMultipleObjects + * with a select-based 'poll' of the sockets at the end to get extra + * specific socket status. + * + * However, the cost of setting up an event handle for each socket and + * cleaning them up reliably was pretty high. Since the event handle + * associated with a socket is also global, creating a new one here + * cancels one that may exist externally to this function. + * + * At any rate, even if global socket event handles were not an issue, + * the 'FD_WRITE' status of a socket event handle does not behave in an + * expected fashion, being triggered by an edge on a write buffer rather + * than simply triggering if there is space available. + */ + timespent_ms = 0; + wait_rc = WAIT_FAILED; + + if (timeout_ms < 0) + timeout_ms = INFINITE; + looptime_ms = timeout_ms > 100 ? 100 : timeout_ms; + + do { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = looptime_ms * 1000; + int handle_signaled = 0; + + /* + * Check if any file handles have signaled + */ + if (num_handles) { + wait_rc = WaitForMultipleObjects(num_handles, handles, FALSE, 0); + if (wait_rc == WAIT_FAILED) { + /* + * The documentation for WaitForMultipleObjects + * does not specify what values GetLastError + * may return here. Rather than enumerate + * badness like for wsa_select_errno, assume a + * general errno value. + */ + errno = ENOMEM; + return 0; + } + } + + /* + * If we signaled on a file handle, don't wait on the sockets. + */ + if (wait_rc >= WAIT_OBJECT_0 + && (wait_rc <= WAIT_OBJECT_0 + num_handles - 1)) { + tv.tv_usec = 0; + handle_signaled = 1; + } + + /* + * Check if any sockets have signaled + */ + rc = select(0, &rfds, &wfds, &efds, &tv); + if (!handle_signaled && rc == SOCKET_ERROR) + return wsa_select_errno(WSAGetLastError()); + + if (handle_signaled || (num_sockets && rc > 0)) + break; + + timespent_ms += looptime_ms; + + } while (timespent_ms < timeout_ms); + + rc = 0; + num_handles = 0; + for (i = 0; i < nfds; i++) { + pfds[i].revents = 0; + + if ((int)pfds[i].fd < 0) + continue; + + if (is_socket(pfds[i].fd)) { + pfds[i].revents = compute_select_revents( + pfds[i].fd, + pfds[i].events, + &rfds, + &wfds, + &efds); + + } else { + pfds[i].revents = compute_wait_revents( + handles[num_handles], + pfds[i].events, + num_handles, + wait_rc); + num_handles++; + } + + if (pfds[i].revents) + rc++; + } + + return rc; +} diff --git a/util/win32-poll.h b/util/win32-poll.h new file mode 100644 index 0000000..3d2dfd9 --- /dev/null +++ b/util/win32-poll.h @@ -0,0 +1,63 @@ +/* + * Public domain + * + * poll(2) emulation for Windows + * + * This emulates just-enough poll functionality on Windows to work in the + * context of the openssl(1) program. This is not a replacement for + * POSIX.1-2001 poll(2). + * + * Dongsheng Song + * Brent Cook + */ + +#ifndef _UTIL_POLL_H +#define _UTIL_POLL_H + +#ifndef _WIN32 +# include_next +#else + +# include + +/* Type used for the number of file descriptors. */ +typedef unsigned long int nfds_t; + +# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) +/* Data structure describing a polling request. */ +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; + +/* Event types that can be polled */ +# define POLLIN 0x001 /* There is data to read. */ +# define POLLPRI 0x002 /* There is urgent data to read. */ +# define POLLOUT 0x004 /* Writing now will not block. */ + +# define POLLRDNORM 0x040 /* Normal data may be read. */ +# define POLLRDBAND 0x080 /* Priority data may be read. */ +# define POLLWRNORM 0x100 /* Writing now will not block. */ +# define POLLWRBAND 0x200 /* Priority data may be written. */ + +/* Event types always implicitly polled. */ +# define POLLERR 0x008 /* Error condition. */ +# define POLLHUP 0x010 /* Hung up. */ +# define POLLNVAL 0x020 /* Invalid polling request. */ + +# endif + +# ifdef __cplusplus +extern "C" { +# endif + +int poll(struct pollfd *pfds, nfds_t nfds, int timeout); + +# ifdef __cplusplus +} +# endif + +#endif /* HAVE_POLL */ + +#endif /* _UTIL_POLL_H */ \ No newline at end of file diff --git a/util/win32-pwd.c b/util/win32-pwd.c new file mode 100644 index 0000000..4848b4c --- /dev/null +++ b/util/win32-pwd.c @@ -0,0 +1,44 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#include "win32-pwd.h" + +#include + +// WARN: VERY ADHOC: dummy function lol +uid_t +getuid() +{ + return 0; +} + +// WARN: VERY ADHOC: ignores uid, only populates pw_dir +struct passwd * +getpwuid(uid_t uid) +{ + struct passwd *pw = malloc(sizeof(struct passwd)); + memset(pw, 0, sizeof(struct passwd)); + + char *homeDirStr = malloc(MAX_PATH); + if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, homeDirStr))) { + pw->pw_dir = homeDirStr; + } else { + return NULL; + } + + return pw; +} \ No newline at end of file diff --git a/util/win32-pwd.h b/util/win32-pwd.h new file mode 100644 index 0000000..f812b43 --- /dev/null +++ b/util/win32-pwd.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _PWD_H_ +#define _PWD_H_ + +#include + +typedef int uid_t; +typedef int gid_t; + +struct passwd { + char *pw_name; /* user name */ + char *pw_passwd; /* encrypted password */ + uid_t pw_uid; /* user uid */ + gid_t pw_gid; /* user gid */ + time_t pw_change; /* password change time */ + char *pw_class; /* user access class */ + char *pw_gecos; /* Honeywell login info */ + char *pw_dir; /* home directory */ + char *pw_shell; /* default shell */ + time_t pw_expire; /* account expiration */ +}; + +uid_t getuid(); +struct passwd *getpwuid(uid_t uid); + +#endif /* _PWD_H_ */ \ No newline at end of file diff --git a/util/win32-socket.h b/util/win32-socket.h new file mode 100644 index 0000000..9976dd2 --- /dev/null +++ b/util/win32-socket.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_SOCKET_H +#define _UTIL_SOCKET_H + +#define WIN32_LEAN_AND_MEAN +#include + +#define getsockopt(sockfd, level, optname, optval, optLen) \ + getsockopt(sockfd, level, optname, (char *)optval, optLen) +#define setsockopt(sockfd, level, optname, optval, optLen) \ + setsockopt(sockfd, level, optname, (const char *)optval, optLen) +#define send(sockfd, buf, len, flags) \ + send(sockfd, (const char *)buf, len, flags) + +#ifdef interface +# undef interface +#endif /* interface */ + +#endif /* _UTIL_SOCKET_H */ \ No newline at end of file diff --git a/util/win32-stat.h b/util/win32-stat.h new file mode 100644 index 0000000..cc4d8b7 --- /dev/null +++ b/util/win32-stat.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_STAT_H +#define _UTIL_STAT_H + +#include + +#if (defined(_WIN32) || defined(__WIN32__)) +# define mkdir(A, B) mkdir(A) +#endif + +#endif /* _UTIL_STAT_H */ \ No newline at end of file diff --git a/util/win32-statvfs.c b/util/win32-statvfs.c new file mode 100644 index 0000000..1281d59 --- /dev/null +++ b/util/win32-statvfs.c @@ -0,0 +1,45 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#include "win32-statvfs.h" + +#include +#include + +/* A bit adhoc */ +int +statvfs(const char *restrict path, struct statvfs *restrict buf) +{ + DWORD SectorsPerCluster = 0; + DWORD BytesPerSector = 0; + DWORD NumberOfFreeClusters = 0; + DWORD TotalNumberOfClusters = 0; + int r = GetDiskFreeSpaceA( + path, + &SectorsPerCluster, + &BytesPerSector, + &NumberOfFreeClusters, + &TotalNumberOfClusters); + + buf->f_frsize = BytesPerSector * SectorsPerCluster; + buf->f_bsize = buf->f_frsize; + + buf->f_blocks = TotalNumberOfClusters; + buf->f_bavail = NumberOfFreeClusters; + + return r; +} diff --git a/util/win32-statvfs.h b/util/win32-statvfs.h new file mode 100644 index 0000000..f9085a1 --- /dev/null +++ b/util/win32-statvfs.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_STATVFS_H +#define _UTIL_STATVFS_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef unsigned long fsblkcnt_t; +typedef unsigned long fsfilcnt_t; + +struct statvfs { + unsigned long f_bsize; /* Filesystem block size */ + unsigned long f_frsize; /* Fragment size */ + fsblkcnt_t f_blocks; /* * Size of fs in f_frsize units */ + fsblkcnt_t f_bfree; /* Number of free blocks */ + fsblkcnt_t f_bavail; /* * Number of free blocks for + unprivileged users */ + fsfilcnt_t f_files; /* Number of inodes */ + fsfilcnt_t f_ffree; /* Number of free inodes */ + fsfilcnt_t f_favail; /* Number of free inodes for + unprivileged users */ + unsigned long f_fsid; /* Filesystem ID */ + unsigned long f_flag; /* Mount flags */ + unsigned long f_namemax; /* Maximum filename length */ +}; + +int statvfs(const char *__restrict path, struct statvfs *__restrict buf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _UTIL_STATVFS_H */ diff --git a/util/win32-stdlib.c b/util/win32-stdlib.c new file mode 100644 index 0000000..52e4b32 --- /dev/null +++ b/util/win32-stdlib.c @@ -0,0 +1,39 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#include "win32-stdlib.h" + +#include + +int +setenv(const char *name, const char *value, int overwrite) +{ + int errcode = 0; + if (!overwrite) { + size_t envsize = 0; + errcode = getenv_s(&envsize, NULL, 0, name); + if (errcode || envsize) + return errcode; + } + return _putenv_s(name, value); +} + +int +unsetenv(const char *name) +{ + return _putenv_s(name, ""); +} \ No newline at end of file diff --git a/util/win32-stdlib.h b/util/win32-stdlib.h new file mode 100644 index 0000000..3a0b2bc --- /dev/null +++ b/util/win32-stdlib.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_STDLIB_H +#define _UTIL_STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int setenv(const char *name, const char *value, int overwrite); +int unsetenv(const char *name); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _UTIL_STDLIB_H */ \ No newline at end of file diff --git a/util/win32-termios.c b/util/win32-termios.c new file mode 100644 index 0000000..e7bde06 --- /dev/null +++ b/util/win32-termios.c @@ -0,0 +1,43 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#include "win32-termios.h" + +#include + +ssize_t +read_noecho_noicanon(int fd, void *buf, size_t count) +{ + char *buff = (char *)buf; + for (int i = 0; i < count; i++) { + buff[i] = (char)_getch(); + buff++; + } + return count; +} + +int +tcgetattr(int fd, struct termios *termios_p) +{ + return 0; +} + +int +tcsetattr(int fd, int optional_actions, const struct termios *termios_p) +{ + return 0; +} diff --git a/util/win32-termios.h b/util/win32-termios.h new file mode 100644 index 0000000..f85d15c --- /dev/null +++ b/util/win32-termios.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_TERMIOS_H +#define _UTIL_TERMIOS_H + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_cc[NCCS]; + speed_t c_ispeed; + speed_t c_ospeed; +}; + +#define TCSANOW 0 + +#define ICANON 2 +#define ECHO 8 + +#define read read_noecho_noicanon + +ssize_t read_noecho_noicanon(int fd, void *buf, size_t count); +int tcgetattr(int fd, struct termios *termios_p); +int tcsetattr(int fd, int optional_actions, const struct termios *termios_p); + +#endif /* _UTIL_TERMIOS_H */ \ No newline at end of file diff --git a/util/win32-time.c b/util/win32-time.c new file mode 100644 index 0000000..c018fa8 --- /dev/null +++ b/util/win32-time.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "win32-time.h" diff --git a/util/win32-time.h b/util/win32-time.h new file mode 100644 index 0000000..5b34ac1 --- /dev/null +++ b/util/win32-time.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_TIME_H +#define _UTIL_TIME_H + +#include +#include +#include + +#define gmtime_r(timep, result) gmtime_s(result, timep) +#define localtime_r(timep, result) localtime_s(result, timep) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* timeradd, timersub, timercmp were borrowed from the + Standard GNU C Library */ +#ifndef timercmp +# define timercmp(a, b, CMP) \ + (((a)->tv_sec == (b)->tv_sec) ? ((a)->tv_usec CMP(b)->tv_usec) \ + : ((a)->tv_sec CMP(b)->tv_sec)) +#endif /* timercmp */ + +#ifndef timeradd +# define timeradd(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ + if ((result)->tv_usec >= 1000000) { \ + ++(result)->tv_sec; \ + (result)->tv_usec -= 1000000; \ + } \ + } while (0) +#endif /* timeradd */ + +#ifndef timersub +# define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif /* timersub */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _UTIL_TIME_H */ diff --git a/util/win32-unistd.c b/util/win32-unistd.c new file mode 100644 index 0000000..e0a1943 --- /dev/null +++ b/util/win32-unistd.c @@ -0,0 +1,43 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#include "win32-unistd.h" + +#include + +long +sysconf(int name) +{ + switch (name) { + case _SC_NPROCESSORS_ONLN: { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwNumberOfProcessors; + } break; + default: + return 0; + } + return 0; +} + +int +getpagesize() +{ + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + return sysInfo.dwPageSize; +} diff --git a/util/win32-unistd.h b/util/win32-unistd.h new file mode 100644 index 0000000..164ec06 --- /dev/null +++ b/util/win32-unistd.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2022 Ángel Ruiz Fernández + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, version 3. + + 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 Lesser 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 + +*/ + +#ifndef _UTIL_UNISTD_H +#define _UTIL_UNISTD_H + +#include + +#include "win32-fcntl.h" + +#ifndef _SC_NPROCESSORS_ONLN +# define _SC_NPROCESSORS_ONLN 84 +#endif /* _SC_NPROCESSORS_ONLN */ + +#define pipe(fds) _pipe(fds, 4096, _O_BINARY) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +long sysconf(int name); +int getpagesize(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _UTIL_UNISTD_H */