From 6876e032ede0fa0b47febe1e3c517c39a28dae5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silva?= Date: Sat, 1 Jun 2024 20:58:09 +0100 Subject: [PATCH] soapy: Use std functions in LT7182S soapy: Check DDR3 init and calibration soapy: Use new ioctl numbers soapy: Start new DMA buffer management implementation soapy: Move utility functions soapy: Misc changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- software/soapy/src/DMAMemoryManager.cpp | 20 +++ software/soapy/src/LT7182S.cpp | 117 ++---------------- software/soapy/src/SoapyIcyRadio.cpp | 64 ++++++---- .../soapy/src/include/DMAMemoryManager.hpp | 25 ++++ software/soapy/src/include/LT7182S.hpp | 4 +- software/soapy/src/include/Utils.hpp | 100 +++++++-------- software/soapy/src/include/ioctl.hpp | 28 +++-- 7 files changed, 158 insertions(+), 200 deletions(-) create mode 100644 software/soapy/src/DMAMemoryManager.cpp create mode 100644 software/soapy/src/include/DMAMemoryManager.hpp diff --git a/software/soapy/src/DMAMemoryManager.cpp b/software/soapy/src/DMAMemoryManager.cpp new file mode 100644 index 00000000..dec56895 --- /dev/null +++ b/software/soapy/src/DMAMemoryManager.cpp @@ -0,0 +1,20 @@ +#include "DMAMemoryManager.hpp" + +DMAMemoryManager::DMAMemoryManager(int fd, AXIPCIe *axi_pcie) +{ + this->fd = fd; + this->axi_pcie = axi_pcie; +} +DMAMemoryManager::~DMAMemoryManager() +{ + this->deinit(); +} + +void DMAMemoryManager::init() +{ + +} +void DMAMemoryManager::deinit() +{ + +} \ No newline at end of file diff --git a/software/soapy/src/LT7182S.cpp b/software/soapy/src/LT7182S.cpp index 39dc6f6c..e9bb3360 100644 --- a/software/soapy/src/LT7182S.cpp +++ b/software/soapy/src/LT7182S.cpp @@ -8,100 +8,6 @@ static const float EAmp_GM_LUT[2][8] = { {150.f, 300.f, 450.f, 600.f, 750.f, 900.f, 1050.f, 1200.f} // Low VOUT Mode }; -float LT7182S::Pow2(int8_t e) -{ - switch(e) - { - case -16: - return 0.0000152587890625f; - case -15: - return 0.000030517578125f; - case -14: - return 0.00006103515625f; - case -13: - return 0.0001220703125f; - case -12: - return 0.000244140625f; - case -11: - return 0.00048828125f; - case -10: - return 0.0009765625f; - case -9: - return 0.001953125f; - case -8: - return 0.00390625f; - case -7: - return 0.0078125f; - case -6: - return 0.015625f; - case -5: - return 0.03125f; - case -4: - return 0.0625f; - case -3: - return 0.125f; - case -2: - return 0.25f; - case -1: - return 0.5f; - case 0: - return 1.f; - case 1: - return 2.f; - case 2: - return 4.f; - case 3: - return 8.f; - case 4: - return 16.f; - case 5: - return 32.f; - case 6: - return 64.f; - case 7: - return 128.f; - case 8: - return 256.f; - case 9: - return 512.f; - case 10: - return 1024.f; - case 11: - return 2048.f; - case 12: - return 4096.f; - case 13: - return 8192.f; - case 14: - return 16384.f; - case 15: - return 32768.f; - } - - return 0.f; -} -uint8_t LT7182S::FindClosest(float val, const float *arr, uint8_t size) -{ - if(arr == nullptr || size == 0) - throw std::runtime_error("LT7182S: Invalid array"); - - uint8_t idx = 0; - float diff = ABS(val - arr[0]); - - for(uint8_t i = 1; i < size; i++) - { - float _diff = ABS(val - arr[i]); - - if(_diff < diff) - { - idx = i; - diff = _diff; - } - } - - return idx; -} - void LT7182S::ISR(void *_this) { if(_this == nullptr) @@ -166,7 +72,7 @@ void LT7182S::writeDWord(uint8_t cmd, uint32_t data) void LT7182S::writeL11(uint8_t cmd, float data) { int8_t exp = -16; - int32_t mant = (int32_t)(data / LT7182S::Pow2(exp)); + int32_t mant = (int32_t)(data / std::pow(2.f, exp)); // Search for an exponent that produces valid 11-bit mantissa do @@ -174,19 +80,14 @@ void LT7182S::writeL11(uint8_t cmd, float data) if(mant >= -1024 && mant <= 1023) break; - mant = (int32_t)(data / LT7182S::Pow2(++exp)); + exp++; + mant = (int32_t)(data / (exp >= 0 ? (1 << exp) : std::pow(2.f, exp))); } while(exp < 15); if(mant < -1024 || mant > 1023) throw std::runtime_error("LT7182S: Invalid L11 mantissa"); - if(exp < -16 || exp > 15) - throw std::runtime_error("LT7182S: Invalid L11 exponent"); - - uint16_t exp16 = exp << 11; - uint16_t mant16 = mant & 0x07FF; - - this->writeWord(cmd, exp16 | mant16); + this->writeWord(cmd, ((uint16_t)exp << 11) | (mant & 0x07FF)); } void LT7182S::writeUL16(uint8_t cmd, float data) { @@ -259,7 +160,7 @@ float LT7182S::readL11(uint8_t cmd) if(data & BIT(10)) mant = -1 * (mant ^ 0x7FF) - 1; - return (float)mant * LT7182S::Pow2(exp); + return (float)mant * (exp >= 0 ? (1 << exp) : std::pow(2.f, exp)); } float LT7182S::readUL16(uint8_t cmd) { @@ -793,11 +694,11 @@ void LT7182S::setChannelPWMConfig(LT7182S::ChanPWMConfig config, LT7182S::Chan c if(config.fcm_at_toff) reg |= BIT(2); - reg |= (LT7182S::FindClosest(config.rith, R_ITH_LUT, 8) << 3) & 0x0038; + reg |= (Utils::FindClosestIndex(R_ITH_LUT, 8, config.rith) << 3) & 0x0038; reg |= (((uint8_t)(config.cith / 10.f) - 1) << 6) & 0x01C0; - reg |= (LT7182S::FindClosest(config.neg_ilim, Neg_ILim_LUT, 4) << 9) & 0x0600; - reg |= (LT7182S::FindClosest(config.pos_ilim, Pos_ILim_LUT, 4) << 9) & 0x0600; - reg |= (LT7182S::FindClosest(config.ea_gm, EAmp_GM_LUT[config.low_vout_mode ? 1 : 0], 8) << 11) & 0x3800; + reg |= (Utils::FindClosestIndex(Neg_ILim_LUT, 4, config.neg_ilim) << 9) & 0x0600; + reg |= (Utils::FindClosestIndex(Pos_ILim_LUT, 4, config.pos_ilim) << 9) & 0x0600; + reg |= (Utils::FindClosestIndex(EAmp_GM_LUT[config.low_vout_mode ? 1 : 0], 8, config.ea_gm) << 11) & 0x3800; std::lock_guard lock(this->mutex); diff --git a/software/soapy/src/SoapyIcyRadio.cpp b/software/soapy/src/SoapyIcyRadio.cpp index 5225c928..4512f22e 100644 --- a/software/soapy/src/SoapyIcyRadio.cpp +++ b/software/soapy/src/SoapyIcyRadio.cpp @@ -160,19 +160,23 @@ void SoapyIcyRadio::setupMemoryMaps() this->axi_ad9361 = new AXIAD9361(this->mm_axi_periph->getVirt(AXI_AD9361_BASE)); // Allocate DMA buffer memory - uint32_t dma_sz = ICYRADIO_DEFAULT_TOTAL_DMA_POOL_SIZE_BYTES; // TODO: make this configurable + icyradio_ioctl_dma_buffer_t arg = { + .ullPhysAddr = 0, + .ulSize = ICYRADIO_DEFAULT_TOTAL_DMA_POOL_SIZE_BYTES // TODO: make this configurable + }; - DLOGF(SOAPY_SDR_DEBUG, "Allocating DMA buffer pool of %u bytes", dma_sz); + DLOGF(SOAPY_SDR_DEBUG, "Allocating DMA buffer pool of %u bytes", arg.ulSize); - uint64_t arg = dma_sz; - - ioctl(this->fd, ICYRADIO_IOCTL_DMA_FREE); // TODO: Implement getting an existing buffer + ioctl(this->fd, ICYRADIO_IOCTL_DMA_FREE_ALL); // TODO: Implement getting an existing buffer if(ioctl(this->fd, ICYRADIO_IOCTL_DMA_ALLOC, &arg) < 0) throw std::runtime_error("Could not allocate DMA buffer memory (" + std::string(std::strerror(errno)) + ")"); + if(arg.ulSize != ICYRADIO_DEFAULT_TOTAL_DMA_POOL_SIZE_BYTES) + DLOGF(SOAPY_SDR_WARNING, "Requested DMA buffer of length %u bytes, actually got %u bytes!", ICYRADIO_DEFAULT_TOTAL_DMA_POOL_SIZE_BYTES, arg.ulSize); + // Map DMA buffer memory - this->mm_dma_buffer = new MappedRegion(this->fd, arg | BIT(48), dma_sz); + this->mm_dma_buffer = new MappedRegion(this->fd, arg.ullPhysAddr | BIT(48), arg.ulSize); DLOGF(SOAPY_SDR_TRACE, "DMA Buffer: Phys = %016llX, Virt = %016llX, Size = %016llX", this->mm_dma_buffer->getPhys() & (BIT(48) - 1), this->mm_dma_buffer->getVirt(), this->mm_dma_buffer->getSize()); } @@ -311,7 +315,7 @@ void SoapyIcyRadio::freeMemoryMaps() this->mm_dma_buffer = nullptr; } - ioctl(this->fd, ICYRADIO_IOCTL_DMA_FREE); + ioctl(this->fd, ICYRADIO_IOCTL_DMA_FREE_ALL); } void SoapyIcyRadio::initPeripheralsPreClocks() @@ -1123,7 +1127,7 @@ void SoapyIcyRadio::initPeripheralsPostClocks() this->mmw_synth->setLockDetectPrecision(IDT8V97003::LDPrecision::LD_PREC_1p0ns); this->mmw_synth->configReferenceInput(this->clk_mngr->getClockFrequency(Si5351::ClockOutput::CLK_SYNTH_REF_CLK), false); - this->mmw_synth->configPFD(250000000UL, IDT8V97003::PFDPulseWidth::PFD_PW_260ps); + this->mmw_synth->configPFD(250e6, IDT8V97003::PFDPulseWidth::PFD_PW_260ps); this->mmw_synth->setLoopFilter( { @@ -1143,7 +1147,7 @@ void SoapyIcyRadio::initPeripheralsPostClocks() this->mmw_synth->setRFOutputPower(IDT8V97003::RFOutput::RFOUT_A, 12); this->mmw_synth->setRFOutputPower(IDT8V97003::RFOutput::RFOUT_B, 12); - // this->mmw_synth->setFrequency(6000000000ULL); // 8 GHz + this->mmw_synth->setFrequency(8e9); // 8 GHz { DLOGF(SOAPY_SDR_DEBUG, "mmWave Synth:"); @@ -1179,16 +1183,16 @@ void SoapyIcyRadio::initPeripheralsPostClocks() DLOGF(SOAPY_SDR_TRACE, " Phase Margin: %.3f deg", lfr.phase_margin); DLOGF(SOAPY_SDR_TRACE, " Target Loop Bandwidth: %.3f kHz", this->mmw_synth->getTargetLoopBandwidth() * 1e-3); - // DLOGF(SOAPY_SDR_DEBUG, " VCO Frequency: %.6f MHz", this->mmw_synth->getVCOFrequency() * 1e-6); - // DLOGF(SOAPY_SDR_DEBUG, " Output Frequency: %.6f MHz", this->mmw_synth->getFrequency() * 1e-6); + DLOGF(SOAPY_SDR_DEBUG, " VCO Frequency: %.6f MHz", this->mmw_synth->getVCOFrequency() * 1e-6); + DLOGF(SOAPY_SDR_DEBUG, " Output Frequency: %.6f MHz", this->mmw_synth->getFrequency() * 1e-6); - // double dist = 0; - // bool frac = this->mmw_synth->isFeedbackDividerFractional(dist); + double dist = 0; + bool frac = this->mmw_synth->isFeedbackDividerFractional(dist); - // if(frac) - // DLOGF(SOAPY_SDR_DEBUG, " Distance to integer boundary: %.6f %%", dist * 100); - // else - // DLOGF(SOAPY_SDR_DEBUG, " PLL in integer mode"); + if(frac) + DLOGF(SOAPY_SDR_DEBUG, " Distance to integer boundary: %.6f %%", dist * 100); + else + DLOGF(SOAPY_SDR_DEBUG, " PLL in integer mode"); } this->mmw_synth->powerDown(); @@ -1224,7 +1228,7 @@ void SoapyIcyRadio::initClocks() // Inputs DLOGF(SOAPY_SDR_DEBUG, "Clock Inputs:"); - this->clk_mngr->configXTAL(26000000UL, Si5351::XTALCapacitance::C_10pF); + this->clk_mngr->configXTAL(26e6, Si5351::XTALCapacitance::C_10pF); uint32_t timeout = 500; while(--timeout && !this->clk_mngr->isXTALDetected()) @@ -1270,7 +1274,7 @@ void SoapyIcyRadio::initClocks() //// PLLA DLOGF(SOAPY_SDR_DEBUG, " PLL A:"); - this->clk_mngr->configPLL(Si5351::PLL::PLLA, 650000000UL, this->config.use_clkin ? Si5351::PLLSource::PLL_SRC_CLKIN : Si5351::PLLSource::PLL_SRC_XTAL, false); + this->clk_mngr->configPLL(Si5351::PLL::PLLA, 650e6, this->config.use_clkin ? Si5351::PLLSource::PLL_SRC_CLKIN : Si5351::PLLSource::PLL_SRC_XTAL, false); timeout = 500; while(--timeout && !this->clk_mngr->isPLLLocked(Si5351::PLL::PLLA)) @@ -1295,7 +1299,7 @@ void SoapyIcyRadio::initClocks() //// PLLB DLOGF(SOAPY_SDR_DEBUG, " PLL B:"); - this->clk_mngr->configPLL(Si5351::PLL::PLLB, 780000000UL, this->config.use_clkin ? Si5351::PLLSource::PLL_SRC_CLKIN : Si5351::PLLSource::PLL_SRC_XTAL, false); + this->clk_mngr->configPLL(Si5351::PLL::PLLB, 780e6, this->config.use_clkin ? Si5351::PLLSource::PLL_SRC_CLKIN : Si5351::PLLSource::PLL_SRC_XTAL, false); timeout = 500; while(--timeout && !this->clk_mngr->isPLLLocked(Si5351::PLL::PLLB)) @@ -1322,7 +1326,7 @@ void SoapyIcyRadio::initClocks() //// FPGA Clock #0 DLOGF(SOAPY_SDR_DEBUG, " Clock #%hhu (FPGA_CLK0):", Si5351::ClockOutput::CLK_FPGA_CLK0); - this->clk_mngr->configClock(Si5351::ClockOutput::CLK_FPGA_CLK0, 50000000UL, 0.f, Si5351::PLL::PLLA, false); + this->clk_mngr->configClock(Si5351::ClockOutput::CLK_FPGA_CLK0, 50e6, 0.f, Si5351::PLL::PLLA, false); this->clk_mngr->setClockDisableState(Si5351::ClockOutput::CLK_FPGA_CLK0, Si5351::ClockOutputDisableState::LOW); this->clk_mngr->setClockDriveCurrent(Si5351::ClockOutput::CLK_FPGA_CLK0, Si5351::ClockOutputDriveCurrent::I_4mA); this->clk_mngr->setClockOutputEnableMode(Si5351::ClockOutput::CLK_FPGA_CLK0, true); // Controlled by OE pin @@ -1347,7 +1351,7 @@ void SoapyIcyRadio::initClocks() //// FPGA Clock #1 DLOGF(SOAPY_SDR_DEBUG, " Clock #%hhu (FPGA_CLK1):", Si5351::ClockOutput::CLK_FPGA_CLK1); - this->clk_mngr->configClock(Si5351::ClockOutput::CLK_FPGA_CLK1, 49152000UL, 0.f, Si5351::PLL::PLLA, false); + this->clk_mngr->configClock(Si5351::ClockOutput::CLK_FPGA_CLK1, 49.152e6, 0.f, Si5351::PLL::PLLA, false); this->clk_mngr->setClockDisableState(Si5351::ClockOutput::CLK_FPGA_CLK1, Si5351::ClockOutputDisableState::LOW); this->clk_mngr->setClockDriveCurrent(Si5351::ClockOutput::CLK_FPGA_CLK1, Si5351::ClockOutputDriveCurrent::I_4mA); this->clk_mngr->setClockOutputEnableMode(Si5351::ClockOutput::CLK_FPGA_CLK1, true); // Controlled by OE pin @@ -1422,7 +1426,7 @@ void SoapyIcyRadio::initClocks() //// Transceiver Reference clock DLOGF(SOAPY_SDR_DEBUG, " Clock #%hhu (TRX_REF_CLK):", Si5351::ClockOutput::CLK_TRX_REF_CLK); - this->clk_mngr->configClock(Si5351::ClockOutput::CLK_TRX_REF_CLK, 39000000UL, 0.f, Si5351::PLL::PLLB, false); + this->clk_mngr->configClock(Si5351::ClockOutput::CLK_TRX_REF_CLK, 39e6, 0.f, Si5351::PLL::PLLB, false); this->clk_mngr->setClockDisableState(Si5351::ClockOutput::CLK_TRX_REF_CLK, Si5351::ClockOutputDisableState::LOW); this->clk_mngr->setClockDriveCurrent(Si5351::ClockOutput::CLK_TRX_REF_CLK, Si5351::ClockOutputDriveCurrent::I_4mA); this->clk_mngr->setClockOutputEnableMode(Si5351::ClockOutput::CLK_TRX_REF_CLK, true); // Controlled by OE pin @@ -1447,7 +1451,7 @@ void SoapyIcyRadio::initClocks() //// mmWave Synthesizer Reference clock DLOGF(SOAPY_SDR_DEBUG, " Clock #%hhu (SYNTH_REF_CLK):", Si5351::ClockOutput::CLK_SYNTH_REF_CLK); - this->clk_mngr->configClock(Si5351::ClockOutput::CLK_SYNTH_REF_CLK, 25000000UL, 0.f, Si5351::PLL::PLLA, false); + this->clk_mngr->configClock(Si5351::ClockOutput::CLK_SYNTH_REF_CLK, 25e6, 0.f, Si5351::PLL::PLLA, false); this->clk_mngr->setClockDisableState(Si5351::ClockOutput::CLK_SYNTH_REF_CLK, Si5351::ClockOutputDisableState::LOW); this->clk_mngr->setClockDriveCurrent(Si5351::ClockOutput::CLK_SYNTH_REF_CLK, Si5351::ClockOutputDriveCurrent::I_8mA); this->clk_mngr->setClockOutputEnableMode(Si5351::ClockOutput::CLK_SYNTH_REF_CLK, true); // Controlled by OE pin @@ -1472,7 +1476,7 @@ void SoapyIcyRadio::initClocks() //// External clock output (on frontend interface pin 2_3) // DLOGF(SOAPY_SDR_DEBUG, " Clock #%hhu (EXT_CLK_2_3):", Si5351::ClockOutput::CLK_EXT_CLK_2_3); - // this->clk_mngr->configClock(Si5351::ClockOutput::CLK_EXT_CLK_2_3, 10000000UL, 0.f, Si5351::PLL::PLL_AUTO, false); + // this->clk_mngr->configClock(Si5351::ClockOutput::CLK_EXT_CLK_2_3, 10e6, 0.f, Si5351::PLL::PLL_AUTO, false); // this->clk_mngr->setClockDisableState(Si5351::ClockOutput::CLK_EXT_CLK_2_3, Si5351::ClockOutputDisableState::LOW); // this->clk_mngr->setClockDriveCurrent(Si5351::ClockOutput::CLK_EXT_CLK_2_3, Si5351::ClockOutputDriveCurrent::I_8mA); // this->clk_mngr->setClockOutputEnableMode(Si5351::ClockOutput::CLK_EXT_CLK_2_3, true); // Controlled by OE pin @@ -1570,6 +1574,16 @@ void SoapyIcyRadio::initClocks() else DLOGF(SOAPY_SDR_DEBUG, "FPGA DDR3 AXI interface reset released!"); + // Check DDR3 init & calib done + timeout = 500; + while(--timeout && !this->axi_gpio[AXI_GPIO_SYS_INST]->getValue(AXI_GPIO_MIG_INIT_CALIB_COMPLETE_BIT)) + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + if(!this->axi_gpio[AXI_GPIO_SYS_INST]->getValue(AXI_GPIO_MIG_INIT_CALIB_COMPLETE_BIT)) + throw std::runtime_error("FPGA DDR3 initialization and/or calibration failed, aborting!"); + else + DLOGF(SOAPY_SDR_DEBUG, "FPGA DDR3 initialized and calibrated!"); + // De-assert I2S Core reset this->axi_gpio[AXI_GPIO_SYS_INST]->setValue(AXI_GPIO_RST_FPGA_CLK1_49M152_AUX_RESET_IN_BIT, AXIGPIO::Value::LOW); diff --git a/software/soapy/src/include/DMAMemoryManager.hpp b/software/soapy/src/include/DMAMemoryManager.hpp new file mode 100644 index 00000000..210aac95 --- /dev/null +++ b/software/soapy/src/include/DMAMemoryManager.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include +#include +#include "ioctl.hpp" +#include "AXIPCIe.hpp" +#include "MappedRegion.hpp" + +class DMAMemoryManager +{ +public: + DMAMemoryManager(int fd, AXIPCIe *axi_pcie); + ~DMAMemoryManager(); + + void init(); + void deinit(); + +private: + int fd; + AXIPCIe *axi_pcie; + + std::mutex mutex; +}; \ No newline at end of file diff --git a/software/soapy/src/include/LT7182S.hpp b/software/soapy/src/include/LT7182S.hpp index 190d8ba4..e227a0c3 100644 --- a/software/soapy/src/include/LT7182S.hpp +++ b/software/soapy/src/include/LT7182S.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -74,9 +75,6 @@ class LT7182S }; private: - static float Pow2(int8_t e); - static uint8_t FindClosest(float val, const float *arr, uint8_t size); - static void ISR(void *_this); void handleIRQ(); diff --git a/software/soapy/src/include/Utils.hpp b/software/soapy/src/include/Utils.hpp index 8c941fc7..a713fe5a 100644 --- a/software/soapy/src/include/Utils.hpp +++ b/software/soapy/src/include/Utils.hpp @@ -44,70 +44,55 @@ namespace Utils // Find last set bit in word uint32_t FindLastSetBit(uint32_t word); - // Locate the closest element in an array - uint32_t FindClosest(int32_t val, const int32_t *array, uint32_t size); - // Shift the value and apply the specified mask - uint32_t FieldPrep(uint32_t mask, uint32_t val); - // Get a field specified by a mask from a word - uint32_t FieldGet(uint32_t mask, uint32_t word); - // Log base 2 of the given number - int32_t LogBase2(uint32_t x); - // Find greatest common divisor of the given two numbers - uint32_t GreatestCommonDivisor(uint32_t a, uint32_t b); - // Find lowest common multiple of the given two numbers - uint32_t LowestCommonMultiple(uint32_t a, uint32_t b); - // Calculate best rational approximation for a given fraction - void RationalBestApproximation(uint32_t givenNumerator, uint32_t givenDenominator, uint32_t maxNumerator, uint32_t maxDenominator, uint32_t *bestNumerator, uint32_t *bestDenominator); - // Calculate the number of set bits (8-bit size) - unsigned int Hweight8(uint8_t word); - // Calculate the number of set bits (16-bit size) - unsigned int Hweight16(uint16_t word); - // Calculate the number of set bits (32-bit size) - unsigned int Hweight32(uint32_t word); - // Calculate the quotient and the remainder of an integer division uint64_t DoDiv(uint64_t* n, uint64_t base); - // Unsigned 64bit divide with 64bit divisor and remainder - uint64_t Div64U64Rem(uint64_t dividend, uint64_t divisor, uint64_t *remainder); - // Unsigned 64bit divide with 32bit divisor with remainder - uint64_t DivU64Rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder); - int64_t DivS64Rem(int64_t dividend, int32_t divisor, int32_t *remainder); - // Unsigned 64bit divide with 32bit divisor - uint64_t DivU64(uint64_t dividend, uint32_t divisor); - int64_t DivS64(int64_t dividend, int32_t divisor); - // Converts from string to int32_t - int32_t StrToInt32(const char *str); - // Converts from string to uint32_t - uint32_t StrToUint32(const char *str); - - void PutUnalignedBe16(uint16_t val, uint8_t *buf); - uint16_t GetUnalignedBe16(uint8_t *buf); - void PutUnalignedLe16(uint16_t val, uint8_t *buf); - uint16_t GetUnalignedLe16(uint8_t *buf); - void PutUnalignedBe24(uint32_t val, uint8_t *buf); - uint32_t GetUnalignedBe24(uint8_t *buf); - void PutUnalignedLe24(uint32_t val, uint8_t *buf); - uint32_t GetUnalignedLe24(uint8_t *buf); - void PutUnalignedBe32(uint32_t val, uint8_t *buf); - uint32_t GetUnalignedBe32(uint8_t *buf); - void PutUnalignedLe32(uint32_t val, uint8_t *buf); - uint32_t GetUnalignedLe32(uint8_t *buf); - - int16_t SignExtend16(uint16_t value, int index); - int32_t SignExtend32(uint32_t value, int index); - uint64_t MulU32U32(uint32_t a, uint32_t b); - uint64_t MulU64U32Shr(uint64_t a, uint32_t mul, unsigned int shift); - - bool IsBigEndian(void); - void Memswap64(void *buf, uint32_t bytes, uint32_t step); uint32_t IntSqrt(uint32_t x); int32_t Ilog2(int32_t x); + // Convert to/from Sign-Integer-Fraction 1.1.14 (1-bit signal, 1-bit integer, 1-bit fraction) format uint16_t IntToSIF1_1_14(int32_t val); // Fractional part is in micro units uint16_t ToSIF1_1_14(double val); int32_t IntFromSIF1_1_14(uint16_t val); // Fractional part is in micro units double FromSIF1_1_14(uint16_t val); + // Find closest value (or its index) in vector + template + size_t FindClosestIndex(std::vector &vec, T value) + { + size_t idx = 0; + T min_diff = std::abs(vec[0] - value); + + for(size_t i = 1; i < vec.size(); i++) + { + T diff = std::abs(vec[i] - value); + + if(diff < min_diff) + { + min_diff = diff; + idx = i; + } + } + + return idx; + } + template + inline size_t FindClosestIndex(const T *vec, size_t size, T value) + { + std::vector v(vec, vec + size); + + return Utils::FindClosestIndex(v, value); + } + template + T FindClosestValue(std::vector &vec, T value) + { + return vec[Utils::FindClosestIndex(vec, value)]; + } + template + inline T FindClosestValue(const T *vec, size_t size, T value) + { + return vec[Utils::FindClosestIndex(vec, size, value)]; + } + template std::pair FindLongestSequence(std::vector &vec, T value) { @@ -145,4 +130,11 @@ namespace Utils return std::make_pair(max_start, max_cnt); } + template + inline std::pair FindLongestSequence(const T *vec, size_t size, T value) + { + std::vector v(vec, vec + size); + + return Utils::FindLongestSequence(v, value); + } } \ No newline at end of file diff --git a/software/soapy/src/include/ioctl.hpp b/software/soapy/src/include/ioctl.hpp index 62d0f15d..b9b1b770 100644 --- a/software/soapy/src/include/ioctl.hpp +++ b/software/soapy/src/include/ioctl.hpp @@ -5,15 +5,23 @@ typedef struct { - uint64_t ullPhysAddr; - uint32_t ulBufSize; -} icyradio_ioctl_dma_buffer_query_t; + union + { + uint64_t ullPhysAddr; // For querying by physical address or to return the physical address + uint64_t ullIndex; // For querying by index + }; + uint32_t ulSize; // Size of the buffer +} icyradio_ioctl_dma_buffer_t; -#define ICYRADIO_IOCTL_DMA_ALLOC _IOWR('B', 64, uint64_t *) -#define ICYRADIO_IOCTL_DMA_QUERY _IOR('B', 65, icyradio_ioctl_dma_buffer_query_t *) -#define ICYRADIO_IOCTL_DMA_FREE _IO('B', 66) -#define ICYRADIO_IOCTL_IRQ_QUERY _IOR('B', 67, uint8_t *) -#define ICYRADIO_IOCTL_IRQ_FLUSH _IO('B', 68) -#define ICYRADIO_IOCTL_IRQ_NOFLUSH _IO('B', 69) +#define ICYRADIO_IOCTL_DMA_ALLOC _IOWR('B', 64, icyradio_ioctl_dma_buffer_t *) // Allocate a DMA buffer +#define ICYRADIO_IOCTL_DMA_GET_COUNT _IOR('B', 65, uint64_t *) // Get the number of allocated DMA buffers +#define ICYRADIO_IOCTL_DMA_QUERY_BY_ADDR _IOR('B', 66, icyradio_ioctl_dma_buffer_t *) // Query a DMA buffer by physical address +#define ICYRADIO_IOCTL_DMA_QUERY_BY_INDEX _IOR('B', 67, icyradio_ioctl_dma_buffer_t *) // Query a DMA buffer by index +#define ICYRADIO_IOCTL_DMA_FREE _IOW('B', 68, icyradio_ioctl_dma_buffer_t *) // Free a DMA buffer +#define ICYRADIO_IOCTL_DMA_FREE_ALL _IO('B', 69) // Free all DMA buffers -#define ICYRADIO_IOCTL_SERIAL_QUERY _IOR('B', 96, uint64_t *) \ No newline at end of file +#define ICYRADIO_IOCTL_IRQ_QUERY _IOR('B', 80, uint8_t *) // Query the number of allocated IRQ vectors +#define ICYRADIO_IOCTL_IRQ_FLUSH _IO('B', 81) // Flush the IRQ count (resets to zero and does not rise) +#define ICYRADIO_IOCTL_IRQ_NOFLUSH _IO('B', 82) // Do not flush the IRQ count (returns to normal operation) + +#define ICYRADIO_IOCTL_SERIAL_QUERY _IOR('B', 96, uint64_t *) // Query the serial number of the device \ No newline at end of file