From 0cca8a846c088220173c79efe0b0ab05c571c73e Mon Sep 17 00:00:00 2001 From: Coburn Date: Sat, 8 Jul 2017 23:10:21 +0000 Subject: [PATCH 01/38] first attempt: registry functions for conversion routines --- include/SoapySDR/Convert.hpp | 30 ++++++++++++++- lib/Convert.cpp | 71 ++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 lib/Convert.cpp diff --git a/include/SoapySDR/Convert.hpp b/include/SoapySDR/Convert.hpp index 44720dd1..eadc30a7 100644 --- a/include/SoapySDR/Convert.hpp +++ b/include/SoapySDR/Convert.hpp @@ -10,13 +10,17 @@ #pragma once #include +#include #include +#include #include +#include //memcpy #include +#include +#include namespace SoapySDR { - /*! * A typedef for a conversion function. * A conversion function converts an input buffer into and output buffer. @@ -24,6 +28,18 @@ namespace SoapySDR */ typedef void (*ConvertFunction)(const void *, void *, const size_t, const double); +// https://stackoverflow.com/questions/10758811/c-syntax-for-functions-returning-function-pointers + +/*! + * A typedef for a map of possible conversion targets given this conversion source. + */ +typedef std::map FormatConverters; + +/*! + * A typedef for a map of possible conversion functions. + */ +typedef std::map SourceFormatConverters; + /*! * Get a list of formats to which we can convert the source format into. * There is a registered conversion function from the specified source @@ -42,6 +58,16 @@ SOAPY_SDR_API std::vector convertTargetFormats(const std::string &s */ SOAPY_SDR_API std::vector convertSourceFormats(const std::string &targetFormat); +/*! + * Register a converter between a source and target format. + * \throws invalid_argument if the conversion already exists + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \param converter function to register + * \return true + */ +SOAPY_SDR_API bool registerConverter(const std::string &sourceFormat, const std::string &targetFormat, ConvertFunction); + /*! * Get a converter between a source and target format. * \throws invalid_argument when the conversion does not exist @@ -49,6 +75,6 @@ SOAPY_SDR_API std::vector convertSourceFormats(const std::string &t * \param targetFormat the target format markup string * \return a conversion function pointer */ -SOAPY_SDR_API ConvertFunction getConverter(const std::string &sourceFormat, const std::string &targetFormat) +SOAPY_SDR_API ConvertFunction getConverter(const std::string &sourceFormat, const std::string &targetFormat); } diff --git a/lib/Convert.cpp b/lib/Convert.cpp new file mode 100644 index 00000000..ca65d73a --- /dev/null +++ b/lib/Convert.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2017-2017 Coburn Wightman +// SPDX-License-Identifier: BSL-1.0 + +#include + +SoapySDR::SourceFormatConverters Converters; + +bool SoapySDR::registerConverter(const std::string &sourceFormat, const std::string &targetFormat, SoapySDR::ConvertFunction converterFunction) +{ + if (Converters.count(sourceFormat) == 0) + { + SoapySDR::FormatConverters converters; + converters[targetFormat] = converterFunction; + Converters[sourceFormat] = converters; + } + else + { + SoapySDR::FormatConverters converters = Converters[sourceFormat]; + if (converters.count(targetFormat) != 0){ + throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + "."); + } + else{ + converters[targetFormat] = converterFunction; + } + } + + return true; +} + +std::vector SoapySDR::convertTargetFormats(const std::string &sourceFormat) +{ + std::vector targets; + + if (Converters.count(sourceFormat) == 0) + return targets; + + SoapySDR::FormatConverters converters = Converters[sourceFormat]; + + for(SoapySDR::FormatConverters::iterator it = converters.begin() ; it != converters.end(); ++it) + { + targets.push_back(it->first); + } + + return targets; +} + +std::vector SoapySDR::convertSourceFormats(const std::string &targetFormat) +{ + std::vector sources; + + for(SoapySDR::SourceFormatConverters::iterator it = Converters.begin() ; it != Converters.end(); ++it) + { + SoapySDR::FormatConverters converters = Converters[it->first]; + if (converters.count(targetFormat) > 0) + sources.push_back(it->first); + } + + return sources; +} + +SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat, const std::string &targetFormat) +{ + if (Converters.count(sourceFormat) == 0) + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + + SoapySDR::FormatConverters converters = Converters[sourceFormat]; + if (converters.count(targetFormat) == 0) + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + + return converters[targetFormat]; +} From 02a4fb315fa15a6abd765e4f94850593859dac63 Mon Sep 17 00:00:00 2001 From: Coburn Date: Sat, 8 Jul 2017 23:13:43 +0000 Subject: [PATCH 02/38] add to library --- lib/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 0ce91059..c12fd854 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -21,6 +21,7 @@ list(APPEND SOAPY_SDR_SOURCES Logger.cpp Errors.cpp Formats.cpp + Convert.cpp ) #dl libs used by dlopen in unix From d444669f0f34ed2441954c0b5214160fa058a0f9 Mon Sep 17 00:00:00 2001 From: Coburn Date: Sat, 8 Jul 2017 23:18:39 +0000 Subject: [PATCH 03/38] tester and sample conversion functions for concept tests. --- tests/CMakeLists.txt | 4 ++ tests/TestFormatConvert.cpp | 119 ++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 tests/TestFormatConvert.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 674f3009..ef34e313 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,3 +19,7 @@ add_test(TestTimeConversion TestTimeConversion) add_executable(TestFormatParser TestFormatParser.cpp) target_link_libraries(TestFormatParser SoapySDR) add_test(TestFormatParser TestFormatParser) + +add_executable(TestFormatConvert TestFormatConvert.cpp) +target_link_libraries(TestFormatConvert SoapySDR) +add_test(TestFormatConvert TestFormatConvert) diff --git a/tests/TestFormatConvert.cpp b/tests/TestFormatConvert.cpp new file mode 100644 index 00000000..f273f079 --- /dev/null +++ b/tests/TestFormatConvert.cpp @@ -0,0 +1,119 @@ +// Copyright (c) 2015-2015 Josh Blum +// SPDX-License-Identifier: BSL-1.0 + +#include +#include +#include + + +SoapySDR::ConvertFunction CF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "CF32 to CF32" << std::endl; + + if (scaler == 1.0) + { + size_t elemSize = 4; + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + std::cout << " straight memcpy" << std::endl; + } + else + { + float *dst = (float*)dstBuff; + float *src = (float*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = src[i] * scaler; + } + std::cout << " sample copy with scaler" << std::endl; + } + return 0; +} + +SoapySDR::ConvertFunction CS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CS16 to CF32" << std::endl; + + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = src[i] * scaler; + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +SoapySDR::ConvertFunction CU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CU16 to CF32" << std::endl; + + float *dst = (float*)dstBuff; + uint16_t *src = (uint16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = (src[i] - 2147483647) * scaler; + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +// ****************************** + +int main(void) +{ + size_t numElems = 128; + size_t elemDepth = 2; + int32_t inElems[numElems * elemDepth]; + int32_t outElems[numElems * elemDepth]; + + // todo + // fill outbuff + // clear inbuff + + std::cout << "registering converters..." << std::endl; + SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CF32toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CS16toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CU16toCF32); + + try{ + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CU16toCF32); + } + catch (const std::exception &ex){ + std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; + } + + std::cout << std::endl << "get supported target formats for " << SOAPY_SDR_CF32 << std::endl; + std::vector formats; + formats = SoapySDR::convertTargetFormats(SOAPY_SDR_CF32); + for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) + { + std::cout << " " << *it << std::endl; + } + + std::cout << "get supported source formats from " << SOAPY_SDR_CF32 << std::endl; + formats = SoapySDR::convertSourceFormats(SOAPY_SDR_CF32); + for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) + { + std::cout << " " << *it << std::endl; + } + + // SoapySDR::ConvertFunction convert; + + SoapySDR::ConvertFunction convert = SoapySDR::getConverter(SOAPY_SDR_CF32, formats[0]); + convert(outElems, inElems, numElems, 0.1); + + // todo + // dump input elems + // dump output elems + + std::cout << "DONE!" << std::endl; + return EXIT_SUCCESS; +} From 44adcd0daaccc7fef79d69efdce4b396b5cb137d Mon Sep 17 00:00:00 2001 From: Coburn Date: Tue, 15 Aug 2017 17:51:50 +0000 Subject: [PATCH 04/38] add exception test --- tests/TestFormatConvert.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/TestFormatConvert.cpp b/tests/TestFormatConvert.cpp index f273f079..a24feae6 100644 --- a/tests/TestFormatConvert.cpp +++ b/tests/TestFormatConvert.cpp @@ -10,7 +10,7 @@ SoapySDR::ConvertFunction CF32toCF32(const void *srcBuff, void *dstBuff, const s { size_t elemDepth = 2; - std::cout << "CF32 to CF32" << std::endl; + std::cout << "converting CF32 to CF32" << std::endl; if (scaler == 1.0) { @@ -58,7 +58,7 @@ SoapySDR::ConvertFunction CU16toCF32(const void *srcBuff, void *dstBuff, const s uint16_t *src = (uint16_t*)srcBuff; for (size_t i = 0; i < numElems*elemDepth; i++) { - dst[i] = (src[i] - 2147483647) * scaler; + dst[i] = (src[i] - 0x7fff) * scaler; } std::cout << " sample copy with scaler" << std::endl; @@ -98,16 +98,21 @@ int main(void) std::cout << " " << *it << std::endl; } - std::cout << "get supported source formats from " << SOAPY_SDR_CF32 << std::endl; + std::cout << "get supported source formats for " << SOAPY_SDR_CF32 << std::endl; formats = SoapySDR::convertSourceFormats(SOAPY_SDR_CF32); for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) { std::cout << " " << *it << std::endl; } - // SoapySDR::ConvertFunction convert; + SoapySDR::ConvertFunction convert; - SoapySDR::ConvertFunction convert = SoapySDR::getConverter(SOAPY_SDR_CF32, formats[0]); + std::cout << std::endl << "try a registered conversion..." << std::endl; + convert = SoapySDR::getConverter(SOAPY_SDR_CF32, formats[0]); + convert(outElems, inElems, numElems, 0.1); + + std::cout << std::endl << "try an unregistered conversion..." << std::endl; + convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16); convert(outElems, inElems, numElems, 0.1); // todo From 9834aa7e322a69f53f943bc808cc4e008ebffd76 Mon Sep 17 00:00:00 2001 From: Coburn Date: Tue, 15 Aug 2017 20:24:48 +0000 Subject: [PATCH 05/38] catch exception to prevent travis failure --- tests/TestFormatConvert.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/TestFormatConvert.cpp b/tests/TestFormatConvert.cpp index a24feae6..203395d0 100644 --- a/tests/TestFormatConvert.cpp +++ b/tests/TestFormatConvert.cpp @@ -112,8 +112,13 @@ int main(void) convert(outElems, inElems, numElems, 0.1); std::cout << std::endl << "try an unregistered conversion..." << std::endl; - convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16); - convert(outElems, inElems, numElems, 0.1); + try{ + convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16); + convert(outElems, inElems, numElems, 0.1); + } + catch (const std::exception &ex){ + std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; + } // todo // dump input elems From 04827b11e98f310723992ff1a918bbb3f56d24d5 Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 18 Aug 2017 22:16:58 +0000 Subject: [PATCH 06/38] added conversion primatives --- CMakeLists.txt | 1 + devel/CMakeLists.txt | 17 +++ devel/TestFormatConvert.cpp | 213 ++++++++++++++++++++++++++++++++++++ devel/convertPrimatives.hpp | 104 ++++++++++++++++++ tests/CMakeLists.txt | 4 - tests/TestFormatConvert.cpp | 129 ---------------------- 6 files changed, 335 insertions(+), 133 deletions(-) create mode 100644 devel/CMakeLists.txt create mode 100644 devel/TestFormatConvert.cpp create mode 100644 devel/convertPrimatives.hpp delete mode 100644 tests/TestFormatConvert.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 246e5e12..930053da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ install(DIRECTORY include/SoapySDR DESTINATION include) ######################################################################## add_subdirectory(lib) add_subdirectory(apps) +add_subdirectory(devel) add_subdirectory(tests) add_subdirectory(docs) diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt new file mode 100644 index 00000000..d7c61052 --- /dev/null +++ b/devel/CMakeLists.txt @@ -0,0 +1,17 @@ +######################################################################## +## Feature registration +######################################################################## +#include(FeatureSummary) +#include(CMakeDependentOption) +#cmake_dependent_option(ENABLE_TESTS "Enable library unit tests" ON "ENABLE_LIBRARY" OFF) +#add_feature_info(Tests ENABLE_TESTS "library unit tests") +#if (NOT ENABLE_TESTS) +# return() +#endif() + +######################################################################## +# Unit tests +######################################################################## +add_executable(TestFormatConvert TestFormatConvert.cpp) +target_link_libraries(TestFormatConvert SoapySDR) +add_test(TestFormatConvert TestFormatConvert) diff --git a/devel/TestFormatConvert.cpp b/devel/TestFormatConvert.cpp new file mode 100644 index 00000000..ae8a179b --- /dev/null +++ b/devel/TestFormatConvert.cpp @@ -0,0 +1,213 @@ +// Copyright (c) 2015-2015 Josh Blum +// SPDX-License-Identifier: BSL-1.0 + +#include "convertPrimatives.hpp" +#include +#include +#include + +bool fillBuffer(uint8_t*, int, std::string); +bool dumpBuffer(uint8_t*, int, std::string); + + +SoapySDR::ConvertFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CF32 to CF32" << std::endl; + + if (scaler == 1.0) + { + size_t elemSize = 4; + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + std::cout << " straight memcpy" << std::endl; + } + else + { + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + float *src = (float*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + // dst[i] = src[i] * sf; + // dst[i+1] = src[i+1] * sf; + CF32toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + } + return 0; +} + +SoapySDR::ConvertFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CS16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +SoapySDR::ConvertFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CU16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + uint16_t *src = (uint16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + //dst[i] = src[i] - 0x7fff) * scaler; + CU16toCF32(src, dst, sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +// ****************************** + +int main(void) +{ + const size_t numElems = 128; + const size_t elemDepth = 2; + int32_t devBuffer[numElems * elemDepth]; + int32_t soapyBuffer[numElems * elemDepth]; + + std::cout << "registering converters..." << std::endl; + SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32); + + try{ + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32); + } + catch (const std::exception &ex){ + std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; + } + + std::cout << std::endl << "get supported target formats for " << SOAPY_SDR_CF32 << std::endl; + std::vector formats; + formats = SoapySDR::convertTargetFormats(SOAPY_SDR_CF32); + for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) + { + std::cout << " " << *it << std::endl; + } + + std::cout << "get supported source formats for " << SOAPY_SDR_CF32 << std::endl; + formats = SoapySDR::convertSourceFormats(SOAPY_SDR_CF32); + for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) + { + std::cout << " " << *it << std::endl; + } + + std::string inElemFormat = SOAPY_SDR_CS16; + std::string outElemFormat = SOAPY_SDR_CF32; + + std::cout << std::endl << "try a registered conversion..." << std::endl; + SoapySDR::ConvertFunction convert = SoapySDR::getConverter(inElemFormat, outElemFormat); + + fillBuffer((uint8_t*)devBuffer, numElems, inElemFormat); + dumpBuffer((uint8_t*)devBuffer, numElems, inElemFormat); + + convert(devBuffer, soapyBuffer, numElems, 2); + dumpBuffer((uint8_t*)soapyBuffer, numElems, outElemFormat); + + std::cout << std::endl << "try an unregistered conversion..." << std::endl; + try{ + convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16); + convert(devBuffer, soapyBuffer, numElems, 0.1); + } + catch (const std::exception &ex){ + std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; + } + + std::cout << "DONE!" << std::endl; + return EXIT_SUCCESS; +} + +bool fillBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ + size_t elemDepth = 2; + + if (elemFormat == SOAPY_SDR_CF32){ + float* buff = (float*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = (float)i; + buff[i+1] = (float)i+1; + } + } + else if (elemFormat == SOAPY_SDR_CS32){ + int32_t* buff = (int32_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = i; + buff[i+1] = i+1; + } + } + else if (elemFormat == SOAPY_SDR_CS16){ + int16_t* buff = (int16_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = i; + buff[i+1] = i+1; + } + } + else + std::cout << "unrecognized elem format" << std::endl; + + return true; +} + +bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ + size_t elemDepth = 2; + + if (elemFormat == SOAPY_SDR_CF32){ + float* buff = (float*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0){ + std::cout << std::endl << i << " > "; + } + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else if (elemFormat == SOAPY_SDR_CS32){ + int32_t* buff = (int32_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0){ + std::cout << std::endl << i << " > "; + } + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else if (elemFormat == SOAPY_SDR_CS16){ + int16_t* buff = (int16_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0){ + std::cout << std::endl << i << " > "; + } + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else{ + std::cout << "unrecognized elem format" << std::endl; + return false; + } + + std::cout << std::endl; + + return true; +} diff --git a/devel/convertPrimatives.hpp b/devel/convertPrimatives.hpp new file mode 100644 index 00000000..cf7ee2ae --- /dev/null +++ b/devel/convertPrimatives.hpp @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSL-1.0 + +#pragma once +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include + +// Simple Primatives + +// integers + +inline int32_t U32toS32(int32_t from){ + return (from - 0x7fffffff); +} + +inline int32_t U24toS32(int32_t from){ + return (from - 0x007fffff); +} + +inline int32_t U16toS32(int16_t from){ + return (from - 0x7fff); +} + +inline int32_t U8toS32(int8_t from){ + return (from - 0x7f); +} + +//floats +inline int32_t F32toS32(float from){ + return int32_t(from); +} + +inline float S16toF32(int16_t from){ + return float(from); +} + +inline float U16toF32(int16_t from){ + return float(U16toS32(from)); +} + +inline float F32toF32(float from){ + return float(from); +} + +// Complex primatives + +/////////////////////////// +// case CONVERT_CF32_CS12: +/////////////////////////// +inline float* CS12toCF32(uint8_t* in, float* out, float scale){ + // float out[2]; + uint16_t part0 = uint16_t(*(in++)); + uint16_t part1 = uint16_t(*(in++)); + uint16_t part2 = uint16_t(*(in++)); + int16_t i = int16_t((part1 << 12) | (part0 << 4)); + int16_t q = int16_t((part2 << 8) | (part1 & 0xf0)); + out[0] = float(i)*scale; + out[1] = float(q)*scale; + return out; + } + +/////////////////////////// +// case CONVERT_CF32_CS16: +/////////////////////////// +inline float* CF32toCF32(float* in, float* out, float scale){ + //const float scale = float(1.0/scaleFactor); + // float out[2]; + + out[0] = F32toF32(in[0])*scale; + out[1] = F32toF32(in[1])*scale; + + return out; +} + +/////////////////////////// +// case CONVERT_CF32_CS16: +/////////////////////////// +inline float* CS16toCF32(int16_t* in, float* out, float scale){ + //const float scale = float(1.0/scaleFactor); + // float out[2]; + + out[0] = S16toF32(in[0])*scale; + out[1] = S16toF32(in[1])*scale; + + return out; +} + +/////////////////////////// +// case CONVERT_CF32_CU16: +/////////////////////////// +inline float* CU16toCF32(uint16_t* in, float* out, float scale){ + //const float scale = float(1.0/scaleFactor); + // float out[2]; + + out[0] = U16toF32(in[0])*scale; + out[1] = U16toF32(in[1])*scale; + + return out; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef34e313..674f3009 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,7 +19,3 @@ add_test(TestTimeConversion TestTimeConversion) add_executable(TestFormatParser TestFormatParser.cpp) target_link_libraries(TestFormatParser SoapySDR) add_test(TestFormatParser TestFormatParser) - -add_executable(TestFormatConvert TestFormatConvert.cpp) -target_link_libraries(TestFormatConvert SoapySDR) -add_test(TestFormatConvert TestFormatConvert) diff --git a/tests/TestFormatConvert.cpp b/tests/TestFormatConvert.cpp deleted file mode 100644 index 203395d0..00000000 --- a/tests/TestFormatConvert.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2015-2015 Josh Blum -// SPDX-License-Identifier: BSL-1.0 - -#include -#include -#include - - -SoapySDR::ConvertFunction CF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CF32 to CF32" << std::endl; - - if (scaler == 1.0) - { - size_t elemSize = 4; - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); - std::cout << " straight memcpy" << std::endl; - } - else - { - float *dst = (float*)dstBuff; - float *src = (float*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i++) - { - dst[i] = src[i] * scaler; - } - std::cout << " sample copy with scaler" << std::endl; - } - return 0; -} - -SoapySDR::ConvertFunction CS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CS16 to CF32" << std::endl; - - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i++) - { - dst[i] = src[i] * scaler; - } - std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -SoapySDR::ConvertFunction CU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CU16 to CF32" << std::endl; - - float *dst = (float*)dstBuff; - uint16_t *src = (uint16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i++) - { - dst[i] = (src[i] - 0x7fff) * scaler; - } - std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -// ****************************** - -int main(void) -{ - size_t numElems = 128; - size_t elemDepth = 2; - int32_t inElems[numElems * elemDepth]; - int32_t outElems[numElems * elemDepth]; - - // todo - // fill outbuff - // clear inbuff - - std::cout << "registering converters..." << std::endl; - SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CF32toCF32); - SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CS16toCF32); - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CU16toCF32); - - try{ - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) CU16toCF32); - } - catch (const std::exception &ex){ - std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; - } - - std::cout << std::endl << "get supported target formats for " << SOAPY_SDR_CF32 << std::endl; - std::vector formats; - formats = SoapySDR::convertTargetFormats(SOAPY_SDR_CF32); - for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) - { - std::cout << " " << *it << std::endl; - } - - std::cout << "get supported source formats for " << SOAPY_SDR_CF32 << std::endl; - formats = SoapySDR::convertSourceFormats(SOAPY_SDR_CF32); - for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) - { - std::cout << " " << *it << std::endl; - } - - SoapySDR::ConvertFunction convert; - - std::cout << std::endl << "try a registered conversion..." << std::endl; - convert = SoapySDR::getConverter(SOAPY_SDR_CF32, formats[0]); - convert(outElems, inElems, numElems, 0.1); - - std::cout << std::endl << "try an unregistered conversion..." << std::endl; - try{ - convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16); - convert(outElems, inElems, numElems, 0.1); - } - catch (const std::exception &ex){ - std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; - } - - // todo - // dump input elems - // dump output elems - - std::cout << "DONE!" << std::endl; - return EXIT_SUCCESS; -} From 8d5098cad1b2f1d62a0fc3fa1ac60698ba45919b Mon Sep 17 00:00:00 2001 From: Coburn Date: Sun, 20 Aug 2017 01:30:32 +0000 Subject: [PATCH 07/38] rough out a device buffer simulator emulates acquireReadBuffer() and readStream(). creates a unique device buffer with each acquireReadBuffer. dumps buffers to help see interleave mistakes etc. --- devel/BufferSim.cpp | 317 +++++++++++++++++++++++++++++++++++++++++++ devel/CMakeLists.txt | 4 + 2 files changed, 321 insertions(+) create mode 100644 devel/BufferSim.cpp diff --git a/devel/BufferSim.cpp b/devel/BufferSim.cpp new file mode 100644 index 00000000..48a5c103 --- /dev/null +++ b/devel/BufferSim.cpp @@ -0,0 +1,317 @@ +// Copyright (c) 2017 Coburn Wightman +// SPDX-License-Identifier: BSL-1.0 + +#include "convertPrimatives.hpp" +#include +//#include +#include +#include + +bool fillBuffer(int8_t*, int, std::string); +bool dumpBuffer(int8_t*, int, std::string); +int readStream(void*, void * const *, const size_t); +int acquireReadBuffer(void *, size_t &, const void **); +void releaseReadBuffer(void *, const size_t); + +SoapySDR::ConvertFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CF32 to CF32" << std::endl; + + if (scaler == 1.0) + { + size_t elemSize = 4; + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + std::cout << " straight memcpy" << std::endl; + } + else + { + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + float *src = (float*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + // dst[i] = src[i] * sf; + // dst[i+1] = src[i+1] * sf; + CF32toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + } + return 0; +} + +SoapySDR::ConvertFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + // std::cout << "converting CS16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCF32(&src[i], &dst[i], sf); + } + // std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +SoapySDR::ConvertFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CU16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + uint16_t *src = (uint16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + //dst[i] = src[i] - 0x7fff) * scaler; + CU16toCF32(src, dst, sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +// ****************************** + +struct Stream{ + size_t numChans; + size_t elemDepth; + // vector chanList; +}; + +struct CS16{ + int16_t i; + int16_t q; +}; + +struct CF32{ + float i; + float q; +}; + + +int main(void) +{ + const size_t numElems = 64; + + struct Stream stream; + stream.numChans = 8; + stream.elemDepth = 2; + + std::cout << "registering converters..." << std::endl; + SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32); + + struct CF32* buffs[8]; + struct CF32 buffer[stream.numChans][numElems]; + + for (size_t i = 0; i < stream.numChans; i++){ + buffs[i] = buffer[i]; + } + + size_t elemCount = readStream((void *)&stream, (void**)buffs, numElems); + + //dumpBuffer((char*)soapyBuffer, numElems, outElemFormat); + + std::cout << "DONE!" << std::endl; + return elemCount; //EXIT_SUCCESS; +} + +/*! + * Read elements from a stream for reception. + * This is a multi-channel call, and buffs should be an array of void *, + * where each pointer will be filled with data from a different channel. + * + * **Client code compatibility:** + * The readStream() call should be well defined at all times, + * including prior to activation and after deactivation. + * When inactive, readStream() should implement the timeout + * specified by the caller and return SOAPY_SDR_TIMEOUT. + * + * \param stream the opaque pointer to a stream handle + * \param buffs an array of void* buffers num chans in size + * \param numElems the number of elements in each buffer + * \param flags optional flag indicators about the result + * \param timeNs the buffer's timestamp in nanoseconds + * \param timeoutUs the timeout in microseconds + * \return the number of elements read per buffer or error code + */ +int readStream(void* stream, void * const *buffs, const size_t numElems) +{ + struct Stream* myStream = (struct Stream*)stream; + + std::string inElemFormat = SOAPY_SDR_CS16; + std::string outElemFormat = SOAPY_SDR_CF32; + SoapySDR::ConvertFunction convert = SoapySDR::getConverter(inElemFormat, outElemFormat); + + size_t handle; + const void *payload[8]; + + size_t elemOffset = 0; + while (elemOffset < numElems) + { + size_t elemCount = acquireReadBuffer(stream, handle, payload); + for (size_t chan = 0; chan < myStream->numChans; chan++) + { + struct CF32* toBuff = (struct CF32*) buffs[chan]; + struct CS16* fromBuff = (struct CS16*) payload[chan]; + convert(&fromBuff[0], &toBuff[elemOffset], elemCount, 1); + } + elemOffset += elemCount; + releaseReadBuffer(stream, handle); + } + + for (size_t chan = 0; chan < myStream->numChans; chan++) + { + std::cout << "readStream(): chan " << chan << " " << outElemFormat << std::endl; + dumpBuffer((int8_t*)buffs[chan], numElems, outElemFormat); + } + + return numElems; +} + +/*! + * Acquire direct buffers from a receive stream. + * This call is part of the direct buffer access API. + * + * The buffs array will be filled with a stream pointer for each channel. + * Each pointer can be read up to the number of return value elements. + * + * The handle will be set by the implementation so that the caller + * may later release access to the buffers with releaseReadBuffer(). + * Handle represents an index into the internal scatter/gather table + * such that handle is between 0 and num direct buffers - 1. + * + * \param stream the opaque pointer to a stream handle + * \param handle an index value used in the release() call + * \param buffs an array of void* buffers num chans in size + * \param flags optional flag indicators about the result + * \param timeNs the buffer's timestamp in nanoseconds + * \param timeoutUs the timeout in microseconds + * \return the number of elements read per buffer or error code + */ + +int acquireReadBuffer(void *stream, size_t &handle, const void **buffs) +{ + const size_t numElems = 16; + const size_t numChans = 8; + const size_t elemDepth = 2; + static int cycleCount = 0; + + struct Stream* myStream = (struct Stream*)stream; + + static struct CS16 devBuffer[numChans][numElems]; + + // fabricate a dummy buffer. + for (size_t chan = 0; chan < numChans; chan++){ + for (size_t elem = 0; elem < numElems; elem++){ + devBuffer[chan][elem].i = cycleCount * 1000 + chan*100 + elem; + devBuffer[chan][elem].q = -(cycleCount * 1000 + chan*100 + elem); + } + buffs[chan] = devBuffer[chan]; + } + + ++cycleCount; + handle = 0; + + std::cout << "acquireReadBuffer(): " << SOAPY_SDR_CS16 << std::endl; + dumpBuffer((int8_t*)devBuffer, numChans*numElems, SOAPY_SDR_CS16); + + return numElems; +} + + +/*! + * Release an acquired buffer back to the receive stream. + * This call is part of the direct buffer access API. + * + * \param stream the opaque pointer to a stream handle + * \param handle the opaque handle from the acquire() call + */ + +void releaseReadBuffer(void *stream, const size_t handle) +{ + struct Stream* myStream = (struct Stream*)stream; +} + +bool fillBuffer(int8_t* buffer, int numElems, std::string elemFormat){ + size_t elemDepth = 2; + + if (elemFormat == SOAPY_SDR_CF32){ + float* buff = (float*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = (float)i; + buff[i+1] = (float)i+1; + } + } + else if (elemFormat == SOAPY_SDR_CS32){ + int32_t* buff = (int32_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = i; + buff[i+1] = i+1; + } + } + else if (elemFormat == SOAPY_SDR_CS16){ + int16_t* buff = (int16_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = i; + buff[i+1] = i+1; + } + } + else + std::cout << "unrecognized elem format" << std::endl; + + return true; +} + +bool dumpBuffer(int8_t* buffer, int numElems, std::string elemFormat){ + size_t elemDepth = 2; + + if (elemFormat == SOAPY_SDR_CF32){ + float* buff = (float*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0) + std::cout << std::endl << i << " > "; + + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else if (elemFormat == SOAPY_SDR_CS32){ + int32_t* buff = (int32_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0) + std::cout << std::endl << i << " > "; + + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else if (elemFormat == SOAPY_SDR_CS16){ + int16_t* buff = (int16_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0) + std::cout << std::endl << i << " > "; + + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else + std::cout << "unrecognized elem format" << std::endl; + + std::cout << std::endl; + + return true; +} diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt index d7c61052..59f9c222 100644 --- a/devel/CMakeLists.txt +++ b/devel/CMakeLists.txt @@ -15,3 +15,7 @@ add_executable(TestFormatConvert TestFormatConvert.cpp) target_link_libraries(TestFormatConvert SoapySDR) add_test(TestFormatConvert TestFormatConvert) + +add_executable(BufferSim BufferSim.cpp) +target_link_libraries(BufferSim SoapySDR) +add_test(BufferSim BufferSim) From 447a3a943c5c8d7a135568d5b5bbf73c77e5e345 Mon Sep 17 00:00:00 2001 From: Coburn Date: Sun, 20 Aug 2017 02:42:11 +0000 Subject: [PATCH 08/38] remove buffersim from travis list --- devel/CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt index 59f9c222..81762695 100644 --- a/devel/CMakeLists.txt +++ b/devel/CMakeLists.txt @@ -12,10 +12,7 @@ ######################################################################## # Unit tests ######################################################################## -add_executable(TestFormatConvert TestFormatConvert.cpp) -target_link_libraries(TestFormatConvert SoapySDR) -add_test(TestFormatConvert TestFormatConvert) add_executable(BufferSim BufferSim.cpp) target_link_libraries(BufferSim SoapySDR) -add_test(BufferSim BufferSim) +#add_test(BufferSim BufferSim) From 4767f4cae7c6342615ae7b41f50b311dc62dab0e Mon Sep 17 00:00:00 2001 From: Coburn Date: Wed, 30 Aug 2017 16:09:16 +0000 Subject: [PATCH 09/38] Fix pass by ref/value error access map using multi dim array notation to better show intent. --- lib/Convert.cpp | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/lib/Convert.cpp b/lib/Convert.cpp index ca65d73a..95f7e720 100644 --- a/lib/Convert.cpp +++ b/lib/Convert.cpp @@ -9,19 +9,18 @@ bool SoapySDR::registerConverter(const std::string &sourceFormat, const std::str { if (Converters.count(sourceFormat) == 0) { - SoapySDR::FormatConverters converters; - converters[targetFormat] = converterFunction; - Converters[sourceFormat] = converters; + Converters[sourceFormat][targetFormat] = converterFunction; } else { - SoapySDR::FormatConverters converters = Converters[sourceFormat]; - if (converters.count(targetFormat) != 0){ - throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + "."); - } - else{ - converters[targetFormat] = converterFunction; - } + if (Converters[sourceFormat].count(targetFormat) != 0) + { + throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + "."); + } + else + { + Converters[sourceFormat][targetFormat] = converterFunction; + } } return true; @@ -34,11 +33,10 @@ std::vector SoapySDR::convertTargetFormats(const std::string &sourc if (Converters.count(sourceFormat) == 0) return targets; - SoapySDR::FormatConverters converters = Converters[sourceFormat]; - - for(SoapySDR::FormatConverters::iterator it = converters.begin() ; it != converters.end(); ++it) + for(SoapySDR::FormatConverters::iterator it = Converters[sourceFormat].begin() ; it != Converters[sourceFormat].end(); ++it) { - targets.push_back(it->first); + std::string targetFormat = it->first; + targets.push_back(targetFormat); } return targets; @@ -50,9 +48,9 @@ std::vector SoapySDR::convertSourceFormats(const std::string &targe for(SoapySDR::SourceFormatConverters::iterator it = Converters.begin() ; it != Converters.end(); ++it) { - SoapySDR::FormatConverters converters = Converters[it->first]; - if (converters.count(targetFormat) > 0) - sources.push_back(it->first); + std::string sourceFormat = it->first; + if (Converters[sourceFormat].count(targetFormat) > 0) + sources.push_back(sourceFormat); } return sources; @@ -63,9 +61,8 @@ SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat if (Converters.count(sourceFormat) == 0) throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); - SoapySDR::FormatConverters converters = Converters[sourceFormat]; - if (converters.count(targetFormat) == 0) + if (Converters[sourceFormat].count(targetFormat) == 0) throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - return converters[targetFormat]; + return Converters[sourceFormat][targetFormat]; } From 7f75c0a48b31f48c5430dfe6d12f86430af9e1d9 Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 1 Sep 2017 17:25:07 +0000 Subject: [PATCH 10/38] add debug symbols --- devel/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt index 81762695..58f129a5 100644 --- a/devel/CMakeLists.txt +++ b/devel/CMakeLists.txt @@ -14,5 +14,9 @@ ######################################################################## add_executable(BufferSim BufferSim.cpp) +target_compile_options(BufferSim PRIVATE -g) target_link_libraries(BufferSim SoapySDR) + +add_executable(TestFormatConvert TestFormatConvert.cpp) +target_link_libraries(TestFormatConvert SoapySDR) #add_test(BufferSim BufferSim) From 93f5c7a91ce1b5aae59e3ab95ed9cdb2aa6deebe Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 1 Sep 2017 17:30:22 +0000 Subject: [PATCH 11/38] add a couple dummy primatives --- devel/convertPrimatives.hpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/devel/convertPrimatives.hpp b/devel/convertPrimatives.hpp index cf7ee2ae..f7225552 100644 --- a/devel/convertPrimatives.hpp +++ b/devel/convertPrimatives.hpp @@ -30,6 +30,15 @@ inline int32_t U8toS32(int8_t from){ return (from - 0x7f); } +inline int32_t S16toS32(int16_t from){ + return int32_t(from); +} + +inline int16_t S16toS16(int16_t from){ + return int16_t(from); +} + + //floats inline int32_t F32toS32(float from){ return int32_t(from); @@ -102,3 +111,29 @@ inline float* CU16toCF32(uint16_t* in, float* out, float scale){ return out; } + +/////////////////////////// +// case CONVERT_CS32_CS16: +/////////////////////////// +inline int32_t* CS16toCS32(int16_t* in, int32_t* out, float scale){ + //const float scale = float(1.0/scaleFactor); + // float out[2]; + + out[0] = S16toS32(in[0])*scale; + out[1] = S16toS32(in[1])*scale; + + return out; +} + +/////////////////////////// +// case CONVERT_CS16_CS16: +/////////////////////////// +inline int16_t* CS16toCS16(int16_t* in, int16_t* out, float scale){ + //const float scale = float(1.0/scaleFactor); + // float out[2]; + + out[0] = S16toS16(in[0])*scale; + out[1] = S16toS16(in[1])*scale; + + return out; +} From 35a9a657bb99280c4e8bd16aff73cc23f5673add Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 1 Sep 2017 17:43:32 +0000 Subject: [PATCH 12/38] added getStreamFormats and getNativeStreamFormat Shows a simple model of stream formats and conversions. --- devel/BufferSim.cpp | 251 ++++++++++++++++++++++++++++++-------------- 1 file changed, 175 insertions(+), 76 deletions(-) diff --git a/devel/BufferSim.cpp b/devel/BufferSim.cpp index 48a5c103..456fc8b5 100644 --- a/devel/BufferSim.cpp +++ b/devel/BufferSim.cpp @@ -1,17 +1,22 @@ // Copyright (c) 2017 Coburn Wightman // SPDX-License-Identifier: BSL-1.0 +//#include "buffer.hpp" #include "convertPrimatives.hpp" #include //#include #include #include +#include bool fillBuffer(int8_t*, int, std::string); bool dumpBuffer(int8_t*, int, std::string); int readStream(void*, void * const *, const size_t); int acquireReadBuffer(void *, size_t &, const void **); void releaseReadBuffer(void *, const size_t); +std::string getNativeStreamFormat(const int, const size_t, double &); +std::vector getStreamFormats(const int, const size_t); +struct Stream *setupStream(const int, const std::string &, const std::vector &); SoapySDR::ConvertFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { @@ -59,6 +64,42 @@ SoapySDR::ConvertFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, cons return 0; } +SoapySDR::ConvertFunction cvtCS16toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + // std::cout << "converting CS16 to CS16" << std::endl; + + float sf = float(1.0/scaler); + int16_t *dst = (int16_t*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCS16(&src[i], &dst[i], sf); + } + // std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +SoapySDR::ConvertFunction cvtCS16toCS32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + // std::cout << "converting CS16 to CS32" << std::endl; + + float sf = float(1.0/scaler); + int32_t *dst = (int32_t*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCS32(&src[i], &dst[i], sf); + } + // std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + SoapySDR::ConvertFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -78,12 +119,26 @@ SoapySDR::ConvertFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, cons return 0; } -// ****************************** struct Stream{ size_t numChans; - size_t elemDepth; // vector chanList; + + SoapySDR::ConvertFunction converter; + std::string streamElemFormat; + size_t streamElemWidth; + size_t streamElemDepth; + size_t streamElemSize; + + std::string nativeElemFormat; + size_t nativeElemWidth; + size_t nativeElemDepth; + size_t nativeElemSize; + + size_t fragmentRemaining; + size_t fragmentOffset; + size_t fragmentHandle; + const void *fragmentBuffs[8]; }; struct CS16{ @@ -97,32 +152,106 @@ struct CF32{ }; +struct Stream _stream; + int main(void) { - const size_t numElems = 64; - struct Stream stream; - stream.numChans = 8; - stream.elemDepth = 2; - std::cout << "registering converters..." << std::endl; - SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CS16, (SoapySDR::ConvertFunction) cvtCS16toCS16); + SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CS32, (SoapySDR::ConvertFunction) cvtCS16toCS32); SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32); - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32); + double fs; + std::string nativeFormat = getNativeStreamFormat(0,1,fs); + std::cout << "native format: " << nativeFormat << std::endl; + + std::cout << std::endl << "supported stream formats for " << nativeFormat << std::endl; + std::vector formats = SoapySDR::convertTargetFormats(nativeFormat); + for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) + { + std::cout << " " << *it << std::endl; + } + + const size_t numElems = 100; //64 + std::vectorchannels; + + struct Stream* myStream = setupStream(0, SOAPY_SDR_CF32, channels ); + struct CF32* buffs[8]; - struct CF32 buffer[stream.numChans][numElems]; + struct CF32 buffer[myStream->numChans][numElems]; - for (size_t i = 0; i < stream.numChans; i++){ - buffs[i] = buffer[i]; + for (size_t chan = 0; chan < myStream->numChans; chan++){ + buffs[chan] = buffer[chan]; } - size_t elemCount = readStream((void *)&stream, (void**)buffs, numElems); - - //dumpBuffer((char*)soapyBuffer, numElems, outElemFormat); + size_t elemCount = readStream((void *)myStream, (void**)buffs, numElems); + + for (size_t chan = 0; chan < myStream->numChans; chan++) + { + std::cout << "readStream() result: chan" << chan << " " << myStream->streamElemFormat << std::endl; + dumpBuffer((int8_t*)buffs[chan], elemCount, myStream->streamElemFormat); + } std::cout << "DONE!" << std::endl; - return elemCount; //EXIT_SUCCESS; + return EXIT_SUCCESS; +} + +/*! + * Query a list of the available stream formats. + * \param direction the channel direction RX or TX + * \param channel an available channel on the device + * \return a list of allowed format strings. See setupStream() for the format syntax. + */ +std::vector getStreamFormats(const int direction, const size_t channel) //const +{ + double fs; + + const std::string sourceFormat = getNativeStreamFormat(direction, channel, fs); + std::vector formats = SoapySDR::convertTargetFormats(sourceFormat); + + return formats; +} + +/*! + * Get the hardware's native stream format for this channel. + * This is the format used by the underlying transport layer, + * and the direct buffer access API calls (when available). + * \param direction the channel direction RX or TX + * \param channel an available channel on the device + * \param [out] fullScale the maximum possible value + * \return the native stream buffer format string + */ +std::string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) //const +{ + fullScale = 3.3/2; + return SOAPY_SDR_CS16; +} + +struct Stream *setupStream(const int direction, const std::string &format, const std::vector &channels) +{ + struct Stream* stream = &_stream; + double fs; + + stream->numChans = 8; + + stream->nativeElemFormat = getNativeStreamFormat(direction, 0, fs); + stream->nativeElemWidth = 2; //bytes + stream->nativeElemDepth = 2; //samples + stream->nativeElemSize = stream->nativeElemWidth * stream->nativeElemDepth; + + stream->streamElemFormat = format; + stream->streamElemWidth = 4; //bytes + stream->streamElemDepth = 2; //samples + stream->streamElemSize = stream->streamElemWidth * stream->streamElemDepth; + + stream->converter = SoapySDR::getConverter(stream->nativeElemFormat, stream->streamElemFormat); + + stream->fragmentRemaining = 0; + stream->fragmentOffset = 0; + // size_t fragmentHandle; + + return stream; } /*! @@ -144,37 +273,41 @@ int main(void) * \param timeoutUs the timeout in microseconds * \return the number of elements read per buffer or error code */ + int readStream(void* stream, void * const *buffs, const size_t numElems) { struct Stream* myStream = (struct Stream*)stream; - std::string inElemFormat = SOAPY_SDR_CS16; - std::string outElemFormat = SOAPY_SDR_CF32; - SoapySDR::ConvertFunction convert = SoapySDR::getConverter(inElemFormat, outElemFormat); - - size_t handle; - const void *payload[8]; - - size_t elemOffset = 0; - while (elemOffset < numElems) + size_t streamOffset = 0; + size_t bufferRemaining = numElems; + while (streamOffset < numElems) { - size_t elemCount = acquireReadBuffer(stream, handle, payload); + if (myStream->fragmentRemaining == 0) + { + myStream->fragmentRemaining = acquireReadBuffer(stream, myStream->fragmentHandle, myStream->fragmentBuffs); + } + size_t elemCount = (bufferRemaining < myStream->fragmentRemaining) ? bufferRemaining : myStream->fragmentRemaining; for (size_t chan = 0; chan < myStream->numChans; chan++) { - struct CF32* toBuff = (struct CF32*) buffs[chan]; - struct CS16* fromBuff = (struct CS16*) payload[chan]; - convert(&fromBuff[0], &toBuff[elemOffset], elemCount, 1); + int8_t* streamBuffer = (int8_t*) buffs[chan]; + int8_t* fragmentBuffer = (int8_t*) myStream->fragmentBuffs[chan]; + myStream->converter(&fragmentBuffer[myStream->fragmentOffset * myStream->nativeElemSize], + &streamBuffer[streamOffset * myStream->streamElemSize], elemCount, 1); + } + streamOffset += elemCount; + bufferRemaining -= elemCount; + + myStream->fragmentOffset += elemCount; + myStream->fragmentRemaining -= elemCount; + + std::cout << myStream->fragmentRemaining << std::endl; + if (myStream->fragmentRemaining == 0) + { + myStream->fragmentOffset = 0; + releaseReadBuffer(stream, myStream->fragmentHandle); } - elemOffset += elemCount; - releaseReadBuffer(stream, handle); } - for (size_t chan = 0; chan < myStream->numChans; chan++) - { - std::cout << "readStream(): chan " << chan << " " << outElemFormat << std::endl; - dumpBuffer((int8_t*)buffs[chan], numElems, outElemFormat); - } - return numElems; } @@ -201,16 +334,15 @@ int readStream(void* stream, void * const *buffs, const size_t numElems) int acquireReadBuffer(void *stream, size_t &handle, const void **buffs) { - const size_t numElems = 16; + const size_t numElems = 12; //16 const size_t numChans = 8; - const size_t elemDepth = 2; static int cycleCount = 0; struct Stream* myStream = (struct Stream*)stream; + std::cout << "acquireReadBuffer(): " << myStream->nativeElemFormat << std::endl; + // fabricate a dummy device buffer. static struct CS16 devBuffer[numChans][numElems]; - - // fabricate a dummy buffer. for (size_t chan = 0; chan < numChans; chan++){ for (size_t elem = 0; elem < numElems; elem++){ devBuffer[chan][elem].i = cycleCount * 1000 + chan*100 + elem; @@ -222,8 +354,7 @@ int acquireReadBuffer(void *stream, size_t &handle, const void **buffs) ++cycleCount; handle = 0; - std::cout << "acquireReadBuffer(): " << SOAPY_SDR_CS16 << std::endl; - dumpBuffer((int8_t*)devBuffer, numChans*numElems, SOAPY_SDR_CS16); + dumpBuffer((int8_t*)devBuffer, numChans*numElems, myStream->nativeElemFormat); return numElems; } @@ -240,39 +371,7 @@ int acquireReadBuffer(void *stream, size_t &handle, const void **buffs) void releaseReadBuffer(void *stream, const size_t handle) { struct Stream* myStream = (struct Stream*)stream; -} - -bool fillBuffer(int8_t* buffer, int numElems, std::string elemFormat){ - size_t elemDepth = 2; - - if (elemFormat == SOAPY_SDR_CF32){ - float* buff = (float*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = (float)i; - buff[i+1] = (float)i+1; - } - } - else if (elemFormat == SOAPY_SDR_CS32){ - int32_t* buff = (int32_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = i; - buff[i+1] = i+1; - } - } - else if (elemFormat == SOAPY_SDR_CS16){ - int16_t* buff = (int16_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = i; - buff[i+1] = i+1; - } - } - else - std::cout << "unrecognized elem format" << std::endl; - - return true; + std::cout << "releaseReadBuffer(): " << myStream->nativeElemFormat << std::endl; } bool dumpBuffer(int8_t* buffer, int numElems, std::string elemFormat){ From e1cd42ab551c273634b23e7ca4e6549f8f9e3f37 Mon Sep 17 00:00:00 2001 From: Coburn Date: Thu, 7 Sep 2017 17:36:19 +0000 Subject: [PATCH 13/38] enable c++11 --- cmake/SoapySDRConfig.cmake | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmake/SoapySDRConfig.cmake b/cmake/SoapySDRConfig.cmake index dd70d7ae..a44042f9 100644 --- a/cmake/SoapySDRConfig.cmake +++ b/cmake/SoapySDRConfig.cmake @@ -63,7 +63,17 @@ endif() ######################################################################## # Helpful compiler flags ######################################################################## + +#C++11 is a required language feature for this project +set(CMAKE_CXX_STANDARD 11) + if(CMAKE_COMPILER_IS_GNUCXX) + + #enable C++11 on older versions of cmake + if (CMAKE_VERSION VERSION_LESS "3.1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + endif() + #force a compile-time error when symbols are missing set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") From 8ae1cc01c865a21082829cd2f605798f4a15bece Mon Sep 17 00:00:00 2001 From: Coburn Date: Thu, 7 Sep 2017 17:38:03 +0000 Subject: [PATCH 14/38] simplify for loops using c+=11 constructs --- lib/Convert.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Convert.cpp b/lib/Convert.cpp index 95f7e720..cc0ed82f 100644 --- a/lib/Convert.cpp +++ b/lib/Convert.cpp @@ -33,9 +33,9 @@ std::vector SoapySDR::convertTargetFormats(const std::string &sourc if (Converters.count(sourceFormat) == 0) return targets; - for(SoapySDR::FormatConverters::iterator it = Converters[sourceFormat].begin() ; it != Converters[sourceFormat].end(); ++it) + for(const auto &it:Converters[sourceFormat]) { - std::string targetFormat = it->first; + std::string targetFormat = it.first; targets.push_back(targetFormat); } @@ -46,9 +46,9 @@ std::vector SoapySDR::convertSourceFormats(const std::string &targe { std::vector sources; - for(SoapySDR::SourceFormatConverters::iterator it = Converters.begin() ; it != Converters.end(); ++it) + for(const auto &it:Converters) { - std::string sourceFormat = it->first; + std::string sourceFormat = it.first; if (Converters[sourceFormat].count(targetFormat) > 0) sources.push_back(sourceFormat); } From f90dfc4db96b070e99f252e124ba19222264f233 Mon Sep 17 00:00:00 2001 From: Coburn Date: Thu, 7 Sep 2017 17:49:38 +0000 Subject: [PATCH 15/38] assign attribution --- devel/convertPrimatives.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/devel/convertPrimatives.hpp b/devel/convertPrimatives.hpp index f7225552..d5b1df36 100644 --- a/devel/convertPrimatives.hpp +++ b/devel/convertPrimatives.hpp @@ -1,3 +1,4 @@ +// Copyright (c) 2017-2017 Coburn Wightman" // SPDX-License-Identifier: BSL-1.0 #pragma once From 19246eac86d9ffbd04bb2b6a11a2d4d27dc46057 Mon Sep 17 00:00:00 2001 From: Coburn Date: Thu, 7 Sep 2017 18:33:34 +0000 Subject: [PATCH 16/38] clean up includes --- devel/BufferSim.cpp | 1 + devel/TestFormatConvert.cpp | 1 + include/SoapySDR/Convert.hpp | 4 ---- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/devel/BufferSim.cpp b/devel/BufferSim.cpp index 456fc8b5..c9d00f27 100644 --- a/devel/BufferSim.cpp +++ b/devel/BufferSim.cpp @@ -8,6 +8,7 @@ #include #include #include +#include //memcpy bool fillBuffer(int8_t*, int, std::string); bool dumpBuffer(int8_t*, int, std::string); diff --git a/devel/TestFormatConvert.cpp b/devel/TestFormatConvert.cpp index ae8a179b..758bed9d 100644 --- a/devel/TestFormatConvert.cpp +++ b/devel/TestFormatConvert.cpp @@ -5,6 +5,7 @@ #include #include #include +#include //memcpy bool fillBuffer(uint8_t*, int, std::string); bool dumpBuffer(uint8_t*, int, std::string); diff --git a/include/SoapySDR/Convert.hpp b/include/SoapySDR/Convert.hpp index eadc30a7..9853306e 100644 --- a/include/SoapySDR/Convert.hpp +++ b/include/SoapySDR/Convert.hpp @@ -9,14 +9,10 @@ /// #pragma once -#include #include #include #include #include -#include //memcpy -#include -#include #include namespace SoapySDR From 74edab2792e25c33c59728b31bda2720b2c711a1 Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 8 Sep 2017 21:06:03 +0000 Subject: [PATCH 17/38] add priority selection to function api --- include/SoapySDR/Convert.hpp | 37 +++++++++++++++++++---- lib/Convert.cpp | 58 +++++++++++++++++++++++++++--------- 2 files changed, 75 insertions(+), 20 deletions(-) diff --git a/include/SoapySDR/Convert.hpp b/include/SoapySDR/Convert.hpp index 9853306e..82c7671a 100644 --- a/include/SoapySDR/Convert.hpp +++ b/include/SoapySDR/Convert.hpp @@ -24,17 +24,30 @@ namespace SoapySDR */ typedef void (*ConvertFunction)(const void *, void *, const size_t, const double); -// https://stackoverflow.com/questions/10758811/c-syntax-for-functions-returning-function-pointers +/*! + * FormatConverterPriority: allow selection of a converter function with a given source and target format + */ +enum FormatConverterPriority{ + GENERIC = 0, // usual C for loops and shifts and multiplies + VECTORIZED = 3, // using SIMD vectorized operations probably + CUSTOM = 5 // custom user re-implementation, max prio +}; + + +/*! + * TargetFormatConverterPriority: a map of possible conversion functions for a given priority. + */ +typedef std::map TargetFormatConverterPriority; /*! - * A typedef for a map of possible conversion targets given this conversion source. + * TargetFormatConverters: a map of possible conversion functions for a given Target Format. */ -typedef std::map FormatConverters; +typedef std::map TargetFormatConverters; /*! - * A typedef for a map of possible conversion functions. + * FormatConverters: a map of possible conversion functions for a given Source Format. */ -typedef std::map SourceFormatConverters; +typedef std::map FormatConverters; /*! * Get a list of formats to which we can convert the source format into. @@ -62,15 +75,27 @@ SOAPY_SDR_API std::vector convertSourceFormats(const std::string &t * \param converter function to register * \return true */ -SOAPY_SDR_API bool registerConverter(const std::string &sourceFormat, const std::string &targetFormat, ConvertFunction); +SOAPY_SDR_API bool registerConverter(const std::string &sourceFormat, const std::string &targetFormat, ConvertFunction, FormatConverterPriority &); +/*! + * Get a list of available converter priorities for a given source and target format. + * \throws invalid_argument when the conversion does not exist + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \return a vector of priorities + */ +SOAPY_SDR_API std::vector getConverterPriorities(const std::string &sourceFormat, const std::string &targetFormat); + /*! * Get a converter between a source and target format. * \throws invalid_argument when the conversion does not exist * \param sourceFormat the source format markup string * \param targetFormat the target format markup string + * \param priority converter priority or highest if not specified * \return a conversion function pointer */ SOAPY_SDR_API ConvertFunction getConverter(const std::string &sourceFormat, const std::string &targetFormat); +SOAPY_SDR_API ConvertFunction getConverter(const std::string &sourceFormat, const std::string &targetFormat, FormatConverterPriority &priority); + } diff --git a/lib/Convert.cpp b/lib/Convert.cpp index cc0ed82f..46a15e17 100644 --- a/lib/Convert.cpp +++ b/lib/Convert.cpp @@ -3,24 +3,17 @@ #include -SoapySDR::SourceFormatConverters Converters; +SoapySDR::FormatConverters Converters; -bool SoapySDR::registerConverter(const std::string &sourceFormat, const std::string &targetFormat, SoapySDR::ConvertFunction converterFunction) +bool SoapySDR::registerConverter(const std::string &sourceFormat, const std::string &targetFormat, SoapySDR::ConvertFunction converterFunction, FormatConverterPriority &priority) { - if (Converters.count(sourceFormat) == 0) + if (Converters[sourceFormat][targetFormat].count(priority) == 0) { - Converters[sourceFormat][targetFormat] = converterFunction; + Converters[sourceFormat][targetFormat][priority] = converterFunction; } else - { - if (Converters[sourceFormat].count(targetFormat) != 0) - { - throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + "."); - } - else - { - Converters[sourceFormat][targetFormat] = converterFunction; - } + { + throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority) + "."); } return true; @@ -56,6 +49,29 @@ std::vector SoapySDR::convertSourceFormats(const std::string &targe return sources; } +std::vector SoapySDR::getConverterPriorities(const std::string &sourceFormat, const std::string &targetFormat) +{ + std::vector priorities; + + if (Converters.count(sourceFormat) == 0) + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + + if (Converters[sourceFormat].count(targetFormat) == 0) + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + + // if (Converters[sourceFormat][targetFormat].size() == 0) + // throw std::invalid_argument("no registered functions for: " sourceFormat + " to "+ targetFormat + "."); + + for(const auto &it:Converters[sourceFormat][targetFormat]) + { + FormatConverterPriority priority = it.first; + priorities.push_back(priority); + } + + return priorities; + +} + SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat, const std::string &targetFormat) { if (Converters.count(sourceFormat) == 0) @@ -64,5 +80,19 @@ SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat if (Converters[sourceFormat].count(targetFormat) == 0) throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - return Converters[sourceFormat][targetFormat]; + return Converters[sourceFormat][targetFormat].rbegin()->second; +} + +SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat, const std::string &targetFormat, FormatConverterPriority &priority) +{ + if (Converters.count(sourceFormat) == 0) + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + + if (Converters[sourceFormat].count(targetFormat) == 0) + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + + if (Converters[sourceFormat][targetFormat].count(priority) == 0) + throw std::invalid_argument("unsupported target priority: " + std::to_string(priority) + "."); + + return Converters[sourceFormat][targetFormat][priority]; } From 33d4e30951f9e8356f014bcfbe1ea4b1b1cbf585 Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 8 Sep 2017 21:06:53 +0000 Subject: [PATCH 18/38] exercise priority selection --- devel/CMakeLists.txt | 7 ++- devel/TestFormatConvert.cpp | 101 ++++++++++++++++++++++++++++-------- 2 files changed, 81 insertions(+), 27 deletions(-) diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt index 58f129a5..ea82b766 100644 --- a/devel/CMakeLists.txt +++ b/devel/CMakeLists.txt @@ -13,10 +13,9 @@ # Unit tests ######################################################################## -add_executable(BufferSim BufferSim.cpp) -target_compile_options(BufferSim PRIVATE -g) -target_link_libraries(BufferSim SoapySDR) +# add_executable(BufferSim BufferSim.cpp) +# target_compile_options(BufferSim PRIVATE -g) +# target_link_libraries(BufferSim SoapySDR) add_executable(TestFormatConvert TestFormatConvert.cpp) target_link_libraries(TestFormatConvert SoapySDR) -#add_test(BufferSim BufferSim) diff --git a/devel/TestFormatConvert.cpp b/devel/TestFormatConvert.cpp index 758bed9d..fdfe296e 100644 --- a/devel/TestFormatConvert.cpp +++ b/devel/TestFormatConvert.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2015 Josh Blum +// Copyright (c) 2017-2017 Coburn Wightman // SPDX-License-Identifier: BSL-1.0 #include "convertPrimatives.hpp" @@ -57,6 +57,24 @@ SoapySDR::ConvertFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, cons return 0; } +SoapySDR::ConvertFunction cvtCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CS16 to CF32 (hot shot)" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + SoapySDR::ConvertFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -85,48 +103,85 @@ int main(void) int32_t devBuffer[numElems * elemDepth]; int32_t soapyBuffer[numElems * elemDepth]; - std::cout << "registering converters..." << std::endl; - SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32); - SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32); - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32); + SoapySDR::FormatConverterPriority priority; + + priority = SoapySDR::VECTORIZED; + std::cout << "registering priority " << std::to_string(priority) << " converters..." << std::endl; + SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32, priority); + SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32hs, priority); + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); try{ - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32); + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); } catch (const std::exception &ex){ std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; } - std::cout << std::endl << "get supported target formats for " << SOAPY_SDR_CF32 << std::endl; - std::vector formats; - formats = SoapySDR::convertTargetFormats(SOAPY_SDR_CF32); - for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) + priority = SoapySDR::GENERIC; + std::cout << "registering priority " << std::to_string(priority) << " converters..." << std::endl; + //SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32, priority); + SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32, priority); + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); + + priority = SoapySDR::CUSTOM; + std::cout << "registering priority " << std::to_string(priority) << " converters..." << std::endl; + SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32, priority); + //SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32, priority); + SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); + + std::string sourceFormat = SOAPY_SDR_CS16; + std::string targetFormat = SOAPY_SDR_CF32; + + std::cout << std::endl << "get supported target formats for " << sourceFormat << std::endl; + std::vector targets = SoapySDR::convertTargetFormats(sourceFormat); + for(const auto target:targets) { - std::cout << " " << *it << std::endl; + std::cout << " " << target; + std::vector priorities = SoapySDR::getConverterPriorities(sourceFormat, target); + for(const auto priority:priorities) + { + std::cout << " " << priority; + } + std::cout << std::endl; } - std::cout << "get supported source formats for " << SOAPY_SDR_CF32 << std::endl; - formats = SoapySDR::convertSourceFormats(SOAPY_SDR_CF32); - for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) + std::cout << "get supported source formats for " << targetFormat << std::endl; + std::vector sources = SoapySDR::convertSourceFormats(targetFormat); + for(const auto source:sources) { - std::cout << " " << *it << std::endl; + std::cout << " " << source; + std::vector priorities = SoapySDR::getConverterPriorities(source, targetFormat); + for(const auto priority:priorities) + { + std::cout << " " << priority; + } + std::cout << std::endl; } - std::string inElemFormat = SOAPY_SDR_CS16; - std::string outElemFormat = SOAPY_SDR_CF32; + sourceFormat = SOAPY_SDR_CS16; + targetFormat = SOAPY_SDR_CF32; - std::cout << std::endl << "try a registered conversion..." << std::endl; - SoapySDR::ConvertFunction convert = SoapySDR::getConverter(inElemFormat, outElemFormat); + std::cout << std::endl << "creating bogus buffer." << std::endl; + fillBuffer((uint8_t*)devBuffer, numElems, sourceFormat); + dumpBuffer((uint8_t*)devBuffer, numElems, sourceFormat); - fillBuffer((uint8_t*)devBuffer, numElems, inElemFormat); - dumpBuffer((uint8_t*)devBuffer, numElems, inElemFormat); + std::cout << std::endl << "try a registered generic priority conversion..." << std::endl; + priority = SoapySDR::GENERIC; + SoapySDR::ConvertFunction convert; + convert = SoapySDR::getConverter(sourceFormat, targetFormat, priority); + convert(devBuffer, soapyBuffer, numElems, 2); + std::cout << std::endl << "try a registered unspecified priority conversion..." << std::endl; + priority = SoapySDR::GENERIC; + convert = SoapySDR::getConverter(sourceFormat, targetFormat); convert(devBuffer, soapyBuffer, numElems, 2); - dumpBuffer((uint8_t*)soapyBuffer, numElems, outElemFormat); + + dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); std::cout << std::endl << "try an unregistered conversion..." << std::endl; try{ - convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16); + convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16, priority); convert(devBuffer, soapyBuffer, numElems, 0.1); } catch (const std::exception &ex){ From eb21eaec34e50481509777a152bf21354a793874 Mon Sep 17 00:00:00 2001 From: Coburn Date: Tue, 12 Sep 2017 20:51:28 +0000 Subject: [PATCH 19/38] transition from function format to object format --- include/SoapySDR/ConverterRegistry.hpp | 132 +++++++++++++++++++++++++ lib/CMakeLists.txt | 1 + lib/ConverterRegistry.cpp | 124 +++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 include/SoapySDR/ConverterRegistry.hpp create mode 100644 lib/ConverterRegistry.cpp diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp new file mode 100644 index 00000000..550da77b --- /dev/null +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -0,0 +1,132 @@ +/// +/// \file SoapySDR/RegisterConverters.hpp +/// +/// Convert buffers between stream formats. +/// +/// \copyright +/// Copyright (c) 2015-2015 Josh Blum +/// Copyright (c) 2017-2017 Coburn Wightman +/// SPDX-License-Identifier: BSL-1.0 +/// + +#pragma once +#include +#include +#include +#include +#include + +namespace SoapySDR +{ +/*! + * A typedef for a conversion function. + * A conversion function converts an input buffer into and output buffer. + * The parameters are (input pointer, output pointer, number of elements, optional scalar) + */ +typedef void (*FormatConverterFunction)(const void *, void *, const size_t, const double); + +/*! + * FormatConverterPriority: allow selection of a converter function with a given source and target format + */ +enum FormatConverterPriority{ + GENERIC = 0, // usual C for loops and shifts and multiplies + VECTORIZED = 3, // using SIMD vectorized operations probably + CUSTOM = 5 // custom user re-implementation, max prio +}; + +/*! + * TargetFormatConverterPriority: a map of possible conversion functions for a given priority. + */ +typedef std::map TargetFormatConverterPriority; + +/*! + * TargetFormatConverters: a map of possible conversion functions for a given Target Format. + */ +typedef std::map TargetFormatConverters; + +/*! + * FormatConverters: a map of possible conversion functions for a given Source Format. + */ +typedef std::map FormatConverters; + + + +class SOAPY_SDR_API ConverterRegistry +{ +public: + + /*! + * Class constructor for managing the Converter Registry. + * \throws invalid_argument if the converter already exists + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \param priority the priority of the converter to register + * \param converter function to register + */ + ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, FormatConverterPriority &, FormatConverterFunction); + + /*! + * Class constructor for using the Converter Registry. + * \param none no parameters + */ + ConverterRegistry(void); + + ~ConverterRegistry(void); + + /*! + * Remove the converter registered by this object otherwise do nothing. + * \param none + * \return nothing + */ + void remove(void); + + /*! + * Get a list of formats to which we can convert the source format into. + * There is a registered conversion function from the specified source + * format to every target format returned in the result vector. + * \param sourceFormat the source format markup string + * \return a list of target formats + */ + std::vector listTargetFormats(const std::string &sourceFormat); + + /*! + * Get a list of formats to which we can convert the target format from. + * There is a registered conversion function from every source format + * returned in the result vector to the specified target format. + * \param targetFormat the target format markup string + * \return a list of source formats + */ + std::vector listSourceFormats(const std::string &targetFormat); + + + /*! + * Get a list of available converter priorities for a given source and target format. + * \throws invalid_argument when the conversion does not exist + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \return a vector of priorities + */ + std::vector listPriorities(const std::string &sourceFormat, const std::string &targetFormat); + + /*! + * Get a converter between a source and target format. + * \throws invalid_argument when the conversion does not exist + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \return a conversion function pointer + */ + FormatConverterFunction getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat); + FormatConverterFunction getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat, const FormatConverterPriority &priority); + +private: + static SoapySDR::FormatConverters formatConverters; + + std::string _sourceFormat; + std::string _targetFormat; + FormatConverterPriority _priority; + + bool _isRegistered; + +}; + +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c12fd854..aff022c2 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -22,6 +22,7 @@ list(APPEND SOAPY_SDR_SOURCES Errors.cpp Formats.cpp Convert.cpp + ConverterRegistry.cpp ) #dl libs used by dlopen in unix diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp new file mode 100644 index 00000000..48c55b2f --- /dev/null +++ b/lib/ConverterRegistry.cpp @@ -0,0 +1,124 @@ +// Copyright (c) 2017-2017 Coburn Wightman +// SPDX-License-Identifier: BSL-1.0 + +#include +#include + +SoapySDR::FormatConverters SoapySDR::ConverterRegistry::formatConverters; + +SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, SoapySDR::FormatConverterPriority &priority, SoapySDR::FormatConverterFunction converterFunction) +{ + if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) + { + throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority) + "."); + } + + formatConverters[sourceFormat][targetFormat][priority] = converterFunction; + + _sourceFormat = sourceFormat; + _targetFormat = targetFormat; + _priority = priority; + _isRegistered = true; + + std::cout << '+'; + return; +} + +SoapySDR::ConverterRegistry::ConverterRegistry(void) +{ + _isRegistered = false; + return; +} + +SoapySDR::ConverterRegistry::~ConverterRegistry(void) +{ + return; +} + +void SoapySDR::ConverterRegistry::remove(void) +{ + if (_isRegistered == true) + formatConverters[_sourceFormat][_targetFormat].erase(_priority); + + std::cout << "~"; + return; +} + +std::vector SoapySDR::ConverterRegistry::listTargetFormats(const std::string &sourceFormat) +{ + std::vector targets; + + if (formatConverters.count(sourceFormat) == 0) + return targets; + + for(const auto &it:formatConverters[sourceFormat]) + { + std::string targetFormat = it.first; + targets.push_back(targetFormat); + } + + return targets; +} + +std::vector SoapySDR::ConverterRegistry::listSourceFormats(const std::string &targetFormat) +{ + std::vector sources; + + for(const auto &it:formatConverters) + { + std::string sourceFormat = it.first; + if (formatConverters[sourceFormat].count(targetFormat) > 0) + sources.push_back(sourceFormat); + } + + return sources; +} + +std::vector SoapySDR::ConverterRegistry::listPriorities(const std::string &sourceFormat, const std::string &targetFormat) +{ + std::vector priorities; + + if (formatConverters.count(sourceFormat) == 0) + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + + if (formatConverters[sourceFormat].count(targetFormat) == 0) + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + + if (formatConverters[sourceFormat][targetFormat].size() == 0) + throw std::invalid_argument("no registered functions for: " + sourceFormat + " to "+ targetFormat + "."); + + for(const auto &it:formatConverters[sourceFormat][targetFormat]) + { + FormatConverterPriority priority = it.first; + priorities.push_back(priority); + } + + return priorities; + +} + +SoapySDR::FormatConverterFunction SoapySDR::ConverterRegistry::getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat) +{ + if (formatConverters.count(sourceFormat) == 0) + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + + if (formatConverters[sourceFormat].count(targetFormat) == 0) + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + + return formatConverters[sourceFormat][targetFormat].rbegin()->second; +} + +SoapySDR::FormatConverterFunction SoapySDR::ConverterRegistry::getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat, const SoapySDR::FormatConverterPriority &priority) +{ + if (formatConverters.count(sourceFormat) == 0) + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + + if (formatConverters[sourceFormat].count(targetFormat) == 0) + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + + if (formatConverters[sourceFormat][targetFormat].count(priority) == 0) + throw std::invalid_argument("unsupported target priority: " + std::to_string(priority) + "."); + + return formatConverters[sourceFormat][targetFormat][priority]; +} + From 54fd972aee801500aba26a2a494dda6709875689 Mon Sep 17 00:00:00 2001 From: Coburn Date: Tue, 12 Sep 2017 20:54:53 +0000 Subject: [PATCH 20/38] exercise ConverterRegistry class --- devel/CMakeLists.txt | 7 +- devel/TestFormatConvertClass.cpp | 307 ++++++++++++++++++ ...ert.cpp => TestFormatConvertFunctions.cpp} | 2 +- 3 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 devel/TestFormatConvertClass.cpp rename devel/{TestFormatConvert.cpp => TestFormatConvertFunctions.cpp} (99%) diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt index ea82b766..67a96718 100644 --- a/devel/CMakeLists.txt +++ b/devel/CMakeLists.txt @@ -17,5 +17,8 @@ # target_compile_options(BufferSim PRIVATE -g) # target_link_libraries(BufferSim SoapySDR) -add_executable(TestFormatConvert TestFormatConvert.cpp) -target_link_libraries(TestFormatConvert SoapySDR) +add_executable(TestFormatConvertFunctions TestFormatConvertFunctions.cpp) +target_link_libraries(TestFormatConvertFunctions SoapySDR) + +add_executable(TestFormatConvertClass TestFormatConvertClass.cpp) +target_link_libraries(TestFormatConvertClass SoapySDR) diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp new file mode 100644 index 00000000..97143053 --- /dev/null +++ b/devel/TestFormatConvertClass.cpp @@ -0,0 +1,307 @@ +// Copyright (c) 2017-2017 Coburn Wightman +// SPDX-License-Identifier: BSL-1.0 + +#include "convertPrimatives.hpp" +//#include +#include +#include +#include +#include //memcpy + +bool fillBuffer(uint8_t*, int, std::string); +bool dumpBuffer(uint8_t*, int, std::string); + + +SoapySDR::FormatConverterFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CF32 to CF32" << std::endl; + + if (scaler == 1.0) + { + size_t elemSize = 4; + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + std::cout << " straight memcpy" << std::endl; + } + else + { + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + float *src = (float*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + // dst[i] = src[i] * sf; + // dst[i+1] = src[i+1] * sf; + CF32toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + } + return 0; +} + +SoapySDR::FormatConverterFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CS16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +SoapySDR::FormatConverterFunction cvtCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CS16 to CF32 (hot shot)" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +SoapySDR::FormatConverterFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CU16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + uint16_t *src = (uint16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + //dst[i] = src[i] - 0x7fff) * scaler; + CU16toCF32(src, dst, sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +// ****************************** + +void dumpSources(std::string targetFormat) +{ + auto myConverter = new SoapySDR::ConverterRegistry(); + std::cout << "get supported source formats for " << targetFormat << std::endl; + std::vector sources = myConverter->listSourceFormats(targetFormat); + for(const auto source:sources) + { + std::cout << " " << source << " > " << targetFormat; + std::vector priorities = myConverter->listPriorities(source, targetFormat); + for(const auto priority:priorities) + { + std::cout << " " << priority; + } + std::cout << std::endl; + } + +} + +int main(void) +{ + const size_t numElems = 128; + const size_t elemDepth = 2; + int32_t devBuffer[numElems * elemDepth]; + int32_t soapyBuffer[numElems * elemDepth]; + + std::vector converters; + + SoapySDR::FormatConverterPriority priority; + + if (false){ + std::cout << "registering a duplicate converters..." << std::endl; + try{ + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); + } + catch (const std::exception &ex){ + std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; + } + } + + priority = SoapySDR::GENERIC; + + std::cout << "registering priority " << std::to_string(priority) << " converters"; + + converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCF32toCF32); + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCS16toCF32); + converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); + std::cout << std::endl; + + priority = SoapySDR::VECTORIZED; + std::cout << "registering priority " << std::to_string(priority) << " converters"; + converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCF32toCF32); + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCS16toCF32); + converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); + std::cout << std::endl; + + priority = SoapySDR::CUSTOM; + std::cout << "registering priority " << std::to_string(priority) << " converters"; + converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCF32toCF32); + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCS16toCF32); + converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); + std::cout << std::endl; + + auto myConverter = new SoapySDR::ConverterRegistry(); + + std::string sourceFormat = SOAPY_SDR_CS16; + std::string targetFormat = SOAPY_SDR_CF32; + + std::cout << std::endl << "get supported target formats for " << sourceFormat << std::endl; + std::vector targets = myConverter->listTargetFormats(sourceFormat); + for(const auto target:targets) + { + std::cout << " " << sourceFormat << " > " << target; + std::vector priorities = myConverter->listPriorities(sourceFormat, target); + for(const auto priority:priorities) + { + std::cout << " " << priority; + } + std::cout << std::endl; + } + + std::cout << "get supported source formats for " << targetFormat << std::endl; + std::vector sources = myConverter->listSourceFormats(targetFormat); + for(const auto source:sources) + { + std::cout << " " << source << " > " << targetFormat; + std::vector priorities = myConverter->listPriorities(source, targetFormat); + for(const auto priority:priorities) + { + std::cout << " " << priority; + } + std::cout << std::endl; + } + + sourceFormat = SOAPY_SDR_CS16; + targetFormat = SOAPY_SDR_CF32; + + std::cout << std::endl << "creating bogus buffer." << std::endl; + fillBuffer((uint8_t*)devBuffer, numElems, sourceFormat); + dumpBuffer((uint8_t*)devBuffer, numElems, sourceFormat); + + std::cout << std::endl << "try a registered generic priority conversion..." << std::endl; + priority = SoapySDR::GENERIC; + SoapySDR::FormatConverterFunction converterFunction = myConverter->getConverterFunction(sourceFormat, targetFormat, priority); + converterFunction(devBuffer, soapyBuffer, numElems, 2); + + // std::cout << std::endl << "try a registered unspecified priority conversion..." << std::endl; + // priority = SoapySDR::GENERIC; + // convert = SoapySDR::getConverter(sourceFormat, targetFormat); + // convert(devBuffer, soapyBuffer, numElems, 2); + + dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); + + // std::cout << std::endl << "try an unregistered conversion..." << std::endl; + // try{ + // convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16, priority); + // convert(devBuffer, soapyBuffer, numElems, 0.1); + // } + // catch (const std::exception &ex){ + // std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; + // } + + std::cout << "unregistering converters"; + while (!converters.empty()) + { + converters.rbegin()->remove(); + converters.pop_back(); + } + std::cout << std::endl; + + std::cout << "DONE!" << std::endl; + return EXIT_SUCCESS; +} + +bool fillBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ + size_t elemDepth = 2; + + if (elemFormat == SOAPY_SDR_CF32){ + float* buff = (float*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = (float)i; + buff[i+1] = (float)i+1; + } + } + else if (elemFormat == SOAPY_SDR_CS32){ + int32_t* buff = (int32_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = i; + buff[i+1] = i+1; + } + } + else if (elemFormat == SOAPY_SDR_CS16){ + int16_t* buff = (int16_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + buff[i] = i; + buff[i+1] = i+1; + } + } + else + std::cout << "unrecognized elem format" << std::endl; + + return true; +} + +bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ + size_t elemDepth = 2; + + if (elemFormat == SOAPY_SDR_CF32){ + float* buff = (float*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0){ + std::cout << std::endl << i << " > "; + } + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else if (elemFormat == SOAPY_SDR_CS32){ + int32_t* buff = (int32_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0){ + std::cout << std::endl << i << " > "; + } + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else if (elemFormat == SOAPY_SDR_CS16){ + int16_t* buff = (int16_t*)buffer; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + if (i%16 == 0){ + std::cout << std::endl << i << " > "; + } + std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; + } + } + else{ + std::cout << "unrecognized elem format" << std::endl; + return false; + } + + std::cout << std::endl; + + return true; +} diff --git a/devel/TestFormatConvert.cpp b/devel/TestFormatConvertFunctions.cpp similarity index 99% rename from devel/TestFormatConvert.cpp rename to devel/TestFormatConvertFunctions.cpp index fdfe296e..c37dbb0d 100644 --- a/devel/TestFormatConvert.cpp +++ b/devel/TestFormatConvertFunctions.cpp @@ -104,7 +104,7 @@ int main(void) int32_t soapyBuffer[numElems * elemDepth]; SoapySDR::FormatConverterPriority priority; - + priority = SoapySDR::VECTORIZED; std::cout << "registering priority " << std::to_string(priority) << " converters..." << std::endl; SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32, priority); From d486cc1cbad9246ef2139a76e9346e1d85e4e3d3 Mon Sep 17 00:00:00 2001 From: Coburn Date: Wed, 13 Sep 2017 16:18:47 +0000 Subject: [PATCH 21/38] refine namespaces --- devel/TestFormatConvertClass.cpp | 137 ++++++++-------- include/SoapySDR/ConverterRegistry.hpp | 214 ++++++++++++------------- lib/ConverterRegistry.cpp | 14 +- 3 files changed, 175 insertions(+), 190 deletions(-) diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp index 97143053..26203b9d 100644 --- a/devel/TestFormatConvertClass.cpp +++ b/devel/TestFormatConvertClass.cpp @@ -12,7 +12,7 @@ bool fillBuffer(uint8_t*, int, std::string); bool dumpBuffer(uint8_t*, int, std::string); -SoapySDR::FormatConverterFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +SoapySDR::ConverterRegistry::ConverterFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -40,7 +40,7 @@ SoapySDR::FormatConverterFunction cvtCF32toCF32(const void *srcBuff, void *dstBu return 0; } -SoapySDR::FormatConverterFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +SoapySDR::ConverterRegistry::ConverterFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -58,7 +58,7 @@ SoapySDR::FormatConverterFunction cvtCS16toCF32(const void *srcBuff, void *dstBu return 0; } -SoapySDR::FormatConverterFunction cvtCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +SoapySDR::ConverterRegistry::ConverterFunction cvtCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -76,7 +76,7 @@ SoapySDR::FormatConverterFunction cvtCS16toCF32hs(const void *srcBuff, void *dst return 0; } -SoapySDR::FormatConverterFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +SoapySDR::ConverterRegistry::ConverterFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -96,6 +96,22 @@ SoapySDR::FormatConverterFunction cvtCU16toCF32(const void *srcBuff, void *dstBu } // ****************************** +void dumpTargets(std::string sourceFormat) +{ + auto myConverter = new SoapySDR::ConverterRegistry(); + std::cout << "get supported target formats for " << sourceFormat << std::endl; + std::vector targets = myConverter->listTargetFormats(sourceFormat); + for(const auto target:targets) + { + std::cout << " " << sourceFormat << " > " << target; + std::vector priorities = myConverter->listPriorities(sourceFormat, target); + for(const auto priority:priorities) + { + std::cout << " " << priority; + } + std::cout << std::endl; + } +} void dumpSources(std::string targetFormat) { @@ -105,7 +121,7 @@ void dumpSources(std::string targetFormat) for(const auto source:sources) { std::cout << " " << source << " > " << targetFormat; - std::vector priorities = myConverter->listPriorities(source, targetFormat); + std::vector priorities = myConverter->listPriorities(source, targetFormat); for(const auto priority:priorities) { std::cout << " " << priority; @@ -124,99 +140,72 @@ int main(void) std::vector converters; - SoapySDR::FormatConverterPriority priority; - - if (false){ - std::cout << "registering a duplicate converters..." << std::endl; - try{ - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); - } - catch (const std::exception &ex){ - std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; - } - } - - priority = SoapySDR::GENERIC; + SoapySDR::ConverterRegistry::FunctionPriority priority; + priority = SoapySDR::ConverterRegistry::GENERIC; std::cout << "registering priority " << std::to_string(priority) << " converters"; - - converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCF32toCF32); - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCS16toCF32); - converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); + converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCF32toCF32); + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCS16toCF32); + converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); std::cout << std::endl; - priority = SoapySDR::VECTORIZED; + priority = SoapySDR::ConverterRegistry::VECTORIZED; std::cout << "registering priority " << std::to_string(priority) << " converters"; - converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCF32toCF32); - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCS16toCF32); - converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); + converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCF32toCF32); + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCS16toCF32); + converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); std::cout << std::endl; - priority = SoapySDR::CUSTOM; + priority = SoapySDR::ConverterRegistry::CUSTOM; std::cout << "registering priority " << std::to_string(priority) << " converters"; - converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCF32toCF32); - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCS16toCF32); - converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::FormatConverterFunction) cvtCU16toCF32); + converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCF32toCF32); + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCS16toCF32); + converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); std::cout << std::endl; - + + std::cout << std::endl << "registering a duplicate converters..." << std::endl; + try + { + converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); + } + catch (const std::exception &ex){ + std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; + } + auto myConverter = new SoapySDR::ConverterRegistry(); std::string sourceFormat = SOAPY_SDR_CS16; std::string targetFormat = SOAPY_SDR_CF32; - std::cout << std::endl << "get supported target formats for " << sourceFormat << std::endl; - std::vector targets = myConverter->listTargetFormats(sourceFormat); - for(const auto target:targets) - { - std::cout << " " << sourceFormat << " > " << target; - std::vector priorities = myConverter->listPriorities(sourceFormat, target); - for(const auto priority:priorities) - { - std::cout << " " << priority; - } - std::cout << std::endl; - } - - std::cout << "get supported source formats for " << targetFormat << std::endl; - std::vector sources = myConverter->listSourceFormats(targetFormat); - for(const auto source:sources) - { - std::cout << " " << source << " > " << targetFormat; - std::vector priorities = myConverter->listPriorities(source, targetFormat); - for(const auto priority:priorities) - { - std::cout << " " << priority; - } - std::cout << std::endl; - } + dumpTargets(sourceFormat); + dumpSources(targetFormat); - sourceFormat = SOAPY_SDR_CS16; - targetFormat = SOAPY_SDR_CF32; - - std::cout << std::endl << "creating bogus buffer." << std::endl; + std::cout << std::endl << "creating bogus " << sourceFormat << " buffer." << std::endl; fillBuffer((uint8_t*)devBuffer, numElems, sourceFormat); dumpBuffer((uint8_t*)devBuffer, numElems, sourceFormat); std::cout << std::endl << "try a registered generic priority conversion..." << std::endl; - priority = SoapySDR::GENERIC; - SoapySDR::FormatConverterFunction converterFunction = myConverter->getConverterFunction(sourceFormat, targetFormat, priority); + priority = SoapySDR::ConverterRegistry::GENERIC; + SoapySDR::ConverterRegistry::ConverterFunction converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); converterFunction(devBuffer, soapyBuffer, numElems, 2); - // std::cout << std::endl << "try a registered unspecified priority conversion..." << std::endl; - // priority = SoapySDR::GENERIC; - // convert = SoapySDR::getConverter(sourceFormat, targetFormat); - // convert(devBuffer, soapyBuffer, numElems, 2); + dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); + + std::cout << std::endl << "try a registered unspecified priority conversion..." << std::endl; + priority = SoapySDR::ConverterRegistry::GENERIC; + converterFunction = myConverter->getFunction(sourceFormat, targetFormat); + converterFunction(devBuffer, soapyBuffer, numElems, 2); dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); - // std::cout << std::endl << "try an unregistered conversion..." << std::endl; - // try{ - // convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16, priority); - // convert(devBuffer, soapyBuffer, numElems, 0.1); - // } - // catch (const std::exception &ex){ - // std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; - // } + std::cout << std::endl << "try an unregistered conversion..." << std::endl; + try{ + converterFunction = myConverter->getFunction(SOAPY_SDR_CU16, SOAPY_SDR_CS16, priority); + converterFunction(devBuffer, soapyBuffer, numElems, 0.1); + } + catch (const std::exception &ex){ + std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; + } std::cout << "unregistering converters"; while (!converters.empty()) diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index 550da77b..43e27180 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -18,115 +18,111 @@ namespace SoapySDR { -/*! - * A typedef for a conversion function. - * A conversion function converts an input buffer into and output buffer. - * The parameters are (input pointer, output pointer, number of elements, optional scalar) - */ -typedef void (*FormatConverterFunction)(const void *, void *, const size_t, const double); + class SOAPY_SDR_API ConverterRegistry + { + public: + /*! + * A typedef for a conversion function. + * A conversion function converts an input buffer into and output buffer. + * The parameters are (input pointer, output pointer, number of elements, optional scalar) + */ + typedef void (*ConverterFunction)(const void *, void *, const size_t, const double); -/*! - * FormatConverterPriority: allow selection of a converter function with a given source and target format - */ -enum FormatConverterPriority{ - GENERIC = 0, // usual C for loops and shifts and multiplies - VECTORIZED = 3, // using SIMD vectorized operations probably - CUSTOM = 5 // custom user re-implementation, max prio -}; - -/*! - * TargetFormatConverterPriority: a map of possible conversion functions for a given priority. - */ -typedef std::map TargetFormatConverterPriority; - -/*! - * TargetFormatConverters: a map of possible conversion functions for a given Target Format. - */ -typedef std::map TargetFormatConverters; - -/*! - * FormatConverters: a map of possible conversion functions for a given Source Format. - */ -typedef std::map FormatConverters; - - - -class SOAPY_SDR_API ConverterRegistry -{ -public: - - /*! - * Class constructor for managing the Converter Registry. - * \throws invalid_argument if the converter already exists - * \param sourceFormat the source format markup string - * \param targetFormat the target format markup string - * \param priority the priority of the converter to register - * \param converter function to register - */ - ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, FormatConverterPriority &, FormatConverterFunction); - - /*! - * Class constructor for using the Converter Registry. - * \param none no parameters - */ - ConverterRegistry(void); - - ~ConverterRegistry(void); - - /*! - * Remove the converter registered by this object otherwise do nothing. - * \param none - * \return nothing - */ - void remove(void); - - /*! - * Get a list of formats to which we can convert the source format into. - * There is a registered conversion function from the specified source - * format to every target format returned in the result vector. - * \param sourceFormat the source format markup string - * \return a list of target formats - */ - std::vector listTargetFormats(const std::string &sourceFormat); - - /*! - * Get a list of formats to which we can convert the target format from. - * There is a registered conversion function from every source format - * returned in the result vector to the specified target format. - * \param targetFormat the target format markup string - * \return a list of source formats - */ - std::vector listSourceFormats(const std::string &targetFormat); - - - /*! - * Get a list of available converter priorities for a given source and target format. - * \throws invalid_argument when the conversion does not exist - * \param sourceFormat the source format markup string - * \param targetFormat the target format markup string - * \return a vector of priorities - */ - std::vector listPriorities(const std::string &sourceFormat, const std::string &targetFormat); + /*! + * FormatConverterPriority: allow selection of a converter function with a given source and target format + */ + enum FunctionPriority{ + GENERIC = 0, // usual C for loops and shifts and multiplies + VECTORIZED = 3, // using SIMD vectorized operations probably + CUSTOM = 5 // custom user re-implementation, max prio + }; + + /*! + * TargetFormatConverterPriority: a map of possible conversion functions for a given Priority. + */ + typedef std::map TargetFormatConverterPriority; + + /*! + * TargetFormatConverters: a map of possible conversion functions for a given Target/Priority Format. + */ + typedef std::map TargetFormatConverters; + + /*! + * FormatConverters: a map of possible conversion functions for a given Source/Target Format. + */ + typedef std::map FormatConverters; + + /*! + * Class constructor for managing the Converter Registry. + * \throws invalid_argument if the converter already exists + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \param priority the priority of the converter to register + * \param converter function to register + */ + ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, FunctionPriority &, ConverterFunction); + + /*! + * Class constructor for using the Converter Registry. + * \param none no parameters + */ + ConverterRegistry(void); + + ~ConverterRegistry(void); + + /*! + * Remove the converter registered by this object otherwise do nothing. + * \param none + * \return nothing + */ + void remove(void); + + /*! + * Get a list of formats to which we can convert the source format into. + * There is a registered conversion function from the specified source + * format to every target format returned in the result vector. + * \param sourceFormat the source format markup string + * \return a list of target formats + */ + std::vector listTargetFormats(const std::string &sourceFormat); + + /*! + * Get a list of formats to which we can convert the target format from. + * There is a registered conversion function from every source format + * returned in the result vector to the specified target format. + * \param targetFormat the target format markup string + * \return a list of source formats + */ + std::vector listSourceFormats(const std::string &targetFormat); + + /*! + * Get a list of available converter priorities for a given source and target format. + * \throws invalid_argument when the conversion does not exist + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \return a vector of priorities + */ + std::vector listPriorities(const std::string &sourceFormat, const std::string &targetFormat); + + /*! + * Get a converter between a source and target format. + * \throws invalid_argument when the conversion does not exist + * \param sourceFormat the source format markup string + * \param targetFormat the target format markup string + * \return a conversion function pointer + */ + ConverterFunction getFunction(const std::string &sourceFormat, const std::string &targetFormat); + ConverterFunction getFunction(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority); + + private: + static FormatConverters formatConverters; + + std::string _sourceFormat; + std::string _targetFormat; + FunctionPriority _priority; + + bool _isRegistered; + + }; - /*! - * Get a converter between a source and target format. - * \throws invalid_argument when the conversion does not exist - * \param sourceFormat the source format markup string - * \param targetFormat the target format markup string - * \return a conversion function pointer - */ - FormatConverterFunction getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat); - FormatConverterFunction getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat, const FormatConverterPriority &priority); - -private: - static SoapySDR::FormatConverters formatConverters; - - std::string _sourceFormat; - std::string _targetFormat; - FormatConverterPriority _priority; - - bool _isRegistered; - -}; - } diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index 48c55b2f..eea44cf6 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -4,9 +4,9 @@ #include #include -SoapySDR::FormatConverters SoapySDR::ConverterRegistry::formatConverters; +SoapySDR::ConverterRegistry::FormatConverters SoapySDR::ConverterRegistry::formatConverters; -SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, SoapySDR::FormatConverterPriority &priority, SoapySDR::FormatConverterFunction converterFunction) +SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, FunctionPriority &priority, ConverterFunction converterFunction) { if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) { @@ -74,9 +74,9 @@ std::vector SoapySDR::ConverterRegistry::listSourceFormats(const st return sources; } -std::vector SoapySDR::ConverterRegistry::listPriorities(const std::string &sourceFormat, const std::string &targetFormat) +std::vector SoapySDR::ConverterRegistry::listPriorities(const std::string &sourceFormat, const std::string &targetFormat) { - std::vector priorities; + std::vector priorities; if (formatConverters.count(sourceFormat) == 0) throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); @@ -89,7 +89,7 @@ std::vector SoapySDR::ConverterRegistry::list for(const auto &it:formatConverters[sourceFormat][targetFormat]) { - FormatConverterPriority priority = it.first; + FunctionPriority priority = it.first; priorities.push_back(priority); } @@ -97,7 +97,7 @@ std::vector SoapySDR::ConverterRegistry::list } -SoapySDR::FormatConverterFunction SoapySDR::ConverterRegistry::getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat) +SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getFunction(const std::string &sourceFormat, const std::string &targetFormat) { if (formatConverters.count(sourceFormat) == 0) throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); @@ -108,7 +108,7 @@ SoapySDR::FormatConverterFunction SoapySDR::ConverterRegistry::getConverterFunct return formatConverters[sourceFormat][targetFormat].rbegin()->second; } -SoapySDR::FormatConverterFunction SoapySDR::ConverterRegistry::getConverterFunction(const std::string &sourceFormat, const std::string &targetFormat, const SoapySDR::FormatConverterPriority &priority) +SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getFunction(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority) { if (formatConverters.count(sourceFormat) == 0) throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); From 9b9c2b2cc0891fbaca803aacbdf142be21939ea6 Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 15 Sep 2017 04:38:10 +0000 Subject: [PATCH 22/38] removed most exceptions, added soapy logging. --- include/SoapySDR/ConverterRegistry.hpp | 22 ++++++--- lib/ConverterRegistry.cpp | 63 ++++++++++++++++++-------- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index 43e27180..71902cbf 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -10,6 +10,7 @@ /// #pragma once +#include #include #include #include @@ -54,10 +55,10 @@ namespace SoapySDR /*! * Class constructor for managing the Converter Registry. - * \throws invalid_argument if the converter already exists + * refuses to register converter and logs error if a source/target/priority entry already exists * \param sourceFormat the source format markup string * \param targetFormat the target format markup string - * \param priority the priority of the converter to register + * \param priority the FunctionPriority of the converter to register * \param converter function to register */ ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, FunctionPriority &, ConverterFunction); @@ -69,7 +70,14 @@ namespace SoapySDR ConverterRegistry(void); ~ConverterRegistry(void); - + + /*! + * did the constructor for this instance register a function. + * \param none + * \return true if a function has been registered + */ + bool isRegistered(void); + /*! * Remove the converter registered by this object otherwise do nothing. * \param none @@ -82,7 +90,7 @@ namespace SoapySDR * There is a registered conversion function from the specified source * format to every target format returned in the result vector. * \param sourceFormat the source format markup string - * \return a list of target formats + * \return a vector of target formats or an empty vector if none found */ std::vector listTargetFormats(const std::string &sourceFormat); @@ -91,13 +99,13 @@ namespace SoapySDR * There is a registered conversion function from every source format * returned in the result vector to the specified target format. * \param targetFormat the target format markup string - * \return a list of source formats + * \return a vector of source formats or an empty vector if none found */ std::vector listSourceFormats(const std::string &targetFormat); /*! * Get a list of available converter priorities for a given source and target format. - * \throws invalid_argument when the conversion does not exist + * \throws invalid_argument when the conversion does not exist and logs error * \param sourceFormat the source format markup string * \param targetFormat the target format markup string * \return a vector of priorities @@ -106,7 +114,7 @@ namespace SoapySDR /*! * Get a converter between a source and target format. - * \throws invalid_argument when the conversion does not exist + * \throws invalid_argument when the conversion does not exist and logs error * \param sourceFormat the source format markup string * \param targetFormat the target format markup string * \return a conversion function pointer diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index eea44cf6..d3ec650d 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -10,7 +10,8 @@ SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, { if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) { - throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority) + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "conversion already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority) + "."); + return; } formatConverters[sourceFormat][targetFormat][priority] = converterFunction; @@ -35,6 +36,11 @@ SoapySDR::ConverterRegistry::~ConverterRegistry(void) return; } +bool SoapySDR::ConverterRegistry::isRegistered(void) +{ + return _isRegistered; +} + void SoapySDR::ConverterRegistry::remove(void) { if (_isRegistered == true) @@ -79,19 +85,21 @@ std::vector SoapySDR::ConverterRe std::vector priorities; if (formatConverters.count(sourceFormat) == 0) - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported source format: " + sourceFormat + "."); - if (formatConverters[sourceFormat].count(targetFormat) == 0) - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - - if (formatConverters[sourceFormat][targetFormat].size() == 0) - throw std::invalid_argument("no registered functions for: " + sourceFormat + " to "+ targetFormat + "."); - - for(const auto &it:formatConverters[sourceFormat][targetFormat]) - { - FunctionPriority priority = it.first; - priorities.push_back(priority); - } + else if (formatConverters[sourceFormat].count(targetFormat) == 0) + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target format: " + targetFormat + "."); + + else if (formatConverters[sourceFormat][targetFormat].size() == 0) + SoapySDR::log(SOAPY_SDR_ERROR, "no registered functions for: " + sourceFormat + " to "+ targetFormat + "."); + + else{ + for(const auto &it:formatConverters[sourceFormat][targetFormat]) + { + FunctionPriority priority = it.first; + priorities.push_back(priority); + } + } return priorities; @@ -100,10 +108,16 @@ std::vector SoapySDR::ConverterRe SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getFunction(const std::string &sourceFormat, const std::string &targetFormat) { if (formatConverters.count(sourceFormat) == 0) - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + { + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported source format: " + sourceFormat + "."); + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + } if (formatConverters[sourceFormat].count(targetFormat) == 0) - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + { + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target format: " + targetFormat + "."); + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + } return formatConverters[sourceFormat][targetFormat].rbegin()->second; } @@ -111,14 +125,23 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getFunction(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority) { if (formatConverters.count(sourceFormat) == 0) - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + { + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported source format: " + sourceFormat + "."); + throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + } if (formatConverters[sourceFormat].count(targetFormat) == 0) - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - + { + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target format: " + targetFormat + "."); + throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + } + if (formatConverters[sourceFormat][targetFormat].count(priority) == 0) - throw std::invalid_argument("unsupported target priority: " + std::to_string(priority) + "."); - + { + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target priority: " + std::to_string(priority) + "."); + throw std::invalid_argument("unsupported target priority: " + std::to_string(priority) + "."); + } + return formatConverters[sourceFormat][targetFormat][priority]; } From 19b9f00231238c80317f39859d343870726aae3a Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 15 Sep 2017 04:38:55 +0000 Subject: [PATCH 23/38] exercise logging --- devel/TestFormatConvertClass.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp index 26203b9d..5aed62ab 100644 --- a/devel/TestFormatConvertClass.cpp +++ b/devel/TestFormatConvertClass.cpp @@ -167,6 +167,8 @@ int main(void) try { converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); + if (!converters.rbegin()->isRegistered()) + converters.pop_back(); } catch (const std::exception &ex){ std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; @@ -204,7 +206,7 @@ int main(void) converterFunction(devBuffer, soapyBuffer, numElems, 0.1); } catch (const std::exception &ex){ - std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; + std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; } std::cout << "unregistering converters"; From 8dcc980013aef27907df743e4d3dbc24505ec826 Mon Sep 17 00:00:00 2001 From: Coburn Date: Wed, 20 Sep 2017 21:54:42 +0000 Subject: [PATCH 24/38] Added DefaultConverters class wrapped in a Soapy Module Initializes the converter registry and preloads with a base set of converter functions durring Soapy loadModules(). --- CMakeLists.txt | 1 + convert/CMakeLists.txt | 15 +++ .../ConvertPrimatives.hpp | 13 +-- convert/DefaultConverters.cpp | 97 +++++++++++++++++++ convert/DefaultConverters.hpp | 43 ++++++++ include/SoapySDR/ConverterRegistry.hpp | 8 +- lib/ConverterRegistry.cpp | 40 ++++---- 7 files changed, 185 insertions(+), 32 deletions(-) create mode 100644 convert/CMakeLists.txt rename devel/convertPrimatives.hpp => convert/ConvertPrimatives.hpp (93%) create mode 100644 convert/DefaultConverters.cpp create mode 100644 convert/DefaultConverters.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 930053da..0e0c59f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ install(DIRECTORY include/SoapySDR DESTINATION include) ######################################################################## add_subdirectory(lib) add_subdirectory(apps) +add_subdirectory(convert) add_subdirectory(devel) add_subdirectory(tests) add_subdirectory(docs) diff --git a/convert/CMakeLists.txt b/convert/CMakeLists.txt new file mode 100644 index 00000000..8048e9d6 --- /dev/null +++ b/convert/CMakeLists.txt @@ -0,0 +1,15 @@ +######################################################################## +# Build the Converter Registry plugin module +######################################################################## +SOAPY_SDR_MODULE_UTIL( + TARGET converterRegistry + SOURCES + DefaultConverters.cpp + # Registration.cpp + # Settings.cpp + # Streaming.cpp + # LogAcceptor.cpp + # ClientStreamData.cpp + # LIBRARIES + # SoapySDRRemoteCommon +) diff --git a/devel/convertPrimatives.hpp b/convert/ConvertPrimatives.hpp similarity index 93% rename from devel/convertPrimatives.hpp rename to convert/ConvertPrimatives.hpp index d5b1df36..4604d9d3 100644 --- a/devel/convertPrimatives.hpp +++ b/convert/ConvertPrimatives.hpp @@ -1,14 +1,11 @@ +// ConvertPrimatives.hpp // Copyright (c) 2017-2017 Coburn Wightman" +// +// derived from SoapyRemote/client/ClientStreamData.cpp +// Copyright (c) 2015-2017 Josh Blum // SPDX-License-Identifier: BSL-1.0 #pragma once -//#include -//#include -//#include -//#include -//#include -//#include -//#include #include // Simple Primatives @@ -40,7 +37,7 @@ inline int16_t S16toS16(int16_t from){ } -//floats +// floats inline int32_t F32toS32(float from){ return int32_t(from); } diff --git a/convert/DefaultConverters.cpp b/convert/DefaultConverters.cpp new file mode 100644 index 00000000..77d245ba --- /dev/null +++ b/convert/DefaultConverters.cpp @@ -0,0 +1,97 @@ +// Copyright (c) 2017-2017 Coburn Wightman +// SPDX-License-Identifier: BSL-1.0 + +#include "DefaultConverters.hpp" + + +SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CF32 to CF32" << std::endl; + + if (scaler == 1.0) + { + size_t elemSize = 4; + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + std::cout << " straight memcpy" << std::endl; + } + else + { + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + float *src = (float*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + // dst[i] = src[i] * sf; + // dst[i+1] = src[i+1] * sf; + CF32toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + } + return 0; +} + +SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CS16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CU16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + uint16_t *src = (uint16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + //dst[i] = src[i] - 0x7fff) * scaler; + CU16toCF32(src, dst, sf); + } + std::cout << " sample copy with scaler" << std::endl; + + return 0; +} + +std::vector SoapySDR::DefaultConverters::registry; + +SoapySDR::DefaultConverters::DefaultConverters(void) +{ + SoapySDR::ConverterRegistry::FunctionPriority priority; + + std::cout << "registering default converters" << std::endl; + + priority = SoapySDR::ConverterRegistry::GENERIC; + SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) SoapySDR::DefaultConverters::genericCF32toCF32); + SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) SoapySDR::DefaultConverters::genericCS16toCF32); + SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) SoapySDR::DefaultConverters::genericCU16toCF32); +} + +SoapySDR::DefaultConverters::~DefaultConverters() +{ + std::cout << "unregistering " << SoapySDR::DefaultConverters::registry.size() << " default converters" << std::endl; + while (!SoapySDR::DefaultConverters::registry.empty()) + { + SoapySDR::DefaultConverters::registry.rbegin()->remove(); + SoapySDR::DefaultConverters::registry.pop_back(); + } +} + +static SoapySDR::DefaultConverters* converterRegistry = new SoapySDR::DefaultConverters(); + diff --git a/convert/DefaultConverters.hpp b/convert/DefaultConverters.hpp new file mode 100644 index 00000000..2b316de1 --- /dev/null +++ b/convert/DefaultConverters.hpp @@ -0,0 +1,43 @@ +/// +/// \file converter/DefaultConverters.hpp +/// +/// Convert buffers between stream formats. +/// +/// \copyright +/// Copyright (c) 2017-2017 Coburn Wightman +/// SPDX-License-Identifier: BSL-1.0 +/// + +#pragma once +//#include +#include "ConvertPrimatives.hpp" +#include +#include +#include +#include +#include +#include //memcpy +#include +#include +#include +#include + +namespace SoapySDR +{ + class SOAPY_SDR_API DefaultConverters + { + public: + DefaultConverters(void); + ~DefaultConverters(void); + + private: + + static SoapySDR::ConverterRegistry::ConverterFunction genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler); + static SoapySDR::ConverterRegistry::ConverterFunction genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler); + static SoapySDR::ConverterRegistry::ConverterFunction genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler); + + static std::vector registry; + + }; + +} diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index 71902cbf..64091686 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -33,9 +33,9 @@ namespace SoapySDR * FormatConverterPriority: allow selection of a converter function with a given source and target format */ enum FunctionPriority{ - GENERIC = 0, // usual C for loops and shifts and multiplies - VECTORIZED = 3, // using SIMD vectorized operations probably - CUSTOM = 5 // custom user re-implementation, max prio + GENERIC = 0, // usual C for-loops, shifts, multiplies, etc + VECTORIZED = 3, // vectorized operations such as SIMD + CUSTOM = 5 // custom user re-implementation, max priority }; /*! @@ -61,7 +61,7 @@ namespace SoapySDR * \param priority the FunctionPriority of the converter to register * \param converter function to register */ - ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, FunctionPriority &, ConverterFunction); + ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &, ConverterFunction); /*! * Class constructor for using the Converter Registry. diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index d3ec650d..60d80903 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -2,26 +2,25 @@ // SPDX-License-Identifier: BSL-1.0 #include -#include SoapySDR::ConverterRegistry::FormatConverters SoapySDR::ConverterRegistry::formatConverters; -SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, FunctionPriority &priority, ConverterFunction converterFunction) +SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority, ConverterFunction converterFunction) { if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "conversion already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority) + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "converter already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); return; } formatConverters[sourceFormat][targetFormat][priority] = converterFunction; + SoapySDR::log(SOAPY_SDR_NOTICE, "registered converter: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); _sourceFormat = sourceFormat; _targetFormat = targetFormat; _priority = priority; _isRegistered = true; - std::cout << '+'; return; } @@ -44,9 +43,11 @@ bool SoapySDR::ConverterRegistry::isRegistered(void) void SoapySDR::ConverterRegistry::remove(void) { if (_isRegistered == true) - formatConverters[_sourceFormat][_targetFormat].erase(_priority); + { + formatConverters[_sourceFormat][_targetFormat].erase(_priority); + SoapySDR::log(SOAPY_SDR_NOTICE, "removed converter: " + _sourceFormat + " to " + _targetFormat + " priority " + std::to_string(_priority)); + } - std::cout << "~"; return; } @@ -85,13 +86,13 @@ std::vector SoapySDR::ConverterRe std::vector priorities; if (formatConverters.count(sourceFormat) == 0) - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported source format: " + sourceFormat + "."); + SoapySDR::log(SOAPY_SDR_WARNING, "unsupported converter source format: " + sourceFormat + " to " + targetFormat); else if (formatConverters[sourceFormat].count(targetFormat) == 0) - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target format: " + targetFormat + "."); + SoapySDR::log(SOAPY_SDR_WARNING, "unsupported converter target format: " + sourceFormat + " to " + targetFormat); else if (formatConverters[sourceFormat][targetFormat].size() == 0) - SoapySDR::log(SOAPY_SDR_ERROR, "no registered functions for: " + sourceFormat + " to "+ targetFormat + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "no registered converter functions for: " + sourceFormat + " to " + targetFormat); else{ for(const auto &it:formatConverters[sourceFormat][targetFormat]) @@ -109,14 +110,14 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF { if (formatConverters.count(sourceFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported source format: " + sourceFormat + "."); - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter source format: " + sourceFormat); + throw std::invalid_argument("unsupported converter source format: " + sourceFormat); } if (formatConverters[sourceFormat].count(targetFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target format: " + targetFormat + "."); - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter target format: " + targetFormat); + throw std::invalid_argument("unsupported converter target format: " + targetFormat); } return formatConverters[sourceFormat][targetFormat].rbegin()->second; @@ -126,22 +127,21 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF { if (formatConverters.count(sourceFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported source format: " + sourceFormat + "."); - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter source format: " + sourceFormat); + throw std::invalid_argument("unsupported converter source format: " + sourceFormat); } if (formatConverters[sourceFormat].count(targetFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target format: " + targetFormat + "."); - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter target format: " + targetFormat); + throw std::invalid_argument("unsupported converter target format: " + targetFormat); } if (formatConverters[sourceFormat][targetFormat].count(priority) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported target priority: " + std::to_string(priority) + "."); - throw std::invalid_argument("unsupported target priority: " + std::to_string(priority) + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter target priority: " + std::to_string(priority)); + throw std::invalid_argument("unsupported converter target priority: " + std::to_string(priority)); } return formatConverters[sourceFormat][targetFormat][priority]; } - From e2503013f975faa10bc39dda9c81ccf118ea8c07 Mon Sep 17 00:00:00 2001 From: Coburn Date: Wed, 20 Sep 2017 22:36:31 +0000 Subject: [PATCH 25/38] exercise registry via Soapy API --- devel/CMakeLists.txt | 4 +- devel/TestFormatConvertClass.cpp | 205 ++++++++++++------------------- 2 files changed, 81 insertions(+), 128 deletions(-) diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt index 67a96718..1e832923 100644 --- a/devel/CMakeLists.txt +++ b/devel/CMakeLists.txt @@ -17,8 +17,8 @@ # target_compile_options(BufferSim PRIVATE -g) # target_link_libraries(BufferSim SoapySDR) -add_executable(TestFormatConvertFunctions TestFormatConvertFunctions.cpp) -target_link_libraries(TestFormatConvertFunctions SoapySDR) +# add_executable(TestFormatConvertFunctions TestFormatConvertFunctions.cpp) +# target_link_libraries(TestFormatConvertFunctions SoapySDR) add_executable(TestFormatConvertClass TestFormatConvertClass.cpp) target_link_libraries(TestFormatConvertClass SoapySDR) diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp index 5aed62ab..473ee0ac 100644 --- a/devel/TestFormatConvertClass.cpp +++ b/devel/TestFormatConvertClass.cpp @@ -1,8 +1,10 @@ // Copyright (c) 2017-2017 Coburn Wightman // SPDX-License-Identifier: BSL-1.0 -#include "convertPrimatives.hpp" -//#include +#include "../convert/ConvertPrimatives.hpp" +#include +#include +#include #include #include #include @@ -11,54 +13,8 @@ bool fillBuffer(uint8_t*, int, std::string); bool dumpBuffer(uint8_t*, int, std::string); - -SoapySDR::ConverterRegistry::ConverterFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CF32 to CF32" << std::endl; - - if (scaler == 1.0) - { - size_t elemSize = 4; - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); - std::cout << " straight memcpy" << std::endl; - } - else - { - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - float *src = (float*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - // dst[i] = src[i] * sf; - // dst[i+1] = src[i+1] * sf; - CF32toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - } - return 0; -} - -SoapySDR::ConverterRegistry::ConverterFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CS16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -SoapySDR::ConverterRegistry::ConverterFunction cvtCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +SoapySDR::ConverterRegistry::ConverterFunction customCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, + const double scaler) { size_t elemDepth = 2; @@ -72,30 +28,10 @@ SoapySDR::ConverterRegistry::ConverterFunction cvtCS16toCF32hs(const void *srcBu CS16toCF32(&src[i], &dst[i], sf); } std::cout << " sample copy with scaler" << std::endl; - - return 0; -} -SoapySDR::ConverterRegistry::ConverterFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CU16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - uint16_t *src = (uint16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - //dst[i] = src[i] - 0x7fff) * scaler; - CU16toCF32(src, dst, sf); - } - std::cout << " sample copy with scaler" << std::endl; - return 0; } -// ****************************** void dumpTargets(std::string sourceFormat) { auto myConverter = new SoapySDR::ConverterRegistry(); @@ -131,6 +67,42 @@ void dumpSources(std::string targetFormat) } +static int printInfo(void) +{ + std::cout << "API Version: v" << SoapySDR::getAPIVersion() << std::endl; + std::cout << "ABI Version: v" << SoapySDR::getABIVersion() << std::endl; + std::cout << "Install root: " << SoapySDR::getRootPath() << std::endl; + + std::vector modules = SoapySDR::listModules(); + for (size_t i = 0; i < modules.size(); i++) + { + std::cout << "Module found: " << modules[i] << std::endl; + } + if (modules.empty()) std::cout << "No modules found!" << std::endl; + + std::cout << "Loading modules... " << std::flush; + SoapySDR::loadModules(); + + // std::cout << "Unloading modules... " << std::flush; + // for (size_t i = 0; i < modules.size(); i++) + // { + // SoapySDR::unloadModule(modules[i]); + // std::cout << "Module " << modules[i] << " unloaded." << std::endl; + // } + + std::cout << "Available factories..."; + const SoapySDR::FindFunctions factories = SoapySDR::Registry::listFindFunctions(); + for (SoapySDR::FindFunctions::const_iterator it = factories.begin(); it != factories.end(); ++it) + { + std::cout << it->first << ", "; + } + if (factories.empty()) std::cout << "No factories found!" << std::endl; + else std::cout << std::endl; + + std::cout << std::endl; + return EXIT_SUCCESS; +} + int main(void) { const size_t numElems = 128; @@ -138,46 +110,13 @@ int main(void) int32_t devBuffer[numElems * elemDepth]; int32_t soapyBuffer[numElems * elemDepth]; - std::vector converters; - - SoapySDR::ConverterRegistry::FunctionPriority priority; - - priority = SoapySDR::ConverterRegistry::GENERIC; - std::cout << "registering priority " << std::to_string(priority) << " converters"; - converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCF32toCF32); - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCS16toCF32); - converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); - std::cout << std::endl; + int stat = printInfo(); - priority = SoapySDR::ConverterRegistry::VECTORIZED; - std::cout << "registering priority " << std::to_string(priority) << " converters"; - converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCF32toCF32); - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCS16toCF32); - converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); - std::cout << std::endl; - - priority = SoapySDR::ConverterRegistry::CUSTOM; - std::cout << "registering priority " << std::to_string(priority) << " converters"; - converters.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCF32toCF32); - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCS16toCF32); - converters.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); - std::cout << std::endl; - - std::cout << std::endl << "registering a duplicate converters..." << std::endl; - try - { - converters.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) cvtCU16toCF32); - if (!converters.rbegin()->isRegistered()) - converters.pop_back(); - } - catch (const std::exception &ex){ - std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; - } - auto myConverter = new SoapySDR::ConverterRegistry(); std::string sourceFormat = SOAPY_SDR_CS16; std::string targetFormat = SOAPY_SDR_CF32; + SoapySDR::ConverterRegistry::FunctionPriority priority; dumpTargets(sourceFormat); dumpSources(targetFormat); @@ -186,37 +125,52 @@ int main(void) fillBuffer((uint8_t*)devBuffer, numElems, sourceFormat); dumpBuffer((uint8_t*)devBuffer, numElems, sourceFormat); - std::cout << std::endl << "try a registered generic priority conversion..." << std::endl; + std::cout << std::endl << "try a registered GENERIC priority conversion..." << std::endl; priority = SoapySDR::ConverterRegistry::GENERIC; - SoapySDR::ConverterRegistry::ConverterFunction converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); + SoapySDR::ConverterRegistry::ConverterFunction converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); + std::cout << "converting " << std::endl; converterFunction(devBuffer, soapyBuffer, numElems, 2); dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); - std::cout << std::endl << "try a registered unspecified priority conversion..." << std::endl; - priority = SoapySDR::ConverterRegistry::GENERIC; + std::cout << std::endl << "try a registered default priority conversion..." << std::endl; converterFunction = myConverter->getFunction(sourceFormat, targetFormat); - converterFunction(devBuffer, soapyBuffer, numElems, 2); + converterFunction(devBuffer, soapyBuffer, 8, 2); - dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); + dumpBuffer((uint8_t*)soapyBuffer, 8, targetFormat); - std::cout << std::endl << "try an unregistered conversion..." << std::endl; + sourceFormat = SOAPY_SDR_CS16; + targetFormat = SOAPY_SDR_CF32; + priority = SoapySDR::ConverterRegistry::CUSTOM; + + std::cout << std::endl << "try an unregistered CUSTOM conversion..." << std::endl; try{ - converterFunction = myConverter->getFunction(SOAPY_SDR_CU16, SOAPY_SDR_CS16, priority); - converterFunction(devBuffer, soapyBuffer, numElems, 0.1); + converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); + std::cout << " no exception. (not good)" << std::endl; } catch (const std::exception &ex){ std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; } - std::cout << "unregistering converters"; - while (!converters.empty()) - { - converters.rbegin()->remove(); - converters.pop_back(); - } - std::cout << std::endl; - + auto myCustomConverter = new SoapySDR::ConverterRegistry(sourceFormat, targetFormat, priority, (SoapySDR::ConverterRegistry::ConverterFunction) customCS16toCF32hs); + + std::cout << std::endl << "try a registered CUSTOM conversion..." << std::endl; + converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); + converterFunction(devBuffer, soapyBuffer, 8, 2); + dumpBuffer((uint8_t*)soapyBuffer, 8, targetFormat); + + std::cout << std::endl << "removing CUSTOM conversion..." << std::endl; + myCustomConverter->remove(); + delete(myCustomConverter); + std::cout << std::endl << "try a deleted CUSTOM conversion..." << std::endl; + try{ + converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); + std::cout << " no exception. (not good)" << std::endl; + } + catch (const std::exception &ex){ + std::cout << " got exception '" << ex.what() << "'. (thats good)" << std::endl; + } + std::cout << "DONE!" << std::endl; return EXIT_SUCCESS; } @@ -261,7 +215,7 @@ bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ float* buff = (float*)buffer; for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) { - if (i%16 == 0){ + if (i%16 == 0 and i!=0){ std::cout << std::endl << i << " > "; } std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; @@ -271,7 +225,7 @@ bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ int32_t* buff = (int32_t*)buffer; for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) { - if (i%16 == 0){ + if (i%16 == 0 and i!=0){ std::cout << std::endl << i << " > "; } std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; @@ -281,7 +235,7 @@ bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ int16_t* buff = (int16_t*)buffer; for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) { - if (i%16 == 0){ + if (i%16 == 0 and i!=0){ std::cout << std::endl << i << " > "; } std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; @@ -293,6 +247,5 @@ bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ } std::cout << std::endl; - return true; } From 59984e8b5848e6b1dfd6a712ee6ff6d7e84a6aaa Mon Sep 17 00:00:00 2001 From: Coburn Date: Fri, 22 Sep 2017 01:01:38 +0000 Subject: [PATCH 26/38] smartened up ConverterRegistry destructor --- convert/DefaultConverters.cpp | 1 - devel/TestFormatConvertClass.cpp | 16 ++++++++-- include/SoapySDR/ConverterRegistry.hpp | 33 ++++++++++---------- lib/ConverterRegistry.cpp | 42 +++++++++++++++++--------- 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/convert/DefaultConverters.cpp b/convert/DefaultConverters.cpp index 77d245ba..05e8fea4 100644 --- a/convert/DefaultConverters.cpp +++ b/convert/DefaultConverters.cpp @@ -88,7 +88,6 @@ SoapySDR::DefaultConverters::~DefaultConverters() std::cout << "unregistering " << SoapySDR::DefaultConverters::registry.size() << " default converters" << std::endl; while (!SoapySDR::DefaultConverters::registry.empty()) { - SoapySDR::DefaultConverters::registry.rbegin()->remove(); SoapySDR::DefaultConverters::registry.pop_back(); } } diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp index 473ee0ac..f7b65dd5 100644 --- a/devel/TestFormatConvertClass.cpp +++ b/devel/TestFormatConvertClass.cpp @@ -152,7 +152,11 @@ int main(void) std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; } + std::cout << std::endl << "register a CUSTOM conversion..." << std::endl; auto myCustomConverter = new SoapySDR::ConverterRegistry(sourceFormat, targetFormat, priority, (SoapySDR::ConverterRegistry::ConverterFunction) customCS16toCF32hs); + + dumpTargets(sourceFormat); + dumpSources(targetFormat); std::cout << std::endl << "try a registered CUSTOM conversion..." << std::endl; converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); @@ -160,7 +164,7 @@ int main(void) dumpBuffer((uint8_t*)soapyBuffer, 8, targetFormat); std::cout << std::endl << "removing CUSTOM conversion..." << std::endl; - myCustomConverter->remove(); + // myCustomConverter->remove(); delete(myCustomConverter); std::cout << std::endl << "try a deleted CUSTOM conversion..." << std::endl; try{ @@ -170,7 +174,15 @@ int main(void) catch (const std::exception &ex){ std::cout << " got exception '" << ex.what() << "'. (thats good)" << std::endl; } - + + std::cout << std::endl << "Unloading modules... " << std::endl << std::flush; + std::vector modules = SoapySDR::listModules(); + for (size_t i = 0; i < modules.size(); i++) + { + SoapySDR::unloadModule(modules[i]); + std::cout << "Module " << modules[i] << " unloaded." << std::endl; + } + std::cout << "DONE!" << std::endl; return EXIT_SUCCESS; } diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index 64091686..6c8184e6 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -38,10 +38,16 @@ namespace SoapySDR CUSTOM = 5 // custom user re-implementation, max priority }; + struct ConverterFunctionEntry{ + ConverterFunction function; + size_t usageCount; + }; + /*! * TargetFormatConverterPriority: a map of possible conversion functions for a given Priority. */ - typedef std::map TargetFormatConverterPriority; + //typedef std::map TargetFormatConverterPriority; + typedef std::map TargetFormatConverterPriority; /*! * TargetFormatConverters: a map of possible conversion functions for a given Target/Priority Format. @@ -64,27 +70,23 @@ namespace SoapySDR ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &, ConverterFunction); /*! - * Class constructor for using the Converter Registry. + * Object constructor for using the Converter Registry. * \param none no parameters */ ConverterRegistry(void); - ~ConverterRegistry(void); - /*! - * did the constructor for this instance register a function. - * \param none - * \return true if a function has been registered - */ - bool isRegistered(void); - - /*! - * Remove the converter registered by this object otherwise do nothing. - * \param none - * \return nothing + * copy constructor. + * \param none no parameters */ - void remove(void); + ConverterRegistry(const ConverterRegistry &); + /*! + * Object destructor. + * \param none no parameters + */ + ~ConverterRegistry(void); + /*! * Get a list of formats to which we can convert the source format into. * There is a registered conversion function from the specified source @@ -130,7 +132,6 @@ namespace SoapySDR FunctionPriority _priority; bool _isRegistered; - }; } diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index 60d80903..7dfaafbd 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: BSL-1.0 #include +#include SoapySDR::ConverterRegistry::FormatConverters SoapySDR::ConverterRegistry::formatConverters; @@ -13,13 +14,14 @@ SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, return; } - formatConverters[sourceFormat][targetFormat][priority] = converterFunction; - SoapySDR::log(SOAPY_SDR_NOTICE, "registered converter: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); + formatConverters[sourceFormat][targetFormat][priority].usageCount = 1; + formatConverters[sourceFormat][targetFormat][priority].function = converterFunction; + //SoapySDR::log(SOAPY_SDR_NOTICE, "registered converter: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); + _isRegistered = true; _sourceFormat = sourceFormat; _targetFormat = targetFormat; _priority = priority; - _isRegistered = true; return; } @@ -30,24 +32,34 @@ SoapySDR::ConverterRegistry::ConverterRegistry(void) return; } -SoapySDR::ConverterRegistry::~ConverterRegistry(void) +SoapySDR::ConverterRegistry::ConverterRegistry(const SoapySDR::ConverterRegistry &old) { + _sourceFormat = old._sourceFormat; + _targetFormat = old._targetFormat; + _priority = old._priority; + _isRegistered = old._isRegistered; + + if (_isRegistered) + ++formatConverters[_sourceFormat][_targetFormat][_priority].usageCount; + + //SoapySDR::log(SOAPY_SDR_NOTICE, "copied converter: " + _sourceFormat + " to " + _targetFormat + " priority " + std::to_string(_priority)); return; } -bool SoapySDR::ConverterRegistry::isRegistered(void) -{ - return _isRegistered; -} -void SoapySDR::ConverterRegistry::remove(void) +SoapySDR::ConverterRegistry::~ConverterRegistry(void) { - if (_isRegistered == true) + if (_isRegistered) { - formatConverters[_sourceFormat][_targetFormat].erase(_priority); - SoapySDR::log(SOAPY_SDR_NOTICE, "removed converter: " + _sourceFormat + " to " + _targetFormat + " priority " + std::to_string(_priority)); + --formatConverters[_sourceFormat][_targetFormat][_priority].usageCount; + //std::cout << "destructor usageCount = " << std::to_string(formatConverters[_sourceFormat][_targetFormat][_priority].usageCount) << std::endl; + if(formatConverters[_sourceFormat][_targetFormat][_priority].usageCount == 0) + { + formatConverters[_sourceFormat][_targetFormat].erase(_priority); + //SoapySDR::log(SOAPY_SDR_NOTICE, "deleted converter: " + _sourceFormat + " to " + _targetFormat + " priority " + std::to_string(_priority)); + } } - + return; } @@ -120,7 +132,7 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF throw std::invalid_argument("unsupported converter target format: " + targetFormat); } - return formatConverters[sourceFormat][targetFormat].rbegin()->second; + return formatConverters[sourceFormat][targetFormat].rbegin()->second.function; } SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getFunction(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority) @@ -143,5 +155,5 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF throw std::invalid_argument("unsupported converter target priority: " + std::to_string(priority)); } - return formatConverters[sourceFormat][targetFormat][priority]; + return formatConverters[sourceFormat][targetFormat][priority].function; } From d40ef1b77e25997e4bb47c3bfc6cab2287580e52 Mon Sep 17 00:00:00 2001 From: Coburn Date: Sat, 23 Sep 2017 01:58:42 +0000 Subject: [PATCH 27/38] fix odd double declaration and resultant need for a casting --- convert/DefaultConverters.cpp | 19 +++++++------------ convert/DefaultConverters.hpp | 21 +++++++++------------ devel/TestFormatConvertClass.cpp | 12 ++++++------ include/SoapySDR/ConverterRegistry.hpp | 12 ++++++++++-- lib/ConverterRegistry.cpp | 2 +- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/convert/DefaultConverters.cpp b/convert/DefaultConverters.cpp index 05e8fea4..8395520c 100644 --- a/convert/DefaultConverters.cpp +++ b/convert/DefaultConverters.cpp @@ -3,8 +3,7 @@ #include "DefaultConverters.hpp" - -SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +void SoapySDR::DefaultConverters::genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -29,10 +28,9 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::gene } std::cout << " sample copy with scaler" << std::endl; } - return 0; } -SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +void SoapySDR::DefaultConverters::genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -47,10 +45,9 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::gene } std::cout << " sample copy with scaler" << std::endl; - return 0; } -SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +void SoapySDR::DefaultConverters::genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -64,9 +61,7 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::DefaultConverters::gene //dst[i] = src[i] - 0x7fff) * scaler; CU16toCF32(src, dst, sf); } - std::cout << " sample copy with scaler" << std::endl; - - return 0; + std::cout << " sample copy with scaler" << std::endl; } std::vector SoapySDR::DefaultConverters::registry; @@ -78,9 +73,9 @@ SoapySDR::DefaultConverters::DefaultConverters(void) std::cout << "registering default converters" << std::endl; priority = SoapySDR::ConverterRegistry::GENERIC; - SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) SoapySDR::DefaultConverters::genericCF32toCF32); - SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) SoapySDR::DefaultConverters::genericCS16toCF32); - SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, (SoapySDR::ConverterRegistry::ConverterFunction) SoapySDR::DefaultConverters::genericCU16toCF32); + SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, SoapySDR::DefaultConverters::genericCF32toCF32); + SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, SoapySDR::DefaultConverters::genericCS16toCF32); + SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, SoapySDR::DefaultConverters::genericCU16toCF32); } SoapySDR::DefaultConverters::~DefaultConverters() diff --git a/convert/DefaultConverters.hpp b/convert/DefaultConverters.hpp index 2b316de1..5793b725 100644 --- a/convert/DefaultConverters.hpp +++ b/convert/DefaultConverters.hpp @@ -12,15 +12,13 @@ //#include #include "ConvertPrimatives.hpp" #include -#include #include -#include -#include #include //memcpy #include -#include #include -#include + +#include +#include namespace SoapySDR { @@ -31,13 +29,12 @@ namespace SoapySDR ~DefaultConverters(void); private: + static SoapySDR::ConverterRegistry::ConverterFunctionProto genericCF32toCF32; + // static void genericCF32toCF32(const void *, void *, const size_t, const double); + static void genericCS16toCF32(const void *, void *, const size_t, const double); + static void genericCU16toCF32(const void *, void *, const size_t, const double); - static SoapySDR::ConverterRegistry::ConverterFunction genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler); - static SoapySDR::ConverterRegistry::ConverterFunction genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler); - static SoapySDR::ConverterRegistry::ConverterFunction genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler); - - static std::vector registry; - + static std::vector registry; }; - + } diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp index f7b65dd5..7474db38 100644 --- a/devel/TestFormatConvertClass.cpp +++ b/devel/TestFormatConvertClass.cpp @@ -13,8 +13,9 @@ bool fillBuffer(uint8_t*, int, std::string); bool dumpBuffer(uint8_t*, int, std::string); -SoapySDR::ConverterRegistry::ConverterFunction customCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, - const double scaler) +//SoapySDR::ConverterRegistry::ConverterFunctionProto customCS16toCF32hs; + +void customCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -29,7 +30,7 @@ SoapySDR::ConverterRegistry::ConverterFunction customCS16toCF32hs(const void *sr } std::cout << " sample copy with scaler" << std::endl; - return 0; + // return 0; } void dumpTargets(std::string sourceFormat) @@ -153,7 +154,7 @@ int main(void) } std::cout << std::endl << "register a CUSTOM conversion..." << std::endl; - auto myCustomConverter = new SoapySDR::ConverterRegistry(sourceFormat, targetFormat, priority, (SoapySDR::ConverterRegistry::ConverterFunction) customCS16toCF32hs); + auto myCustomConverter = new SoapySDR::ConverterRegistry(sourceFormat, targetFormat, priority, customCS16toCF32hs); dumpTargets(sourceFormat); dumpSources(targetFormat); @@ -163,8 +164,7 @@ int main(void) converterFunction(devBuffer, soapyBuffer, 8, 2); dumpBuffer((uint8_t*)soapyBuffer, 8, targetFormat); - std::cout << std::endl << "removing CUSTOM conversion..." << std::endl; - // myCustomConverter->remove(); + std::cout << std::endl << "deleting CUSTOM conversion..." << std::endl; delete(myCustomConverter); std::cout << std::endl << "try a deleted CUSTOM conversion..." << std::endl; try{ diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index 6c8184e6..0176087d 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -23,12 +23,20 @@ namespace SoapySDR { public: /*! - * A typedef for a conversion function. + * A typedef to aid declaring a prototype of a conversion function. * A conversion function converts an input buffer into and output buffer. * The parameters are (input pointer, output pointer, number of elements, optional scalar) */ - typedef void (*ConverterFunction)(const void *, void *, const size_t, const double); + typedef void (ConverterFunctionProto)(const void *, void *, const size_t, const double); + /*! + * A typedef for a conversion function pointer. + * A conversion function converts an input buffer into and output buffer. + * The parameters are (input pointer, output pointer, number of elements, optional scalar) + */ + typedef void (*ConverterFunction)(const void *, void *, const size_t, const double); + //typedef void (*ConverterFunction)(ConverterFunctionProto); + /*! * FormatConverterPriority: allow selection of a converter function with a given source and target format */ diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index 7dfaafbd..139d6e7a 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BSL-1.0 #include -#include +//#include SoapySDR::ConverterRegistry::FormatConverters SoapySDR::ConverterRegistry::formatConverters; From 9c8a40433031cb7a96a1a797eedab030210185da Mon Sep 17 00:00:00 2001 From: Coburn Date: Mon, 25 Sep 2017 05:05:26 +0000 Subject: [PATCH 28/38] convert from module to built-in --- CMakeLists.txt | 1 - convert/CMakeLists.txt | 15 --- convert/DefaultConverters.cpp | 91 ------------------- convert/DefaultConverters.hpp | 40 -------- devel/TestFormatConvertClass.cpp | 4 +- .../SoapySDR/ConverterPrimatives.hpp | 0 include/SoapySDR/ConverterRegistry.hpp | 10 +- lib/CMakeLists.txt | 3 +- lib/DefaultConverters.cpp | 77 ++++++++++++++++ 9 files changed, 82 insertions(+), 159 deletions(-) delete mode 100644 convert/CMakeLists.txt delete mode 100644 convert/DefaultConverters.cpp delete mode 100644 convert/DefaultConverters.hpp rename convert/ConvertPrimatives.hpp => include/SoapySDR/ConverterPrimatives.hpp (100%) create mode 100644 lib/DefaultConverters.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e0c59f5..930053da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,6 @@ install(DIRECTORY include/SoapySDR DESTINATION include) ######################################################################## add_subdirectory(lib) add_subdirectory(apps) -add_subdirectory(convert) add_subdirectory(devel) add_subdirectory(tests) add_subdirectory(docs) diff --git a/convert/CMakeLists.txt b/convert/CMakeLists.txt deleted file mode 100644 index 8048e9d6..00000000 --- a/convert/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -######################################################################## -# Build the Converter Registry plugin module -######################################################################## -SOAPY_SDR_MODULE_UTIL( - TARGET converterRegistry - SOURCES - DefaultConverters.cpp - # Registration.cpp - # Settings.cpp - # Streaming.cpp - # LogAcceptor.cpp - # ClientStreamData.cpp - # LIBRARIES - # SoapySDRRemoteCommon -) diff --git a/convert/DefaultConverters.cpp b/convert/DefaultConverters.cpp deleted file mode 100644 index 8395520c..00000000 --- a/convert/DefaultConverters.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2017-2017 Coburn Wightman -// SPDX-License-Identifier: BSL-1.0 - -#include "DefaultConverters.hpp" - -void SoapySDR::DefaultConverters::genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CF32 to CF32" << std::endl; - - if (scaler == 1.0) - { - size_t elemSize = 4; - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); - std::cout << " straight memcpy" << std::endl; - } - else - { - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - float *src = (float*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - // dst[i] = src[i] * sf; - // dst[i+1] = src[i+1] * sf; - CF32toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - } -} - -void SoapySDR::DefaultConverters::genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CS16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - -} - -void SoapySDR::DefaultConverters::genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CU16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - uint16_t *src = (uint16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - //dst[i] = src[i] - 0x7fff) * scaler; - CU16toCF32(src, dst, sf); - } - std::cout << " sample copy with scaler" << std::endl; -} - -std::vector SoapySDR::DefaultConverters::registry; - -SoapySDR::DefaultConverters::DefaultConverters(void) -{ - SoapySDR::ConverterRegistry::FunctionPriority priority; - - std::cout << "registering default converters" << std::endl; - - priority = SoapySDR::ConverterRegistry::GENERIC; - SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CF32, SOAPY_SDR_CF32, priority, SoapySDR::DefaultConverters::genericCF32toCF32); - SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CS16, SOAPY_SDR_CF32, priority, SoapySDR::DefaultConverters::genericCS16toCF32); - SoapySDR::DefaultConverters::registry.emplace_back(SOAPY_SDR_CU16, SOAPY_SDR_CF32, priority, SoapySDR::DefaultConverters::genericCU16toCF32); -} - -SoapySDR::DefaultConverters::~DefaultConverters() -{ - std::cout << "unregistering " << SoapySDR::DefaultConverters::registry.size() << " default converters" << std::endl; - while (!SoapySDR::DefaultConverters::registry.empty()) - { - SoapySDR::DefaultConverters::registry.pop_back(); - } -} - -static SoapySDR::DefaultConverters* converterRegistry = new SoapySDR::DefaultConverters(); - diff --git a/convert/DefaultConverters.hpp b/convert/DefaultConverters.hpp deleted file mode 100644 index 5793b725..00000000 --- a/convert/DefaultConverters.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/// -/// \file converter/DefaultConverters.hpp -/// -/// Convert buffers between stream formats. -/// -/// \copyright -/// Copyright (c) 2017-2017 Coburn Wightman -/// SPDX-License-Identifier: BSL-1.0 -/// - -#pragma once -//#include -#include "ConvertPrimatives.hpp" -#include -#include -#include //memcpy -#include -#include - -#include -#include - -namespace SoapySDR -{ - class SOAPY_SDR_API DefaultConverters - { - public: - DefaultConverters(void); - ~DefaultConverters(void); - - private: - static SoapySDR::ConverterRegistry::ConverterFunctionProto genericCF32toCF32; - // static void genericCF32toCF32(const void *, void *, const size_t, const double); - static void genericCS16toCF32(const void *, void *, const size_t, const double); - static void genericCU16toCF32(const void *, void *, const size_t, const double); - - static std::vector registry; - }; - -} diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp index 7474db38..66c6f50d 100644 --- a/devel/TestFormatConvertClass.cpp +++ b/devel/TestFormatConvertClass.cpp @@ -1,11 +1,11 @@ // Copyright (c) 2017-2017 Coburn Wightman // SPDX-License-Identifier: BSL-1.0 -#include "../convert/ConvertPrimatives.hpp" #include #include #include #include +#include #include #include #include //memcpy @@ -111,7 +111,7 @@ int main(void) int32_t devBuffer[numElems * elemDepth]; int32_t soapyBuffer[numElems * elemDepth]; - int stat = printInfo(); + // int stat = printInfo(); auto myConverter = new SoapySDR::ConverterRegistry(); diff --git a/convert/ConvertPrimatives.hpp b/include/SoapySDR/ConverterPrimatives.hpp similarity index 100% rename from convert/ConvertPrimatives.hpp rename to include/SoapySDR/ConverterPrimatives.hpp diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index 0176087d..2fb77daf 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -22,20 +22,12 @@ namespace SoapySDR class SOAPY_SDR_API ConverterRegistry { public: - /*! - * A typedef to aid declaring a prototype of a conversion function. - * A conversion function converts an input buffer into and output buffer. - * The parameters are (input pointer, output pointer, number of elements, optional scalar) - */ - typedef void (ConverterFunctionProto)(const void *, void *, const size_t, const double); - /*! * A typedef for a conversion function pointer. - * A conversion function converts an input buffer into and output buffer. + * A conversion function converts an input buffer into an output buffer. * The parameters are (input pointer, output pointer, number of elements, optional scalar) */ typedef void (*ConverterFunction)(const void *, void *, const size_t, const double); - //typedef void (*ConverterFunction)(ConverterFunctionProto); /*! * FormatConverterPriority: allow selection of a converter function with a given source and target format diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index aff022c2..5c810fbd 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -21,8 +21,9 @@ list(APPEND SOAPY_SDR_SOURCES Logger.cpp Errors.cpp Formats.cpp - Convert.cpp +# Convert.cpp ConverterRegistry.cpp + DefaultConverters.cpp ) #dl libs used by dlopen in unix diff --git a/lib/DefaultConverters.cpp b/lib/DefaultConverters.cpp new file mode 100644 index 00000000..ea3be8ed --- /dev/null +++ b/lib/DefaultConverters.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2017-2017 Coburn Wightman +// SPDX-License-Identifier: BSL-1.0 + +#include +#include +#include +#include //memcpy +#include + +#include +#include + +void genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CF32 to CF32" << std::endl; + + if (scaler == 1.0) + { + size_t elemSize = 4; + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + std::cout << " straight memcpy" << std::endl; + } + else + { + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + float *src = (float*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + // dst[i] = src[i] * sf; + // dst[i+1] = src[i+1] * sf; + CF32toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + } +} + +void genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CS16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + int16_t *src = (int16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + CS16toCF32(&src[i], &dst[i], sf); + } + std::cout << " sample copy with scaler" << std::endl; + +} + +void genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + size_t elemDepth = 2; + + std::cout << "converting CU16 to CF32" << std::endl; + + float sf = float(1.0/scaler); + float *dst = (float*)dstBuff; + uint16_t *src = (uint16_t*)srcBuff; + for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + { + //dst[i] = src[i] - 0x7fff) * scaler; + CU16toCF32(src, dst, sf); + } + std::cout << " sample copy with scaler" << std::endl; +} + +static SoapySDR::ConverterRegistry registerGenericCF32toCF32(SOAPY_SDR_CF32, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCF32); +static SoapySDR::ConverterRegistry registerGenericCS16toCF32(SOAPY_SDR_CS16, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCS16toCF32); +static SoapySDR::ConverterRegistry registerGenericCU16toCF32(SOAPY_SDR_CU16, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCU16toCF32); + From ee872c0cf641090baa65fd2685d0224eb34bab14 Mon Sep 17 00:00:00 2001 From: Coburn Date: Tue, 26 Sep 2017 03:27:09 +0000 Subject: [PATCH 29/38] build test out of tree, delete devel folder. --- CMakeLists.txt | 1 - devel/BufferSim.cpp | 417 --------------------------- devel/CMakeLists.txt | 24 -- devel/TestFormatConvertClass.cpp | 263 ----------------- devel/TestFormatConvertFunctions.cpp | 269 ----------------- 5 files changed, 974 deletions(-) delete mode 100644 devel/BufferSim.cpp delete mode 100644 devel/CMakeLists.txt delete mode 100644 devel/TestFormatConvertClass.cpp delete mode 100644 devel/TestFormatConvertFunctions.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 930053da..246e5e12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,6 @@ install(DIRECTORY include/SoapySDR DESTINATION include) ######################################################################## add_subdirectory(lib) add_subdirectory(apps) -add_subdirectory(devel) add_subdirectory(tests) add_subdirectory(docs) diff --git a/devel/BufferSim.cpp b/devel/BufferSim.cpp deleted file mode 100644 index c9d00f27..00000000 --- a/devel/BufferSim.cpp +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright (c) 2017 Coburn Wightman -// SPDX-License-Identifier: BSL-1.0 - -//#include "buffer.hpp" -#include "convertPrimatives.hpp" -#include -//#include -#include -#include -#include -#include //memcpy - -bool fillBuffer(int8_t*, int, std::string); -bool dumpBuffer(int8_t*, int, std::string); -int readStream(void*, void * const *, const size_t); -int acquireReadBuffer(void *, size_t &, const void **); -void releaseReadBuffer(void *, const size_t); -std::string getNativeStreamFormat(const int, const size_t, double &); -std::vector getStreamFormats(const int, const size_t); -struct Stream *setupStream(const int, const std::string &, const std::vector &); - -SoapySDR::ConvertFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CF32 to CF32" << std::endl; - - if (scaler == 1.0) - { - size_t elemSize = 4; - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); - std::cout << " straight memcpy" << std::endl; - } - else - { - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - float *src = (float*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - // dst[i] = src[i] * sf; - // dst[i+1] = src[i+1] * sf; - CF32toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - } - return 0; -} - -SoapySDR::ConvertFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - // std::cout << "converting CS16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCF32(&src[i], &dst[i], sf); - } - // std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -SoapySDR::ConvertFunction cvtCS16toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - // std::cout << "converting CS16 to CS16" << std::endl; - - float sf = float(1.0/scaler); - int16_t *dst = (int16_t*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCS16(&src[i], &dst[i], sf); - } - // std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -SoapySDR::ConvertFunction cvtCS16toCS32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - // std::cout << "converting CS16 to CS32" << std::endl; - - float sf = float(1.0/scaler); - int32_t *dst = (int32_t*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCS32(&src[i], &dst[i], sf); - } - // std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -SoapySDR::ConvertFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CU16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - uint16_t *src = (uint16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - //dst[i] = src[i] - 0x7fff) * scaler; - CU16toCF32(src, dst, sf); - } - std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - - -struct Stream{ - size_t numChans; - // vector chanList; - - SoapySDR::ConvertFunction converter; - std::string streamElemFormat; - size_t streamElemWidth; - size_t streamElemDepth; - size_t streamElemSize; - - std::string nativeElemFormat; - size_t nativeElemWidth; - size_t nativeElemDepth; - size_t nativeElemSize; - - size_t fragmentRemaining; - size_t fragmentOffset; - size_t fragmentHandle; - const void *fragmentBuffs[8]; -}; - -struct CS16{ - int16_t i; - int16_t q; -}; - -struct CF32{ - float i; - float q; -}; - - -struct Stream _stream; - -int main(void) -{ - - std::cout << "registering converters..." << std::endl; - SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CS16, (SoapySDR::ConvertFunction) cvtCS16toCS16); - SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CS32, (SoapySDR::ConvertFunction) cvtCS16toCS32); - SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32); - - double fs; - std::string nativeFormat = getNativeStreamFormat(0,1,fs); - std::cout << "native format: " << nativeFormat << std::endl; - - std::cout << std::endl << "supported stream formats for " << nativeFormat << std::endl; - std::vector formats = SoapySDR::convertTargetFormats(nativeFormat); - for(std::vector::iterator it = formats.begin() ; it != formats.end(); ++it) - { - std::cout << " " << *it << std::endl; - } - - const size_t numElems = 100; //64 - std::vectorchannels; - - struct Stream* myStream = setupStream(0, SOAPY_SDR_CF32, channels ); - - struct CF32* buffs[8]; - struct CF32 buffer[myStream->numChans][numElems]; - - for (size_t chan = 0; chan < myStream->numChans; chan++){ - buffs[chan] = buffer[chan]; - } - - size_t elemCount = readStream((void *)myStream, (void**)buffs, numElems); - - for (size_t chan = 0; chan < myStream->numChans; chan++) - { - std::cout << "readStream() result: chan" << chan << " " << myStream->streamElemFormat << std::endl; - dumpBuffer((int8_t*)buffs[chan], elemCount, myStream->streamElemFormat); - } - - std::cout << "DONE!" << std::endl; - return EXIT_SUCCESS; -} - -/*! - * Query a list of the available stream formats. - * \param direction the channel direction RX or TX - * \param channel an available channel on the device - * \return a list of allowed format strings. See setupStream() for the format syntax. - */ -std::vector getStreamFormats(const int direction, const size_t channel) //const -{ - double fs; - - const std::string sourceFormat = getNativeStreamFormat(direction, channel, fs); - std::vector formats = SoapySDR::convertTargetFormats(sourceFormat); - - return formats; -} - -/*! - * Get the hardware's native stream format for this channel. - * This is the format used by the underlying transport layer, - * and the direct buffer access API calls (when available). - * \param direction the channel direction RX or TX - * \param channel an available channel on the device - * \param [out] fullScale the maximum possible value - * \return the native stream buffer format string - */ -std::string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) //const -{ - fullScale = 3.3/2; - return SOAPY_SDR_CS16; -} - -struct Stream *setupStream(const int direction, const std::string &format, const std::vector &channels) -{ - struct Stream* stream = &_stream; - double fs; - - stream->numChans = 8; - - stream->nativeElemFormat = getNativeStreamFormat(direction, 0, fs); - stream->nativeElemWidth = 2; //bytes - stream->nativeElemDepth = 2; //samples - stream->nativeElemSize = stream->nativeElemWidth * stream->nativeElemDepth; - - stream->streamElemFormat = format; - stream->streamElemWidth = 4; //bytes - stream->streamElemDepth = 2; //samples - stream->streamElemSize = stream->streamElemWidth * stream->streamElemDepth; - - stream->converter = SoapySDR::getConverter(stream->nativeElemFormat, stream->streamElemFormat); - - stream->fragmentRemaining = 0; - stream->fragmentOffset = 0; - // size_t fragmentHandle; - - return stream; -} - -/*! - * Read elements from a stream for reception. - * This is a multi-channel call, and buffs should be an array of void *, - * where each pointer will be filled with data from a different channel. - * - * **Client code compatibility:** - * The readStream() call should be well defined at all times, - * including prior to activation and after deactivation. - * When inactive, readStream() should implement the timeout - * specified by the caller and return SOAPY_SDR_TIMEOUT. - * - * \param stream the opaque pointer to a stream handle - * \param buffs an array of void* buffers num chans in size - * \param numElems the number of elements in each buffer - * \param flags optional flag indicators about the result - * \param timeNs the buffer's timestamp in nanoseconds - * \param timeoutUs the timeout in microseconds - * \return the number of elements read per buffer or error code - */ - -int readStream(void* stream, void * const *buffs, const size_t numElems) -{ - struct Stream* myStream = (struct Stream*)stream; - - size_t streamOffset = 0; - size_t bufferRemaining = numElems; - while (streamOffset < numElems) - { - if (myStream->fragmentRemaining == 0) - { - myStream->fragmentRemaining = acquireReadBuffer(stream, myStream->fragmentHandle, myStream->fragmentBuffs); - } - size_t elemCount = (bufferRemaining < myStream->fragmentRemaining) ? bufferRemaining : myStream->fragmentRemaining; - for (size_t chan = 0; chan < myStream->numChans; chan++) - { - int8_t* streamBuffer = (int8_t*) buffs[chan]; - int8_t* fragmentBuffer = (int8_t*) myStream->fragmentBuffs[chan]; - myStream->converter(&fragmentBuffer[myStream->fragmentOffset * myStream->nativeElemSize], - &streamBuffer[streamOffset * myStream->streamElemSize], elemCount, 1); - } - streamOffset += elemCount; - bufferRemaining -= elemCount; - - myStream->fragmentOffset += elemCount; - myStream->fragmentRemaining -= elemCount; - - std::cout << myStream->fragmentRemaining << std::endl; - if (myStream->fragmentRemaining == 0) - { - myStream->fragmentOffset = 0; - releaseReadBuffer(stream, myStream->fragmentHandle); - } - } - - return numElems; -} - -/*! - * Acquire direct buffers from a receive stream. - * This call is part of the direct buffer access API. - * - * The buffs array will be filled with a stream pointer for each channel. - * Each pointer can be read up to the number of return value elements. - * - * The handle will be set by the implementation so that the caller - * may later release access to the buffers with releaseReadBuffer(). - * Handle represents an index into the internal scatter/gather table - * such that handle is between 0 and num direct buffers - 1. - * - * \param stream the opaque pointer to a stream handle - * \param handle an index value used in the release() call - * \param buffs an array of void* buffers num chans in size - * \param flags optional flag indicators about the result - * \param timeNs the buffer's timestamp in nanoseconds - * \param timeoutUs the timeout in microseconds - * \return the number of elements read per buffer or error code - */ - -int acquireReadBuffer(void *stream, size_t &handle, const void **buffs) -{ - const size_t numElems = 12; //16 - const size_t numChans = 8; - static int cycleCount = 0; - - struct Stream* myStream = (struct Stream*)stream; - std::cout << "acquireReadBuffer(): " << myStream->nativeElemFormat << std::endl; - - // fabricate a dummy device buffer. - static struct CS16 devBuffer[numChans][numElems]; - for (size_t chan = 0; chan < numChans; chan++){ - for (size_t elem = 0; elem < numElems; elem++){ - devBuffer[chan][elem].i = cycleCount * 1000 + chan*100 + elem; - devBuffer[chan][elem].q = -(cycleCount * 1000 + chan*100 + elem); - } - buffs[chan] = devBuffer[chan]; - } - - ++cycleCount; - handle = 0; - - dumpBuffer((int8_t*)devBuffer, numChans*numElems, myStream->nativeElemFormat); - - return numElems; -} - - -/*! - * Release an acquired buffer back to the receive stream. - * This call is part of the direct buffer access API. - * - * \param stream the opaque pointer to a stream handle - * \param handle the opaque handle from the acquire() call - */ - -void releaseReadBuffer(void *stream, const size_t handle) -{ - struct Stream* myStream = (struct Stream*)stream; - std::cout << "releaseReadBuffer(): " << myStream->nativeElemFormat << std::endl; -} - -bool dumpBuffer(int8_t* buffer, int numElems, std::string elemFormat){ - size_t elemDepth = 2; - - if (elemFormat == SOAPY_SDR_CF32){ - float* buff = (float*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0) - std::cout << std::endl << i << " > "; - - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else if (elemFormat == SOAPY_SDR_CS32){ - int32_t* buff = (int32_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0) - std::cout << std::endl << i << " > "; - - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else if (elemFormat == SOAPY_SDR_CS16){ - int16_t* buff = (int16_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0) - std::cout << std::endl << i << " > "; - - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else - std::cout << "unrecognized elem format" << std::endl; - - std::cout << std::endl; - - return true; -} diff --git a/devel/CMakeLists.txt b/devel/CMakeLists.txt deleted file mode 100644 index 1e832923..00000000 --- a/devel/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -######################################################################## -## Feature registration -######################################################################## -#include(FeatureSummary) -#include(CMakeDependentOption) -#cmake_dependent_option(ENABLE_TESTS "Enable library unit tests" ON "ENABLE_LIBRARY" OFF) -#add_feature_info(Tests ENABLE_TESTS "library unit tests") -#if (NOT ENABLE_TESTS) -# return() -#endif() - -######################################################################## -# Unit tests -######################################################################## - -# add_executable(BufferSim BufferSim.cpp) -# target_compile_options(BufferSim PRIVATE -g) -# target_link_libraries(BufferSim SoapySDR) - -# add_executable(TestFormatConvertFunctions TestFormatConvertFunctions.cpp) -# target_link_libraries(TestFormatConvertFunctions SoapySDR) - -add_executable(TestFormatConvertClass TestFormatConvertClass.cpp) -target_link_libraries(TestFormatConvertClass SoapySDR) diff --git a/devel/TestFormatConvertClass.cpp b/devel/TestFormatConvertClass.cpp deleted file mode 100644 index 66c6f50d..00000000 --- a/devel/TestFormatConvertClass.cpp +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright (c) 2017-2017 Coburn Wightman -// SPDX-License-Identifier: BSL-1.0 - -#include -#include -#include -#include -#include -#include -#include -#include //memcpy - -bool fillBuffer(uint8_t*, int, std::string); -bool dumpBuffer(uint8_t*, int, std::string); - -//SoapySDR::ConverterRegistry::ConverterFunctionProto customCS16toCF32hs; - -void customCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CS16 to CF32 (hot shot)" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - - // return 0; -} - -void dumpTargets(std::string sourceFormat) -{ - auto myConverter = new SoapySDR::ConverterRegistry(); - std::cout << "get supported target formats for " << sourceFormat << std::endl; - std::vector targets = myConverter->listTargetFormats(sourceFormat); - for(const auto target:targets) - { - std::cout << " " << sourceFormat << " > " << target; - std::vector priorities = myConverter->listPriorities(sourceFormat, target); - for(const auto priority:priorities) - { - std::cout << " " << priority; - } - std::cout << std::endl; - } -} - -void dumpSources(std::string targetFormat) -{ - auto myConverter = new SoapySDR::ConverterRegistry(); - std::cout << "get supported source formats for " << targetFormat << std::endl; - std::vector sources = myConverter->listSourceFormats(targetFormat); - for(const auto source:sources) - { - std::cout << " " << source << " > " << targetFormat; - std::vector priorities = myConverter->listPriorities(source, targetFormat); - for(const auto priority:priorities) - { - std::cout << " " << priority; - } - std::cout << std::endl; - } - -} - -static int printInfo(void) -{ - std::cout << "API Version: v" << SoapySDR::getAPIVersion() << std::endl; - std::cout << "ABI Version: v" << SoapySDR::getABIVersion() << std::endl; - std::cout << "Install root: " << SoapySDR::getRootPath() << std::endl; - - std::vector modules = SoapySDR::listModules(); - for (size_t i = 0; i < modules.size(); i++) - { - std::cout << "Module found: " << modules[i] << std::endl; - } - if (modules.empty()) std::cout << "No modules found!" << std::endl; - - std::cout << "Loading modules... " << std::flush; - SoapySDR::loadModules(); - - // std::cout << "Unloading modules... " << std::flush; - // for (size_t i = 0; i < modules.size(); i++) - // { - // SoapySDR::unloadModule(modules[i]); - // std::cout << "Module " << modules[i] << " unloaded." << std::endl; - // } - - std::cout << "Available factories..."; - const SoapySDR::FindFunctions factories = SoapySDR::Registry::listFindFunctions(); - for (SoapySDR::FindFunctions::const_iterator it = factories.begin(); it != factories.end(); ++it) - { - std::cout << it->first << ", "; - } - if (factories.empty()) std::cout << "No factories found!" << std::endl; - else std::cout << std::endl; - - std::cout << std::endl; - return EXIT_SUCCESS; -} - -int main(void) -{ - const size_t numElems = 128; - const size_t elemDepth = 2; - int32_t devBuffer[numElems * elemDepth]; - int32_t soapyBuffer[numElems * elemDepth]; - - // int stat = printInfo(); - - auto myConverter = new SoapySDR::ConverterRegistry(); - - std::string sourceFormat = SOAPY_SDR_CS16; - std::string targetFormat = SOAPY_SDR_CF32; - SoapySDR::ConverterRegistry::FunctionPriority priority; - - dumpTargets(sourceFormat); - dumpSources(targetFormat); - - std::cout << std::endl << "creating bogus " << sourceFormat << " buffer." << std::endl; - fillBuffer((uint8_t*)devBuffer, numElems, sourceFormat); - dumpBuffer((uint8_t*)devBuffer, numElems, sourceFormat); - - std::cout << std::endl << "try a registered GENERIC priority conversion..." << std::endl; - priority = SoapySDR::ConverterRegistry::GENERIC; - SoapySDR::ConverterRegistry::ConverterFunction converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); - std::cout << "converting " << std::endl; - converterFunction(devBuffer, soapyBuffer, numElems, 2); - - dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); - - std::cout << std::endl << "try a registered default priority conversion..." << std::endl; - converterFunction = myConverter->getFunction(sourceFormat, targetFormat); - converterFunction(devBuffer, soapyBuffer, 8, 2); - - dumpBuffer((uint8_t*)soapyBuffer, 8, targetFormat); - - sourceFormat = SOAPY_SDR_CS16; - targetFormat = SOAPY_SDR_CF32; - priority = SoapySDR::ConverterRegistry::CUSTOM; - - std::cout << std::endl << "try an unregistered CUSTOM conversion..." << std::endl; - try{ - converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); - std::cout << " no exception. (not good)" << std::endl; - } - catch (const std::exception &ex){ - std::cout << " got exception '" << ex.what() << "' (thats good)" << std::endl; - } - - std::cout << std::endl << "register a CUSTOM conversion..." << std::endl; - auto myCustomConverter = new SoapySDR::ConverterRegistry(sourceFormat, targetFormat, priority, customCS16toCF32hs); - - dumpTargets(sourceFormat); - dumpSources(targetFormat); - - std::cout << std::endl << "try a registered CUSTOM conversion..." << std::endl; - converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); - converterFunction(devBuffer, soapyBuffer, 8, 2); - dumpBuffer((uint8_t*)soapyBuffer, 8, targetFormat); - - std::cout << std::endl << "deleting CUSTOM conversion..." << std::endl; - delete(myCustomConverter); - std::cout << std::endl << "try a deleted CUSTOM conversion..." << std::endl; - try{ - converterFunction = myConverter->getFunction(sourceFormat, targetFormat, priority); - std::cout << " no exception. (not good)" << std::endl; - } - catch (const std::exception &ex){ - std::cout << " got exception '" << ex.what() << "'. (thats good)" << std::endl; - } - - std::cout << std::endl << "Unloading modules... " << std::endl << std::flush; - std::vector modules = SoapySDR::listModules(); - for (size_t i = 0; i < modules.size(); i++) - { - SoapySDR::unloadModule(modules[i]); - std::cout << "Module " << modules[i] << " unloaded." << std::endl; - } - - std::cout << "DONE!" << std::endl; - return EXIT_SUCCESS; -} - -bool fillBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ - size_t elemDepth = 2; - - if (elemFormat == SOAPY_SDR_CF32){ - float* buff = (float*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = (float)i; - buff[i+1] = (float)i+1; - } - } - else if (elemFormat == SOAPY_SDR_CS32){ - int32_t* buff = (int32_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = i; - buff[i+1] = i+1; - } - } - else if (elemFormat == SOAPY_SDR_CS16){ - int16_t* buff = (int16_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = i; - buff[i+1] = i+1; - } - } - else - std::cout << "unrecognized elem format" << std::endl; - - return true; -} - -bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ - size_t elemDepth = 2; - - if (elemFormat == SOAPY_SDR_CF32){ - float* buff = (float*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0 and i!=0){ - std::cout << std::endl << i << " > "; - } - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else if (elemFormat == SOAPY_SDR_CS32){ - int32_t* buff = (int32_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0 and i!=0){ - std::cout << std::endl << i << " > "; - } - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else if (elemFormat == SOAPY_SDR_CS16){ - int16_t* buff = (int16_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0 and i!=0){ - std::cout << std::endl << i << " > "; - } - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else{ - std::cout << "unrecognized elem format" << std::endl; - return false; - } - - std::cout << std::endl; - return true; -} diff --git a/devel/TestFormatConvertFunctions.cpp b/devel/TestFormatConvertFunctions.cpp deleted file mode 100644 index c37dbb0d..00000000 --- a/devel/TestFormatConvertFunctions.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) 2017-2017 Coburn Wightman -// SPDX-License-Identifier: BSL-1.0 - -#include "convertPrimatives.hpp" -#include -#include -#include -#include //memcpy - -bool fillBuffer(uint8_t*, int, std::string); -bool dumpBuffer(uint8_t*, int, std::string); - - -SoapySDR::ConvertFunction cvtCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CF32 to CF32" << std::endl; - - if (scaler == 1.0) - { - size_t elemSize = 4; - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); - std::cout << " straight memcpy" << std::endl; - } - else - { - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - float *src = (float*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - // dst[i] = src[i] * sf; - // dst[i+1] = src[i+1] * sf; - CF32toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - } - return 0; -} - -SoapySDR::ConvertFunction cvtCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CS16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -SoapySDR::ConvertFunction cvtCS16toCF32hs(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CS16 to CF32 (hot shot)" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - CS16toCF32(&src[i], &dst[i], sf); - } - std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -SoapySDR::ConvertFunction cvtCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) -{ - size_t elemDepth = 2; - - std::cout << "converting CU16 to CF32" << std::endl; - - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - uint16_t *src = (uint16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - //dst[i] = src[i] - 0x7fff) * scaler; - CU16toCF32(src, dst, sf); - } - std::cout << " sample copy with scaler" << std::endl; - - return 0; -} - -// ****************************** - -int main(void) -{ - const size_t numElems = 128; - const size_t elemDepth = 2; - int32_t devBuffer[numElems * elemDepth]; - int32_t soapyBuffer[numElems * elemDepth]; - - SoapySDR::FormatConverterPriority priority; - - priority = SoapySDR::VECTORIZED; - std::cout << "registering priority " << std::to_string(priority) << " converters..." << std::endl; - SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32, priority); - SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32hs, priority); - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); - - try{ - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); - } - catch (const std::exception &ex){ - std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; - } - - priority = SoapySDR::GENERIC; - std::cout << "registering priority " << std::to_string(priority) << " converters..." << std::endl; - //SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32, priority); - SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32, priority); - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); - - priority = SoapySDR::CUSTOM; - std::cout << "registering priority " << std::to_string(priority) << " converters..." << std::endl; - SoapySDR::registerConverter(SOAPY_SDR_CF32, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCF32toCF32, priority); - //SoapySDR::registerConverter(SOAPY_SDR_CS16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCS16toCF32, priority); - SoapySDR::registerConverter(SOAPY_SDR_CU16, SOAPY_SDR_CF32, (SoapySDR::ConvertFunction) cvtCU16toCF32, priority); - - std::string sourceFormat = SOAPY_SDR_CS16; - std::string targetFormat = SOAPY_SDR_CF32; - - std::cout << std::endl << "get supported target formats for " << sourceFormat << std::endl; - std::vector targets = SoapySDR::convertTargetFormats(sourceFormat); - for(const auto target:targets) - { - std::cout << " " << target; - std::vector priorities = SoapySDR::getConverterPriorities(sourceFormat, target); - for(const auto priority:priorities) - { - std::cout << " " << priority; - } - std::cout << std::endl; - } - - std::cout << "get supported source formats for " << targetFormat << std::endl; - std::vector sources = SoapySDR::convertSourceFormats(targetFormat); - for(const auto source:sources) - { - std::cout << " " << source; - std::vector priorities = SoapySDR::getConverterPriorities(source, targetFormat); - for(const auto priority:priorities) - { - std::cout << " " << priority; - } - std::cout << std::endl; - } - - sourceFormat = SOAPY_SDR_CS16; - targetFormat = SOAPY_SDR_CF32; - - std::cout << std::endl << "creating bogus buffer." << std::endl; - fillBuffer((uint8_t*)devBuffer, numElems, sourceFormat); - dumpBuffer((uint8_t*)devBuffer, numElems, sourceFormat); - - std::cout << std::endl << "try a registered generic priority conversion..." << std::endl; - priority = SoapySDR::GENERIC; - SoapySDR::ConvertFunction convert; - convert = SoapySDR::getConverter(sourceFormat, targetFormat, priority); - convert(devBuffer, soapyBuffer, numElems, 2); - - std::cout << std::endl << "try a registered unspecified priority conversion..." << std::endl; - priority = SoapySDR::GENERIC; - convert = SoapySDR::getConverter(sourceFormat, targetFormat); - convert(devBuffer, soapyBuffer, numElems, 2); - - dumpBuffer((uint8_t*)soapyBuffer, numElems, targetFormat); - - std::cout << std::endl << "try an unregistered conversion..." << std::endl; - try{ - convert = SoapySDR::getConverter(SOAPY_SDR_CU16, SOAPY_SDR_CS16, priority); - convert(devBuffer, soapyBuffer, numElems, 0.1); - } - catch (const std::exception &ex){ - std::cout << " got error '" << ex.what() << "' (thats good)" << std::endl; - } - - std::cout << "DONE!" << std::endl; - return EXIT_SUCCESS; -} - -bool fillBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ - size_t elemDepth = 2; - - if (elemFormat == SOAPY_SDR_CF32){ - float* buff = (float*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = (float)i; - buff[i+1] = (float)i+1; - } - } - else if (elemFormat == SOAPY_SDR_CS32){ - int32_t* buff = (int32_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = i; - buff[i+1] = i+1; - } - } - else if (elemFormat == SOAPY_SDR_CS16){ - int16_t* buff = (int16_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - buff[i] = i; - buff[i+1] = i+1; - } - } - else - std::cout << "unrecognized elem format" << std::endl; - - return true; -} - -bool dumpBuffer(uint8_t* buffer, int numElems, std::string elemFormat){ - size_t elemDepth = 2; - - if (elemFormat == SOAPY_SDR_CF32){ - float* buff = (float*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0){ - std::cout << std::endl << i << " > "; - } - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else if (elemFormat == SOAPY_SDR_CS32){ - int32_t* buff = (int32_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0){ - std::cout << std::endl << i << " > "; - } - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else if (elemFormat == SOAPY_SDR_CS16){ - int16_t* buff = (int16_t*)buffer; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) - { - if (i%16 == 0){ - std::cout << std::endl << i << " > "; - } - std::cout << ' ' << buff[i] << ":" << buff[i+1] << ", "; - } - } - else{ - std::cout << "unrecognized elem format" << std::endl; - return false; - } - - std::cout << std::endl; - - return true; -} From 4337560ccd85d1c290e8bafe87e395aeb3b0d142 Mon Sep 17 00:00:00 2001 From: Coburn Date: Wed, 4 Oct 2017 17:08:08 +0000 Subject: [PATCH 30/38] convert to static member functions --- include/SoapySDR/ConverterRegistry.hpp | 34 +++------ lib/Convert.cpp | 57 +++++++-------- lib/ConverterRegistry.cpp | 98 +++++++++----------------- lib/DefaultConverters.cpp | 6 +- 4 files changed, 73 insertions(+), 122 deletions(-) diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index 2fb77daf..b7e45f7a 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -38,16 +38,11 @@ namespace SoapySDR CUSTOM = 5 // custom user re-implementation, max priority }; - struct ConverterFunctionEntry{ - ConverterFunction function; - size_t usageCount; - }; - /*! * TargetFormatConverterPriority: a map of possible conversion functions for a given Priority. */ //typedef std::map TargetFormatConverterPriority; - typedef std::map TargetFormatConverterPriority; + typedef std::map TargetFormatConverterPriority; /*! * TargetFormatConverters: a map of possible conversion functions for a given Target/Priority Format. @@ -69,18 +64,6 @@ namespace SoapySDR */ ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &, ConverterFunction); - /*! - * Object constructor for using the Converter Registry. - * \param none no parameters - */ - ConverterRegistry(void); - - /*! - * copy constructor. - * \param none no parameters - */ - ConverterRegistry(const ConverterRegistry &); - /*! * Object destructor. * \param none no parameters @@ -94,7 +77,7 @@ namespace SoapySDR * \param sourceFormat the source format markup string * \return a vector of target formats or an empty vector if none found */ - std::vector listTargetFormats(const std::string &sourceFormat); + static std::vector listTargetFormats(const std::string &sourceFormat); /*! * Get a list of formats to which we can convert the target format from. @@ -103,16 +86,15 @@ namespace SoapySDR * \param targetFormat the target format markup string * \return a vector of source formats or an empty vector if none found */ - std::vector listSourceFormats(const std::string &targetFormat); + static std::vector listSourceFormats(const std::string &targetFormat); /*! * Get a list of available converter priorities for a given source and target format. - * \throws invalid_argument when the conversion does not exist and logs error * \param sourceFormat the source format markup string * \param targetFormat the target format markup string - * \return a vector of priorities + * \return a vector of priorities or an empty vector if none found */ - std::vector listPriorities(const std::string &sourceFormat, const std::string &targetFormat); + static std::vector listPriorities(const std::string &sourceFormat, const std::string &targetFormat); /*! * Get a converter between a source and target format. @@ -121,17 +103,17 @@ namespace SoapySDR * \param targetFormat the target format markup string * \return a conversion function pointer */ - ConverterFunction getFunction(const std::string &sourceFormat, const std::string &targetFormat); - ConverterFunction getFunction(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority); + static ConverterFunction getFunction(const std::string &sourceFormat, const std::string &targetFormat); + static ConverterFunction getFunction(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority); private: static FormatConverters formatConverters; + bool _isRegistered; std::string _sourceFormat; std::string _targetFormat; FunctionPriority _priority; - bool _isRegistered; }; } diff --git a/lib/Convert.cpp b/lib/Convert.cpp index 46a15e17..6eec5c04 100644 --- a/lib/Convert.cpp +++ b/lib/Convert.cpp @@ -3,18 +3,17 @@ #include -SoapySDR::FormatConverters Converters; +SoapySDR::FormatConverters formatConverters; bool SoapySDR::registerConverter(const std::string &sourceFormat, const std::string &targetFormat, SoapySDR::ConvertFunction converterFunction, FormatConverterPriority &priority) { - if (Converters[sourceFormat][targetFormat].count(priority) == 0) + if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) { - Converters[sourceFormat][targetFormat][priority] = converterFunction; - } - else - { - throw std::invalid_argument("conversion already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority) + "."); + SoapySDR::log(SOAPY_SDR_ERROR, "converter already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); + return false; } + + formatConverters[sourceFormat][targetFormat][priority] = converterFunction; return true; } @@ -23,10 +22,10 @@ std::vector SoapySDR::convertTargetFormats(const std::string &sourc { std::vector targets; - if (Converters.count(sourceFormat) == 0) + if (formatConverters.count(sourceFormat) == 0) return targets; - for(const auto &it:Converters[sourceFormat]) + for(const auto &it:formatConverters[sourceFormat]) { std::string targetFormat = it.first; targets.push_back(targetFormat); @@ -39,10 +38,10 @@ std::vector SoapySDR::convertSourceFormats(const std::string &targe { std::vector sources; - for(const auto &it:Converters) + for(const auto &it:formatConverters) { std::string sourceFormat = it.first; - if (Converters[sourceFormat].count(targetFormat) > 0) + if (formatConverters[sourceFormat].count(targetFormat) > 0) sources.push_back(sourceFormat); } @@ -53,19 +52,17 @@ std::vector SoapySDR::getConverterPriorities( { std::vector priorities; - if (Converters.count(sourceFormat) == 0) - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); - - if (Converters[sourceFormat].count(targetFormat) == 0) - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - - // if (Converters[sourceFormat][targetFormat].size() == 0) - // throw std::invalid_argument("no registered functions for: " sourceFormat + " to "+ targetFormat + "."); - - for(const auto &it:Converters[sourceFormat][targetFormat]) + if (formatConverters.count(sourceFormat) == 0) + ; + else if (formatConverters[sourceFormat].count(targetFormat) == 0) + ; + else { - FormatConverterPriority priority = it.first; - priorities.push_back(priority); + for(const auto &it:formatConverters[sourceFormat][targetFormat]) + { + FormatConverterPriority priority = it.first; + priorities.push_back(priority); + } } return priorities; @@ -74,25 +71,25 @@ std::vector SoapySDR::getConverterPriorities( SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat, const std::string &targetFormat) { - if (Converters.count(sourceFormat) == 0) + if (formatConverters.count(sourceFormat) == 0) throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); - if (Converters[sourceFormat].count(targetFormat) == 0) + if (formatConverters[sourceFormat].count(targetFormat) == 0) throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - return Converters[sourceFormat][targetFormat].rbegin()->second; + return formatConverters[sourceFormat][targetFormat].rbegin()->second; } SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat, const std::string &targetFormat, FormatConverterPriority &priority) { - if (Converters.count(sourceFormat) == 0) + if (formatConverters.count(sourceFormat) == 0) throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); - if (Converters[sourceFormat].count(targetFormat) == 0) + if (formatConverters[sourceFormat].count(targetFormat) == 0) throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - if (Converters[sourceFormat][targetFormat].count(priority) == 0) + if (formatConverters[sourceFormat][targetFormat].count(priority) == 0) throw std::invalid_argument("unsupported target priority: " + std::to_string(priority) + "."); - return Converters[sourceFormat][targetFormat][priority]; + return formatConverters[sourceFormat][targetFormat][priority]; } diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index 139d6e7a..38e44ced 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -2,23 +2,26 @@ // SPDX-License-Identifier: BSL-1.0 #include -//#include SoapySDR::ConverterRegistry::FormatConverters SoapySDR::ConverterRegistry::formatConverters; SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority, ConverterFunction converterFunction) { - if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) + _isRegistered = false; + + if (formatConverters.count(sourceFormat) == 0) + ; + else if (formatConverters[sourceFormat].count(targetFormat) == 0) + ; + else if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "converter already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); + SoapySDR::logf(SOAPY_SDR_ERROR, "SoapySDR::ConverterRegistry(%s, %s, %s) duplicate registration", sourceFormat.c_str(), targetFormat.c_str(), std::to_string(priority).c_str()); return; } - formatConverters[sourceFormat][targetFormat][priority].usageCount = 1; - formatConverters[sourceFormat][targetFormat][priority].function = converterFunction; - //SoapySDR::log(SOAPY_SDR_NOTICE, "registered converter: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); - _isRegistered = true; + formatConverters[sourceFormat][targetFormat][priority] = converterFunction; + _isRegistered = true; _sourceFormat = sourceFormat; _targetFormat = targetFormat; _priority = priority; @@ -26,40 +29,11 @@ SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, return; } -SoapySDR::ConverterRegistry::ConverterRegistry(void) -{ - _isRegistered = false; - return; -} - -SoapySDR::ConverterRegistry::ConverterRegistry(const SoapySDR::ConverterRegistry &old) -{ - _sourceFormat = old._sourceFormat; - _targetFormat = old._targetFormat; - _priority = old._priority; - _isRegistered = old._isRegistered; - - if (_isRegistered) - ++formatConverters[_sourceFormat][_targetFormat][_priority].usageCount; - - //SoapySDR::log(SOAPY_SDR_NOTICE, "copied converter: " + _sourceFormat + " to " + _targetFormat + " priority " + std::to_string(_priority)); - return; -} - - SoapySDR::ConverterRegistry::~ConverterRegistry(void) { if (_isRegistered) - { - --formatConverters[_sourceFormat][_targetFormat][_priority].usageCount; - //std::cout << "destructor usageCount = " << std::to_string(formatConverters[_sourceFormat][_targetFormat][_priority].usageCount) << std::endl; - if(formatConverters[_sourceFormat][_targetFormat][_priority].usageCount == 0) - { - formatConverters[_sourceFormat][_targetFormat].erase(_priority); - //SoapySDR::log(SOAPY_SDR_NOTICE, "deleted converter: " + _sourceFormat + " to " + _targetFormat + " priority " + std::to_string(_priority)); - } - } - + formatConverters[_sourceFormat][_targetFormat].erase(_priority); + return; } @@ -98,21 +72,19 @@ std::vector SoapySDR::ConverterRe std::vector priorities; if (formatConverters.count(sourceFormat) == 0) - SoapySDR::log(SOAPY_SDR_WARNING, "unsupported converter source format: " + sourceFormat + " to " + targetFormat); - + ; else if (formatConverters[sourceFormat].count(targetFormat) == 0) - SoapySDR::log(SOAPY_SDR_WARNING, "unsupported converter target format: " + sourceFormat + " to " + targetFormat); - + ; else if (formatConverters[sourceFormat][targetFormat].size() == 0) - SoapySDR::log(SOAPY_SDR_ERROR, "no registered converter functions for: " + sourceFormat + " to " + targetFormat); - - else{ - for(const auto &it:formatConverters[sourceFormat][targetFormat]) - { - FunctionPriority priority = it.first; - priorities.push_back(priority); - } - } + ; + else + { + for(const auto &it:formatConverters[sourceFormat][targetFormat]) + { + FunctionPriority priority = it.first; + priorities.push_back(priority); + } + } return priorities; @@ -122,38 +94,38 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF { if (formatConverters.count(sourceFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter source format: " + sourceFormat); - throw std::invalid_argument("unsupported converter source format: " + sourceFormat); + throw std::invalid_argument("no registered converters for source format: " + sourceFormat); } if (formatConverters[sourceFormat].count(targetFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter target format: " + targetFormat); - throw std::invalid_argument("unsupported converter target format: " + targetFormat); + throw std::invalid_argument("no registered converters for target format: " + targetFormat); + } + + if (formatConverters[sourceFormat][targetFormat].size() == 0) + { + throw std::invalid_argument("no registered converters of any priority: " + targetFormat); } - return formatConverters[sourceFormat][targetFormat].rbegin()->second.function; + return formatConverters[sourceFormat][targetFormat].rbegin()->second; } SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getFunction(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority) { if (formatConverters.count(sourceFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter source format: " + sourceFormat); - throw std::invalid_argument("unsupported converter source format: " + sourceFormat); + throw std::invalid_argument("no registered converters for source format: " + sourceFormat); } if (formatConverters[sourceFormat].count(targetFormat) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter target format: " + targetFormat); - throw std::invalid_argument("unsupported converter target format: " + targetFormat); + throw std::invalid_argument("no registered converters for target format: " + targetFormat); } if (formatConverters[sourceFormat][targetFormat].count(priority) == 0) { - SoapySDR::log(SOAPY_SDR_ERROR, "unsupported converter target priority: " + std::to_string(priority)); - throw std::invalid_argument("unsupported converter target priority: " + std::to_string(priority)); + throw std::invalid_argument("no registered converters for target priority: " + std::to_string(priority)); } - return formatConverters[sourceFormat][targetFormat][priority].function; + return formatConverters[sourceFormat][targetFormat][priority]; } diff --git a/lib/DefaultConverters.cpp b/lib/DefaultConverters.cpp index ea3be8ed..e4927777 100644 --- a/lib/DefaultConverters.cpp +++ b/lib/DefaultConverters.cpp @@ -10,7 +10,7 @@ #include #include -void genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +static void genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -37,7 +37,7 @@ void genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems } } -void genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +static void genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; @@ -54,7 +54,7 @@ void genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems } -void genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +static void genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { size_t elemDepth = 2; From 0adfed06f67ba030aead5e03e53024f48bf8792d Mon Sep 17 00:00:00 2001 From: Coburn Date: Wed, 4 Oct 2017 17:29:24 +0000 Subject: [PATCH 31/38] remove Convert.*pp --- include/SoapySDR/Convert.hpp | 101 ----------------------------------- lib/Convert.cpp | 95 -------------------------------- 2 files changed, 196 deletions(-) delete mode 100644 include/SoapySDR/Convert.hpp delete mode 100644 lib/Convert.cpp diff --git a/include/SoapySDR/Convert.hpp b/include/SoapySDR/Convert.hpp deleted file mode 100644 index 82c7671a..00000000 --- a/include/SoapySDR/Convert.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/// -/// \file SoapySDR/Convert.hpp -/// -/// Convert buffers between stream formats. -/// -/// \copyright -/// Copyright (c) 2015-2015 Josh Blum -/// SPDX-License-Identifier: BSL-1.0 -/// - -#pragma once -#include -#include -#include -#include -#include - -namespace SoapySDR -{ -/*! - * A typedef for a conversion function. - * A conversion function converts an input buffer into and output buffer. - * The parameters are (input pointer, output pointer, number of elements, optional scalar) - */ -typedef void (*ConvertFunction)(const void *, void *, const size_t, const double); - -/*! - * FormatConverterPriority: allow selection of a converter function with a given source and target format - */ -enum FormatConverterPriority{ - GENERIC = 0, // usual C for loops and shifts and multiplies - VECTORIZED = 3, // using SIMD vectorized operations probably - CUSTOM = 5 // custom user re-implementation, max prio -}; - - -/*! - * TargetFormatConverterPriority: a map of possible conversion functions for a given priority. - */ -typedef std::map TargetFormatConverterPriority; - -/*! - * TargetFormatConverters: a map of possible conversion functions for a given Target Format. - */ -typedef std::map TargetFormatConverters; - -/*! - * FormatConverters: a map of possible conversion functions for a given Source Format. - */ -typedef std::map FormatConverters; - -/*! - * Get a list of formats to which we can convert the source format into. - * There is a registered conversion function from the specified source - * format to every target format returned in the result vector. - * \param sourceFormat the source format markup string - * \return a list of target formats - */ -SOAPY_SDR_API std::vector convertTargetFormats(const std::string &sourceFormat); - -/*! - * Get a list of formats to which we can convert the target format from. - * There is a registered conversion function from every source format - * returned in the result vector to the specified target format. - * \param targetFormat the target format markup string - * \return a list of source formats - */ -SOAPY_SDR_API std::vector convertSourceFormats(const std::string &targetFormat); - -/*! - * Register a converter between a source and target format. - * \throws invalid_argument if the conversion already exists - * \param sourceFormat the source format markup string - * \param targetFormat the target format markup string - * \param converter function to register - * \return true - */ -SOAPY_SDR_API bool registerConverter(const std::string &sourceFormat, const std::string &targetFormat, ConvertFunction, FormatConverterPriority &); - -/*! - * Get a list of available converter priorities for a given source and target format. - * \throws invalid_argument when the conversion does not exist - * \param sourceFormat the source format markup string - * \param targetFormat the target format markup string - * \return a vector of priorities - */ -SOAPY_SDR_API std::vector getConverterPriorities(const std::string &sourceFormat, const std::string &targetFormat); - -/*! - * Get a converter between a source and target format. - * \throws invalid_argument when the conversion does not exist - * \param sourceFormat the source format markup string - * \param targetFormat the target format markup string - * \param priority converter priority or highest if not specified - * \return a conversion function pointer - */ -SOAPY_SDR_API ConvertFunction getConverter(const std::string &sourceFormat, const std::string &targetFormat); - -SOAPY_SDR_API ConvertFunction getConverter(const std::string &sourceFormat, const std::string &targetFormat, FormatConverterPriority &priority); - -} diff --git a/lib/Convert.cpp b/lib/Convert.cpp deleted file mode 100644 index 6eec5c04..00000000 --- a/lib/Convert.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2017-2017 Coburn Wightman -// SPDX-License-Identifier: BSL-1.0 - -#include - -SoapySDR::FormatConverters formatConverters; - -bool SoapySDR::registerConverter(const std::string &sourceFormat, const std::string &targetFormat, SoapySDR::ConvertFunction converterFunction, FormatConverterPriority &priority) -{ - if (formatConverters[sourceFormat][targetFormat].count(priority) != 0) - { - SoapySDR::log(SOAPY_SDR_ERROR, "converter already registered: " + sourceFormat + " to " + targetFormat + " priority " + std::to_string(priority)); - return false; - } - - formatConverters[sourceFormat][targetFormat][priority] = converterFunction; - - return true; -} - -std::vector SoapySDR::convertTargetFormats(const std::string &sourceFormat) -{ - std::vector targets; - - if (formatConverters.count(sourceFormat) == 0) - return targets; - - for(const auto &it:formatConverters[sourceFormat]) - { - std::string targetFormat = it.first; - targets.push_back(targetFormat); - } - - return targets; -} - -std::vector SoapySDR::convertSourceFormats(const std::string &targetFormat) -{ - std::vector sources; - - for(const auto &it:formatConverters) - { - std::string sourceFormat = it.first; - if (formatConverters[sourceFormat].count(targetFormat) > 0) - sources.push_back(sourceFormat); - } - - return sources; -} - -std::vector SoapySDR::getConverterPriorities(const std::string &sourceFormat, const std::string &targetFormat) -{ - std::vector priorities; - - if (formatConverters.count(sourceFormat) == 0) - ; - else if (formatConverters[sourceFormat].count(targetFormat) == 0) - ; - else - { - for(const auto &it:formatConverters[sourceFormat][targetFormat]) - { - FormatConverterPriority priority = it.first; - priorities.push_back(priority); - } - } - - return priorities; - -} - -SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat, const std::string &targetFormat) -{ - if (formatConverters.count(sourceFormat) == 0) - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); - - if (formatConverters[sourceFormat].count(targetFormat) == 0) - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - - return formatConverters[sourceFormat][targetFormat].rbegin()->second; -} - -SoapySDR::ConvertFunction SoapySDR::getConverter(const std::string &sourceFormat, const std::string &targetFormat, FormatConverterPriority &priority) -{ - if (formatConverters.count(sourceFormat) == 0) - throw std::invalid_argument("unsupported source format: " + sourceFormat + "."); - - if (formatConverters[sourceFormat].count(targetFormat) == 0) - throw std::invalid_argument("unsupported target format: " + targetFormat + "."); - - if (formatConverters[sourceFormat][targetFormat].count(priority) == 0) - throw std::invalid_argument("unsupported target priority: " + std::to_string(priority) + "."); - - return formatConverters[sourceFormat][targetFormat][priority]; -} From 0a6fa0f3375ea76093a9a2d9fcdf892e95d3b076 Mon Sep 17 00:00:00 2001 From: Coburn Date: Sun, 8 Oct 2017 16:53:13 +0000 Subject: [PATCH 32/38] remove destructor --- include/SoapySDR/ConverterRegistry.hpp | 11 ----------- lib/ConverterRegistry.cpp | 15 --------------- 2 files changed, 26 deletions(-) diff --git a/include/SoapySDR/ConverterRegistry.hpp b/include/SoapySDR/ConverterRegistry.hpp index b7e45f7a..fc8ecd4f 100644 --- a/include/SoapySDR/ConverterRegistry.hpp +++ b/include/SoapySDR/ConverterRegistry.hpp @@ -64,12 +64,6 @@ namespace SoapySDR */ ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &, ConverterFunction); - /*! - * Object destructor. - * \param none no parameters - */ - ~ConverterRegistry(void); - /*! * Get a list of formats to which we can convert the source format into. * There is a registered conversion function from the specified source @@ -109,11 +103,6 @@ namespace SoapySDR private: static FormatConverters formatConverters; - bool _isRegistered; - std::string _sourceFormat; - std::string _targetFormat; - FunctionPriority _priority; - }; } diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index 38e44ced..12dfc799 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -7,8 +7,6 @@ SoapySDR::ConverterRegistry::FormatConverters SoapySDR::ConverterRegistry::forma SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, const std::string &targetFormat, const FunctionPriority &priority, ConverterFunction converterFunction) { - _isRegistered = false; - if (formatConverters.count(sourceFormat) == 0) ; else if (formatConverters[sourceFormat].count(targetFormat) == 0) @@ -21,19 +19,6 @@ SoapySDR::ConverterRegistry::ConverterRegistry(const std::string &sourceFormat, formatConverters[sourceFormat][targetFormat][priority] = converterFunction; - _isRegistered = true; - _sourceFormat = sourceFormat; - _targetFormat = targetFormat; - _priority = priority; - - return; -} - -SoapySDR::ConverterRegistry::~ConverterRegistry(void) -{ - if (_isRegistered) - formatConverters[_sourceFormat][_targetFormat].erase(_priority); - return; } From aa658bba71713a4d7af1ad4711ba6177b3ae05ac Mon Sep 17 00:00:00 2001 From: Coburn Date: Sat, 14 Oct 2017 20:37:03 +0000 Subject: [PATCH 33/38] flesh out converters --- include/SoapySDR/ConverterPrimatives.hpp | 202 +++++++------ lib/DefaultConverters.cpp | 363 +++++++++++++++++++++-- 2 files changed, 437 insertions(+), 128 deletions(-) diff --git a/include/SoapySDR/ConverterPrimatives.hpp b/include/SoapySDR/ConverterPrimatives.hpp index 4604d9d3..2c21d6e0 100644 --- a/include/SoapySDR/ConverterPrimatives.hpp +++ b/include/SoapySDR/ConverterPrimatives.hpp @@ -1,137 +1,145 @@ -// ConvertPrimatives.hpp -// Copyright (c) 2017-2017 Coburn Wightman" -// -// derived from SoapyRemote/client/ClientStreamData.cpp -// Copyright (c) 2015-2017 Josh Blum -// SPDX-License-Identifier: BSL-1.0 +/// +/// \file SoapySDR/ConverterPrimatives.hpp +/// +/// inline Soapy real Format Converter primatives. +/// +/// \copyright +/// Copyright (c) 2017-2017 Coburn Wightman +/// SPDX-License-Identifier: BSL-1.0 +/// #pragma once #include -// Simple Primatives +namespace SoapySDR +{ + +/*! + * Conversion primatives for converting real values between Soapy Formats. + * \param from a real value to convert from + * \return the converted value + */ -// integers +// type conversion: float <> signed ints -inline int32_t U32toS32(int32_t from){ - return (from - 0x7fffffff); +inline int32_t F32toS32(float from){ + return int32_t(from); +} +inline float S32toF32(int32_t from){ + return float(from); } -inline int32_t U24toS32(int32_t from){ - return (from - 0x007fffff); +inline int16_t F32toS16(float from){ + return int16_t(from); +} +inline float S16toF32(int16_t from){ + return float(from); } -inline int32_t U16toS32(int16_t from){ - return (from - 0x7fff); +inline int8_t F32toS8(float from){ + return int8_t(from); +} +inline float S8toF32(int8_t from){ + return float(from); } -inline int32_t U8toS32(int8_t from){ - return (from - 0x7f); + +// type conversion: unsigned <> signed ints + +inline int32_t U32toS32(uint32_t from){ + return int32_t(from - 0x7fffffff); } -inline int32_t S16toS32(int16_t from){ - return int32_t(from); +inline uint32_t S32toU32(int32_t from){ + return uint32_t(from + 0x7fffffff); } -inline int16_t S16toS16(int16_t from){ - return int16_t(from); +inline int16_t U16toS16(uint16_t from){ + return int16_t(from - 0x7fff); } +inline uint16_t S16toU16(int16_t from){ + return uint16_t(from + 0x7fff); +} -// floats -inline int32_t F32toS32(float from){ - return int32_t(from); +inline int8_t U8toS8(uint8_t from){ + return int8_t(from - 0x7f); } -inline float S16toF32(int16_t from){ - return float(from); +inline uint8_t S8toU8(int8_t from){ + return uint8_t(from + 0x7f); } -inline float U16toF32(int16_t from){ - return float(U16toS32(from)); +// size conversion: signed <> signed + +inline int16_t S32toS16(int32_t from){ + return int16_t(from >> 16); +} +inline int32_t S16toS32(int16_t from){ + return int32_t(from << 16); } -inline float F32toF32(float from){ - return float(from); +inline int8_t S16toS8(int16_t from){ + return int8_t(from >> 8); +} +inline int16_t S8toS16(int8_t from){ + return int16_t(from << 8); } -// Complex primatives - -/////////////////////////// -// case CONVERT_CF32_CS12: -/////////////////////////// -inline float* CS12toCF32(uint8_t* in, float* out, float scale){ - // float out[2]; - uint16_t part0 = uint16_t(*(in++)); - uint16_t part1 = uint16_t(*(in++)); - uint16_t part2 = uint16_t(*(in++)); - int16_t i = int16_t((part1 << 12) | (part0 << 4)); - int16_t q = int16_t((part2 << 8) | (part1 & 0xf0)); - out[0] = float(i)*scale; - out[1] = float(q)*scale; - return out; - } - -/////////////////////////// -// case CONVERT_CF32_CS16: -/////////////////////////// -inline float* CF32toCF32(float* in, float* out, float scale){ - //const float scale = float(1.0/scaleFactor); - // float out[2]; - - out[0] = F32toF32(in[0])*scale; - out[1] = F32toF32(in[1])*scale; - - return out; +// compound conversions + +// float <> unsigned (type and size) + +inline uint32_t F32toU32(float from){ + return S32toU32(F32toS32(from)); +} +inline float U32toF32(uint32_t from){ + return S32toF32(U32toS32(from)); } -/////////////////////////// -// case CONVERT_CF32_CS16: -/////////////////////////// -inline float* CS16toCF32(int16_t* in, float* out, float scale){ - //const float scale = float(1.0/scaleFactor); - // float out[2]; +inline uint16_t F32toU16(float from){ + return S16toU16(F32toS16(from)); +} +inline float U16toF32(uint16_t from){ + return S16toF32(U16toS16(from)); +} - out[0] = S16toF32(in[0])*scale; - out[1] = S16toF32(in[1])*scale; - - return out; +inline uint8_t F32toU8(float from){ + return S8toU8(F32toS8(from)); +} +inline float U8toF32(uint8_t from){ + return S8toF32(U8toS8(from)); } -/////////////////////////// -// case CONVERT_CF32_CU16: -/////////////////////////// -inline float* CU16toCF32(uint16_t* in, float* out, float scale){ - //const float scale = float(1.0/scaleFactor); - // float out[2]; +// signed <> unsigned (type and size) - out[0] = U16toF32(in[0])*scale; - out[1] = U16toF32(in[1])*scale; - - return out; +inline uint16_t S32toU16(int32_t from){ + return S16toU16(S32toS16(from)); +} +inline int32_t U16toS32(uint16_t from){ + return S16toS32(U16toS16(from)); } -/////////////////////////// -// case CONVERT_CS32_CS16: -/////////////////////////// -inline int32_t* CS16toCS32(int16_t* in, int32_t* out, float scale){ - //const float scale = float(1.0/scaleFactor); - // float out[2]; +inline uint8_t S32toU8(int32_t from){ + return S8toU8(S16toS8(S32toS16(from))); +} +inline int32_t U8toS32(uint8_t from){ + return S16toS32(S8toS16(U8toS8(from))); +} - out[0] = S16toS32(in[0])*scale; - out[1] = S16toS32(in[1])*scale; - - return out; +inline uint8_t S16toU8(int16_t from){ + return S8toU8(S16toS8(from)); +} +inline int16_t U8toS16(uint8_t from){ + return S8toS16(U8toS8(from)); +} + +inline int8_t U16toS8(uint16_t from){ + return S16toS8(U16toS16(from)); +} +inline uint16_t S8toU16(int8_t from){ + return S16toU16(S8toS16(from)); } -/////////////////////////// -// case CONVERT_CS16_CS16: -/////////////////////////// -inline int16_t* CS16toCS16(int16_t* in, int16_t* out, float scale){ - //const float scale = float(1.0/scaleFactor); - // float out[2]; - out[0] = S16toS16(in[0])*scale; - out[1] = S16toS16(in[1])*scale; - - return out; } diff --git a/lib/DefaultConverters.cpp b/lib/DefaultConverters.cpp index e4927777..226db4dc 100644 --- a/lib/DefaultConverters.cpp +++ b/lib/DefaultConverters.cpp @@ -1,77 +1,378 @@ // Copyright (c) 2017-2017 Coburn Wightman +// +// derived from SoapyRemote/client/ClientStreamData.cpp +// Copyright (c) 2015-2017 Josh Blum // SPDX-License-Identifier: BSL-1.0 #include #include #include #include //memcpy -#include #include -#include +// Copy Converters + +// CF32 <> CF32 static void genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { - size_t elemDepth = 2; + const size_t elemDepth = 2; std::cout << "converting CF32 to CF32" << std::endl; if (scaler == 1.0) { - size_t elemSize = 4; + const size_t elemSize = sizeof(float); std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); - std::cout << " straight memcpy" << std::endl; } else { - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - float *src = (float*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + auto *src = (float*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) { - // dst[i] = src[i] * sf; - // dst[i+1] = src[i+1] * sf; - CF32toCF32(&src[i], &dst[i], sf); + dst[i] = float(src[i]) * scaler; } - std::cout << " sample copy with scaler" << std::endl; + } +} + +static SoapySDR::ConverterRegistry registerGenericCF32toCF32(SOAPY_SDR_CF32, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCF32); + +// CS32 <> CS32 +static void genericCS32toCS32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS32 to CS32" << std::endl; + + if (scaler == 1.0) + { + const size_t elemSize = sizeof(int32_t); + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + } + else + { + auto *src = (int32_t*)srcBuff; + auto *dst = (int32_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = int32_t(src[i]) * scaler; + } + } +} + +static SoapySDR::ConverterRegistry registerGenericCS32toCS32(SOAPY_SDR_CS32, SOAPY_SDR_CS32, SoapySDR::ConverterRegistry::GENERIC, &genericCS32toCS32); + +// CS16 <> CS16 +static void genericCS16toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS16 to CS16" << std::endl; + + if (scaler == 1.0) + { + const size_t elemSize = sizeof(int16_t); + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + } + else + { + auto *src = (int16_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = int16_t(src[i]) * scaler; + } + } +} + +static SoapySDR::ConverterRegistry registerGenericCS16toCS16(SOAPY_SDR_CS16, SOAPY_SDR_CS16, SoapySDR::ConverterRegistry::GENERIC, &genericCS16toCS16); + +// CS8 <> CS8 +static void genericCS8toCS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS8 to CS8" << std::endl; + + if (scaler == 1.0) + { + const size_t elemSize = sizeof(int8_t); + std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + } + else + { + auto *src = (int8_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = int8_t(src[i]) * scaler; + } + } +} + +static SoapySDR::ConverterRegistry registerGenericCS8toCS8(SOAPY_SDR_CS8, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCS8); + + +// Type Converters + +// CF32 <> CS16 +static void genericCF32toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CF32 to CS16" << std::endl; + + auto *src = (float*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::F32toS16(src[i] * scaler); } } static void genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { - size_t elemDepth = 2; + const size_t elemDepth = 2; std::cout << "converting CS16 to CF32" << std::endl; - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - int16_t *src = (int16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + auto *src = (int16_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toF32(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCF32toCS16(SOAPY_SDR_CF32, SOAPY_SDR_CS16, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCS16); +static SoapySDR::ConverterRegistry registerGenericCS16toCF32(SOAPY_SDR_CS16, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCS16toCF32); + + +// CF32 <> CU16 +static void genericCF32toCU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CF32 to CU16" << std::endl; + + auto *src = (float*)srcBuff; + auto *dst = (uint16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) { - CS16toCF32(&src[i], &dst[i], sf); + dst[i] = SoapySDR::F32toU16(src[i] * scaler); } - std::cout << " sample copy with scaler" << std::endl; - } static void genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) { - size_t elemDepth = 2; + const size_t elemDepth = 2; std::cout << "converting CU16 to CF32" << std::endl; - float sf = float(1.0/scaler); - float *dst = (float*)dstBuff; - uint16_t *src = (uint16_t*)srcBuff; - for (size_t i = 0; i < numElems*elemDepth; i+=elemDepth) + auto *src = (uint16_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) { - //dst[i] = src[i] - 0x7fff) * scaler; - CU16toCF32(src, dst, sf); + dst[i] = SoapySDR::U16toF32(src[i]) * scaler; } - std::cout << " sample copy with scaler" << std::endl; } -static SoapySDR::ConverterRegistry registerGenericCF32toCF32(SOAPY_SDR_CF32, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCF32); -static SoapySDR::ConverterRegistry registerGenericCS16toCF32(SOAPY_SDR_CS16, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCS16toCF32); +static SoapySDR::ConverterRegistry registerGenericCF32toCU16(SOAPY_SDR_CF32, SOAPY_SDR_CU16, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCU16); static SoapySDR::ConverterRegistry registerGenericCU16toCF32(SOAPY_SDR_CU16, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCU16toCF32); + +// CF32 <> CS8 +static void genericCF32toCS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CF32 to CS8" << std::endl; + + auto *src = (float*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::F32toS8(src[i] * scaler); + } +} + +static void genericCS8toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS8 to CF32" << std::endl; + + auto *src = (int8_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toF32(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCF32toCS8(SOAPY_SDR_CF32, SOAPY_SDR_CU8, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCS8); +static SoapySDR::ConverterRegistry registerGenericCS8toCF32(SOAPY_SDR_CU8, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCF32); + + +// CF32 <> CU8 +static void genericCF32toCU8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CF32 to CU8" << std::endl; + + auto *src = (float*)srcBuff; + auto *dst = (uint8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::F32toU8(src[i] * scaler); + } +} + +static void genericCU8toCF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CU8 to CF32" << std::endl; + + auto *src = (uint8_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U8toF32(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCF32toCU8(SOAPY_SDR_CF32, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCU8); +static SoapySDR::ConverterRegistry registerGenericCU8toCF32(SOAPY_SDR_CS8, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCU8toCF32); + +// CS16 <> CU16 +static void genericCS16toCU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS16 to CU16" << std::endl; + + auto *src = (int16_t*)srcBuff; + auto *dst = (uint16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toU16(src[i] * scaler); + } +} + +static void genericCU16toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CU16 to CS16" << std::endl; + + auto *src = (uint16_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U16toS16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCS16toCU16(SOAPY_SDR_CS16, SOAPY_SDR_CU16, SoapySDR::ConverterRegistry::GENERIC, &genericCS16toCU16); +static SoapySDR::ConverterRegistry registerGenericCU16toCS16(SOAPY_SDR_CU16, SOAPY_SDR_CS16, SoapySDR::ConverterRegistry::GENERIC, &genericCU16toCS16); + + +// CS16 <> CS8 +static void genericCS16toCS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS16 to CS8" << std::endl; + + auto *src = (int16_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toS8(src[i] * scaler); + } +} + +static void genericCS8toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS8 to CS16" << std::endl; + + auto *src = (int8_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toS16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCS16toCS8(SOAPY_SDR_CS16, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCS16toCS8); +static SoapySDR::ConverterRegistry registerGenericCS8toCS16(SOAPY_SDR_CS8, SOAPY_SDR_CS16, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCS16); + +// CS16 <> CU8 +static void genericCS16toCU8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS16 to CU8" << std::endl; + + auto *src = (int16_t*)srcBuff; + auto *dst = (uint8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toU8(src[i] * scaler); + } +} + +static void genericCU8toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CU8 to CS16" << std::endl; + + auto *src = (uint8_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U8toS16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCS16toCU8(SOAPY_SDR_CS16, SOAPY_SDR_CU8, SoapySDR::ConverterRegistry::GENERIC, &genericCS16toCU8); +static SoapySDR::ConverterRegistry registerGenericCU8toCS16(SOAPY_SDR_CU8, SOAPY_SDR_CS16, SoapySDR::ConverterRegistry::GENERIC, &genericCU8toCS16); + +// CU16 <> CS8 +static void genericCU16toCS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CU16 to CS8" << std::endl; + + auto *src = (uint16_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U16toS8(src[i] * scaler); + } +} + +static void genericCS8toCU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + std::cout << "converting CS8 to CU16" << std::endl; + + auto *src = (int8_t*)srcBuff; + auto *dst = (uint16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toU16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCU16toCS8(SOAPY_SDR_CU16, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCU16toCS8); +static SoapySDR::ConverterRegistry registerGenericCS8toCU16(SOAPY_SDR_CS8, SOAPY_SDR_CU16, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCU16); + From 9c252bcba986bea2000053b4791550c021db0e4f Mon Sep 17 00:00:00 2001 From: Coburn Date: Mon, 16 Oct 2017 03:58:07 +0000 Subject: [PATCH 34/38] remove debug prints --- lib/DefaultConverters.cpp | 42 --------------------------------------- 1 file changed, 42 deletions(-) diff --git a/lib/DefaultConverters.cpp b/lib/DefaultConverters.cpp index 226db4dc..348e0dd4 100644 --- a/lib/DefaultConverters.cpp +++ b/lib/DefaultConverters.cpp @@ -9,8 +9,6 @@ #include #include //memcpy -#include - // Copy Converters // CF32 <> CF32 @@ -18,8 +16,6 @@ static void genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CF32 to CF32" << std::endl; - if (scaler == 1.0) { const size_t elemSize = sizeof(float); @@ -43,8 +39,6 @@ static void genericCS32toCS32(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CS32 to CS32" << std::endl; - if (scaler == 1.0) { const size_t elemSize = sizeof(int32_t); @@ -68,8 +62,6 @@ static void genericCS16toCS16(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CS16 to CS16" << std::endl; - if (scaler == 1.0) { const size_t elemSize = sizeof(int16_t); @@ -93,8 +85,6 @@ static void genericCS8toCS8(const void *srcBuff, void *dstBuff, const size_t num { const size_t elemDepth = 2; - std::cout << "converting CS8 to CS8" << std::endl; - if (scaler == 1.0) { const size_t elemSize = sizeof(int8_t); @@ -121,8 +111,6 @@ static void genericCF32toCS16(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CF32 to CS16" << std::endl; - auto *src = (float*)srcBuff; auto *dst = (int16_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -135,8 +123,6 @@ static void genericCS16toCF32(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CS16 to CF32" << std::endl; - auto *src = (int16_t*)srcBuff; auto *dst = (float*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -154,8 +140,6 @@ static void genericCF32toCU16(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CF32 to CU16" << std::endl; - auto *src = (float*)srcBuff; auto *dst = (uint16_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -168,8 +152,6 @@ static void genericCU16toCF32(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CU16 to CF32" << std::endl; - auto *src = (uint16_t*)srcBuff; auto *dst = (float*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -187,8 +169,6 @@ static void genericCF32toCS8(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CF32 to CS8" << std::endl; - auto *src = (float*)srcBuff; auto *dst = (int8_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -201,8 +181,6 @@ static void genericCS8toCF32(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CS8 to CF32" << std::endl; - auto *src = (int8_t*)srcBuff; auto *dst = (float*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -220,8 +198,6 @@ static void genericCF32toCU8(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CF32 to CU8" << std::endl; - auto *src = (float*)srcBuff; auto *dst = (uint8_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -234,8 +210,6 @@ static void genericCU8toCF32(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CU8 to CF32" << std::endl; - auto *src = (uint8_t*)srcBuff; auto *dst = (float*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -252,8 +226,6 @@ static void genericCS16toCU16(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CS16 to CU16" << std::endl; - auto *src = (int16_t*)srcBuff; auto *dst = (uint16_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -266,8 +238,6 @@ static void genericCU16toCS16(const void *srcBuff, void *dstBuff, const size_t n { const size_t elemDepth = 2; - std::cout << "converting CU16 to CS16" << std::endl; - auto *src = (uint16_t*)srcBuff; auto *dst = (int16_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -285,8 +255,6 @@ static void genericCS16toCS8(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CS16 to CS8" << std::endl; - auto *src = (int16_t*)srcBuff; auto *dst = (int8_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -299,8 +267,6 @@ static void genericCS8toCS16(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CS8 to CS16" << std::endl; - auto *src = (int8_t*)srcBuff; auto *dst = (int16_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -317,8 +283,6 @@ static void genericCS16toCU8(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CS16 to CU8" << std::endl; - auto *src = (int16_t*)srcBuff; auto *dst = (uint8_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -331,8 +295,6 @@ static void genericCU8toCS16(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CU8 to CS16" << std::endl; - auto *src = (uint8_t*)srcBuff; auto *dst = (int16_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -349,8 +311,6 @@ static void genericCU16toCS8(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CU16 to CS8" << std::endl; - auto *src = (uint16_t*)srcBuff; auto *dst = (int8_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) @@ -363,8 +323,6 @@ static void genericCS8toCU16(const void *srcBuff, void *dstBuff, const size_t nu { const size_t elemDepth = 2; - std::cout << "converting CS8 to CU16" << std::endl; - auto *src = (int8_t*)srcBuff; auto *dst = (uint16_t*)dstBuff; for (size_t i = 0; i < numElems*elemDepth; i++) From 2a9c10bbfd6a4a57422ea1d312ed418af5c6b777 Mon Sep 17 00:00:00 2001 From: Coburn Date: Wed, 18 Oct 2017 18:40:41 +0000 Subject: [PATCH 35/38] add real format converters --- lib/DefaultConverters.cpp | 348 +++++++++++++++++++++++++++++++++++++- 1 file changed, 340 insertions(+), 8 deletions(-) diff --git a/lib/DefaultConverters.cpp b/lib/DefaultConverters.cpp index 348e0dd4..44d221f0 100644 --- a/lib/DefaultConverters.cpp +++ b/lib/DefaultConverters.cpp @@ -9,6 +9,338 @@ #include #include //memcpy +// ******************************** +// Real Soapy Formats + +// Copy Converters + +// F32 <> F32 +static void genericF32toF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + if (scaler == 1.0) + { + const size_t sampleSize = sizeof(float); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); + } + else + { + auto *src = (float*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = float(src[i]) * scaler; + } + } +} + +static SoapySDR::ConverterRegistry registerGenericF32toF32(SOAPY_SDR_F32, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericF32toF32); + +// S32 <> S32 +static void genericS32toS32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + if (scaler == 1.0) + { + const size_t sampleSize = sizeof(int32_t); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); + } + else + { + auto *src = (int32_t*)srcBuff; + auto *dst = (int32_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = int32_t(src[i]) * scaler; + } + } +} + +static SoapySDR::ConverterRegistry registerGenericS32toS32(SOAPY_SDR_S32, SOAPY_SDR_S32, SoapySDR::ConverterRegistry::GENERIC, &genericS32toS32); + +// S16 <> S16 +static void genericS16toS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + if (scaler == 1.0) + { + const size_t sampleSize = sizeof(int16_t); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); + } + else + { + auto *src = (int16_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = int16_t(src[i]) * scaler; + } + } +} + +static SoapySDR::ConverterRegistry registerGenericS16toS16(SOAPY_SDR_S16, SOAPY_SDR_S16, SoapySDR::ConverterRegistry::GENERIC, &genericS16toS16); + +// S8 <> S8 +static void genericS8toS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + if (scaler == 1.0) + { + const size_t sampleSize = sizeof(int8_t); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); + } + else + { + auto *src = (int8_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = int8_t(src[i]) * scaler; + } + } +} + +static SoapySDR::ConverterRegistry registerGenericS8toS8(SOAPY_SDR_S8, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericS8toS8); + + +// Type Converters + +// F32 <> S16 +static void genericF32toS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (float*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::F32toS16(src[i] * scaler); + } +} + +static void genericS16toF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int16_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toF32(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericF32toS16(SOAPY_SDR_F32, SOAPY_SDR_S16, SoapySDR::ConverterRegistry::GENERIC, &genericF32toS16); +static SoapySDR::ConverterRegistry registerGenericS16toF32(SOAPY_SDR_S16, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericS16toF32); + + +// F32 <> U16 +static void genericF32toU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (float*)srcBuff; + auto *dst = (uint16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::F32toU16(src[i] * scaler); + } +} + +static void genericU16toF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (uint16_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U16toF32(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericF32toU16(SOAPY_SDR_F32, SOAPY_SDR_U16, SoapySDR::ConverterRegistry::GENERIC, &genericF32toU16); +static SoapySDR::ConverterRegistry registerGenericU16toF32(SOAPY_SDR_U16, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericU16toF32); + + +// F32 <> S8 +static void genericF32toS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (float*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::F32toS8(src[i] * scaler); + } +} + +static void genericS8toF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int8_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toF32(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericF32toS8(SOAPY_SDR_F32, SOAPY_SDR_U8, SoapySDR::ConverterRegistry::GENERIC, &genericF32toS8); +static SoapySDR::ConverterRegistry registerGenericS8toF32(SOAPY_SDR_U8, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericS8toF32); + + +// F32 <> U8 +static void genericF32toU8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (float*)srcBuff; + auto *dst = (uint8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::F32toU8(src[i] * scaler); + } +} + +static void genericU8toF32(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (uint8_t*)srcBuff; + auto *dst = (float*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U8toF32(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericF32toU8(SOAPY_SDR_F32, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericF32toU8); +static SoapySDR::ConverterRegistry registerGenericU8toF32(SOAPY_SDR_S8, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericU8toF32); + +// S16 <> U16 +static void genericS16toU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int16_t*)srcBuff; + auto *dst = (uint16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toU16(src[i] * scaler); + } +} + +static void genericU16toS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (uint16_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U16toS16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericS16toU16(SOAPY_SDR_S16, SOAPY_SDR_U16, SoapySDR::ConverterRegistry::GENERIC, &genericS16toU16); +static SoapySDR::ConverterRegistry registerGenericU16toS16(SOAPY_SDR_U16, SOAPY_SDR_S16, SoapySDR::ConverterRegistry::GENERIC, &genericU16toS16); + + +// S16 <> S8 +static void genericS16toS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int16_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toS8(src[i] * scaler); + } +} + +static void genericS8toS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int8_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toS16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericS16toS8(SOAPY_SDR_S16, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericS16toS8); +static SoapySDR::ConverterRegistry registerGenericS8toS16(SOAPY_SDR_S8, SOAPY_SDR_S16, SoapySDR::ConverterRegistry::GENERIC, &genericS8toS16); + +// S16 <> U8 +static void genericS16toU8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int16_t*)srcBuff; + auto *dst = (uint8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S16toU8(src[i] * scaler); + } +} + +static void genericU8toS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (uint8_t*)srcBuff; + auto *dst = (int16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U8toS16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericS16toU8(SOAPY_SDR_S16, SOAPY_SDR_U8, SoapySDR::ConverterRegistry::GENERIC, &genericS16toU8); +static SoapySDR::ConverterRegistry registerGenericU8toS16(SOAPY_SDR_U8, SOAPY_SDR_S16, SoapySDR::ConverterRegistry::GENERIC, &genericU8toS16); + +// U16 <> S8 +static void genericU16toS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (uint16_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U16toS8(src[i] * scaler); + } +} + +static void genericS8toU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int8_t*)srcBuff; + auto *dst = (uint16_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toU16(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericU16toS8(SOAPY_SDR_U16, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericU16toS8); +static SoapySDR::ConverterRegistry registerGenericS8toU16(SOAPY_SDR_S8, SOAPY_SDR_U16, SoapySDR::ConverterRegistry::GENERIC, &genericS8toU16); + + +// ******************************** +// Complex Data Types + // Copy Converters // CF32 <> CF32 @@ -18,8 +350,8 @@ static void genericCF32toCF32(const void *srcBuff, void *dstBuff, const size_t n if (scaler == 1.0) { - const size_t elemSize = sizeof(float); - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + const size_t sampleSize = sizeof(float); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); } else { @@ -41,8 +373,8 @@ static void genericCS32toCS32(const void *srcBuff, void *dstBuff, const size_t n if (scaler == 1.0) { - const size_t elemSize = sizeof(int32_t); - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + const size_t sampleSize = sizeof(int32_t); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); } else { @@ -64,8 +396,8 @@ static void genericCS16toCS16(const void *srcBuff, void *dstBuff, const size_t n if (scaler == 1.0) { - const size_t elemSize = sizeof(int16_t); - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + const size_t sampleSize = sizeof(int16_t); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); } else { @@ -87,8 +419,8 @@ static void genericCS8toCS8(const void *srcBuff, void *dstBuff, const size_t num if (scaler == 1.0) { - const size_t elemSize = sizeof(int8_t); - std::memcpy(dstBuff, srcBuff, numElems*elemSize*elemDepth); + const size_t sampleSize = sizeof(int8_t); + std::memcpy(dstBuff, srcBuff, numElems*elemDepth*sampleSize); } else { From 6f765a1d417134a8f5b8ba315ba9291d5df403bf Mon Sep 17 00:00:00 2001 From: Coburn Date: Thu, 19 Oct 2017 03:38:18 +0000 Subject: [PATCH 36/38] cleanup error messages --- lib/ConverterRegistry.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/ConverterRegistry.cpp b/lib/ConverterRegistry.cpp index 12dfc799..0aaffc9f 100644 --- a/lib/ConverterRegistry.cpp +++ b/lib/ConverterRegistry.cpp @@ -79,17 +79,20 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF { if (formatConverters.count(sourceFormat) == 0) { - throw std::invalid_argument("no registered converters for source format: " + sourceFormat); + throw std::runtime_error("ConverterRegistry::getFunction() conversion source not registered; " + "sourceFormat="+sourceFormat+", targetFormat="+targetFormat); } if (formatConverters[sourceFormat].count(targetFormat) == 0) { - throw std::invalid_argument("no registered converters for target format: " + targetFormat); + throw std::runtime_error("ConverterRegistry::getFunction() conversion target not registered; " + "sourceFormat="+sourceFormat+", targetFormat="+targetFormat); } if (formatConverters[sourceFormat][targetFormat].size() == 0) { - throw std::invalid_argument("no registered converters of any priority: " + targetFormat); + throw std::runtime_error("ConverterRegistry::getFunction() no functions found for registered conversion; " + "sourceFormat="+sourceFormat+", targetFormat="+targetFormat); } return formatConverters[sourceFormat][targetFormat].rbegin()->second; @@ -99,18 +102,21 @@ SoapySDR::ConverterRegistry::ConverterFunction SoapySDR::ConverterRegistry::getF { if (formatConverters.count(sourceFormat) == 0) { - throw std::invalid_argument("no registered converters for source format: " + sourceFormat); + throw std::runtime_error("ConverterRegistry::getFunction() conversion source not registered; " + "sourceFormat="+sourceFormat+", targetFormat="+targetFormat+", priority="+std::to_string(priority)); } - + if (formatConverters[sourceFormat].count(targetFormat) == 0) { - throw std::invalid_argument("no registered converters for target format: " + targetFormat); + throw std::runtime_error("ConverterRegistry::getFunction() conversion target not registered; " + "sourceFormat="+sourceFormat+", targetFormat="+targetFormat+", priority="+std::to_string(priority)); } - + if (formatConverters[sourceFormat][targetFormat].count(priority) == 0) { - throw std::invalid_argument("no registered converters for target priority: " + std::to_string(priority)); + throw std::runtime_error("ConverterRegistry::getFunction() conversion priority not registered; " + "sourceFormat="+sourceFormat+", targetFormat="+targetFormat+", priority="+std::to_string(priority)); } - + return formatConverters[sourceFormat][targetFormat][priority]; } From 1f56c6345ba0e607884b238ddb075f4575e70046 Mon Sep 17 00:00:00 2001 From: Coburn Date: Thu, 19 Oct 2017 05:29:45 +0000 Subject: [PATCH 37/38] add cs8/cu8 converters. fix cut and paste error. --- lib/DefaultConverters.cpp | 72 ++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/lib/DefaultConverters.cpp b/lib/DefaultConverters.cpp index 44d221f0..bc88d521 100644 --- a/lib/DefaultConverters.cpp +++ b/lib/DefaultConverters.cpp @@ -192,8 +192,8 @@ static void genericS8toF32(const void *srcBuff, void *dstBuff, const size_t numE } } -static SoapySDR::ConverterRegistry registerGenericF32toS8(SOAPY_SDR_F32, SOAPY_SDR_U8, SoapySDR::ConverterRegistry::GENERIC, &genericF32toS8); -static SoapySDR::ConverterRegistry registerGenericS8toF32(SOAPY_SDR_U8, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericS8toF32); +static SoapySDR::ConverterRegistry registerGenericF32toS8(SOAPY_SDR_F32, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericF32toS8); +static SoapySDR::ConverterRegistry registerGenericS8toF32(SOAPY_SDR_S8, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericS8toF32); // F32 <> U8 @@ -221,8 +221,8 @@ static void genericU8toF32(const void *srcBuff, void *dstBuff, const size_t numE } } -static SoapySDR::ConverterRegistry registerGenericF32toU8(SOAPY_SDR_F32, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericF32toU8); -static SoapySDR::ConverterRegistry registerGenericU8toF32(SOAPY_SDR_S8, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericU8toF32); +static SoapySDR::ConverterRegistry registerGenericF32toU8(SOAPY_SDR_F32, SOAPY_SDR_U8, SoapySDR::ConverterRegistry::GENERIC, &genericF32toU8); +static SoapySDR::ConverterRegistry registerGenericU8toF32(SOAPY_SDR_U8, SOAPY_SDR_F32, SoapySDR::ConverterRegistry::GENERIC, &genericU8toF32); // S16 <> U16 static void genericS16toU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) @@ -337,6 +337,34 @@ static void genericS8toU16(const void *srcBuff, void *dstBuff, const size_t numE static SoapySDR::ConverterRegistry registerGenericU16toS8(SOAPY_SDR_U16, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericU16toS8); static SoapySDR::ConverterRegistry registerGenericS8toU16(SOAPY_SDR_S8, SOAPY_SDR_U16, SoapySDR::ConverterRegistry::GENERIC, &genericS8toU16); +// S8 <> U8 +static void genericS8toU8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (int8_t*)srcBuff; + auto *dst = (uint8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toU8(src[i] * scaler); + } +} + +static void genericU8toS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 1; + + auto *src = (uint8_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U8toS8(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericS8toU8(SOAPY_SDR_S8, SOAPY_SDR_U8, SoapySDR::ConverterRegistry::GENERIC, &genericS8toU8); +static SoapySDR::ConverterRegistry registerGenericU8toS8(SOAPY_SDR_U8, SOAPY_SDR_S8, SoapySDR::ConverterRegistry::GENERIC, &genericU8toS8); + // ******************************** // Complex Data Types @@ -521,8 +549,8 @@ static void genericCS8toCF32(const void *srcBuff, void *dstBuff, const size_t nu } } -static SoapySDR::ConverterRegistry registerGenericCF32toCS8(SOAPY_SDR_CF32, SOAPY_SDR_CU8, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCS8); -static SoapySDR::ConverterRegistry registerGenericCS8toCF32(SOAPY_SDR_CU8, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCF32); +static SoapySDR::ConverterRegistry registerGenericCF32toCS8(SOAPY_SDR_CF32, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCS8); +static SoapySDR::ConverterRegistry registerGenericCS8toCF32(SOAPY_SDR_CS8, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCF32); // CF32 <> CU8 @@ -550,8 +578,8 @@ static void genericCU8toCF32(const void *srcBuff, void *dstBuff, const size_t nu } } -static SoapySDR::ConverterRegistry registerGenericCF32toCU8(SOAPY_SDR_CF32, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCU8); -static SoapySDR::ConverterRegistry registerGenericCU8toCF32(SOAPY_SDR_CS8, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCU8toCF32); +static SoapySDR::ConverterRegistry registerGenericCF32toCU8(SOAPY_SDR_CF32, SOAPY_SDR_CU8, SoapySDR::ConverterRegistry::GENERIC, &genericCF32toCU8); +static SoapySDR::ConverterRegistry registerGenericCU8toCF32(SOAPY_SDR_CU8, SOAPY_SDR_CF32, SoapySDR::ConverterRegistry::GENERIC, &genericCU8toCF32); // CS16 <> CU16 static void genericCS16toCU16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) @@ -666,3 +694,31 @@ static void genericCS8toCU16(const void *srcBuff, void *dstBuff, const size_t nu static SoapySDR::ConverterRegistry registerGenericCU16toCS8(SOAPY_SDR_CU16, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCU16toCS8); static SoapySDR::ConverterRegistry registerGenericCS8toCU16(SOAPY_SDR_CS8, SOAPY_SDR_CU16, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCU16); +// CS8 <> CU8 +static void genericCS8toCU8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + auto *src = (int8_t*)srcBuff; + auto *dst = (uint8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::S8toU8(src[i] * scaler); + } +} + +static void genericCU8toCS8(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler) +{ + const size_t elemDepth = 2; + + auto *src = (uint8_t*)srcBuff; + auto *dst = (int8_t*)dstBuff; + for (size_t i = 0; i < numElems*elemDepth; i++) + { + dst[i] = SoapySDR::U8toS8(src[i]) * scaler; + } +} + +static SoapySDR::ConverterRegistry registerGenericCS8toCU8(SOAPY_SDR_CS8, SOAPY_SDR_CU8, SoapySDR::ConverterRegistry::GENERIC, &genericCS8toCU8); +static SoapySDR::ConverterRegistry registerGenericCU8toCS8(SOAPY_SDR_CU8, SOAPY_SDR_CS8, SoapySDR::ConverterRegistry::GENERIC, &genericCU8toCS8); + From 2a66d827548f2a3fcc602c2de413234d2d7b16ec Mon Sep 17 00:00:00 2001 From: Coburn Date: Sun, 22 Oct 2017 03:09:28 +0000 Subject: [PATCH 38/38] scaled floats to +/-1.0. --- include/SoapySDR/ConverterPrimatives.hpp | 44 ++++++++++++++---------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/include/SoapySDR/ConverterPrimatives.hpp b/include/SoapySDR/ConverterPrimatives.hpp index 2c21d6e0..a31d3509 100644 --- a/include/SoapySDR/ConverterPrimatives.hpp +++ b/include/SoapySDR/ConverterPrimatives.hpp @@ -14,60 +14,68 @@ namespace SoapySDR { +const uint32_t U32_ZERO_OFFSET = uint32_t(1<<31); +const uint16_t U16_ZERO_OFFSET = uint16_t(1<<15); +const uint8_t U8_ZERO_OFFSET = uint8_t(1<<7); + +const uint32_t S32_FULL_SCALE = (U32_ZERO_OFFSET-1); +const uint16_t S16_FULL_SCALE = (U16_ZERO_OFFSET-1); +const uint8_t S8_FULL_SCALE = (U8_ZERO_OFFSET-1); + /*! * Conversion primatives for converting real values between Soapy Formats. - * \param from a real value to convert from + * \param from the value to convert from * \return the converted value */ -// type conversion: float <> signed ints +// type conversion: float <> signed integers inline int32_t F32toS32(float from){ - return int32_t(from); + return int32_t(from * S32_FULL_SCALE); } inline float S32toF32(int32_t from){ - return float(from); + return float(from) / S32_FULL_SCALE; } inline int16_t F32toS16(float from){ - return int16_t(from); + return int16_t(from * S16_FULL_SCALE); } inline float S16toF32(int16_t from){ - return float(from); + return float(from) / S16_FULL_SCALE; } inline int8_t F32toS8(float from){ - return int8_t(from); + return int8_t(from * S8_FULL_SCALE); } inline float S8toF32(int8_t from){ - return float(from); + return float(from) / S8_FULL_SCALE; } -// type conversion: unsigned <> signed ints +// type conversion: offset binary <> two's complement (signed) integers inline int32_t U32toS32(uint32_t from){ - return int32_t(from - 0x7fffffff); + return int32_t(from - U32_ZERO_OFFSET); } inline uint32_t S32toU32(int32_t from){ - return uint32_t(from + 0x7fffffff); + return uint32_t(from) + U32_ZERO_OFFSET; } inline int16_t U16toS16(uint16_t from){ - return int16_t(from - 0x7fff); + return int16_t(from - U16_ZERO_OFFSET); } inline uint16_t S16toU16(int16_t from){ - return uint16_t(from + 0x7fff); + return uint16_t(from) + U16_ZERO_OFFSET; } inline int8_t U8toS8(uint8_t from){ - return int8_t(from - 0x7f); + return int8_t(from - U8_ZERO_OFFSET); } inline uint8_t S8toU8(int8_t from){ - return uint8_t(from + 0x7f); + return uint8_t(from) + U8_ZERO_OFFSET; } // size conversion: signed <> signed @@ -134,12 +142,12 @@ inline int16_t U8toS16(uint8_t from){ return S8toS16(U8toS8(from)); } -inline int8_t U16toS8(uint16_t from){ - return S16toS8(U16toS16(from)); -} inline uint16_t S8toU16(int8_t from){ return S16toU16(S8toS16(from)); } +inline int8_t U16toS8(uint16_t from){ + return S16toS8(U16toS16(from)); +} }