From 3685a9c25865c4d175accef0cc975c6e5af4c449 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 19 Dec 2023 15:57:01 +0200 Subject: [PATCH 01/46] Finish documenting all the class and structs within classes headers --- src/ADF4002/ADF4002.h | 4 ++++ src/CDCM6208/CDCM6208_Dev.h | 5 ++++- src/Si5351C/Si5351C.h | 5 ++++- src/boards/LimeSDR_X3/LimeSDR_X3.h | 1 + src/include/limesuite/LMS7002M.h | 5 ++++- src/include/limesuite/SDRDevice.h | 18 ++++++++++++++++-- 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/ADF4002/ADF4002.h b/src/ADF4002/ADF4002.h index b6eb71f12..57f3022fb 100644 --- a/src/ADF4002/ADF4002.h +++ b/src/ADF4002/ADF4002.h @@ -13,6 +13,10 @@ namespace lime { +/** @brief The class for controlling the ADF4002 frequency synthesizer. + * + * More information: https://www.analog.com/en/products/adf4002.html + */ class LIME_API ADF4002 { public: diff --git a/src/CDCM6208/CDCM6208_Dev.h b/src/CDCM6208/CDCM6208_Dev.h index a4078d4ec..b49b6d429 100644 --- a/src/CDCM6208/CDCM6208_Dev.h +++ b/src/CDCM6208/CDCM6208_Dev.h @@ -72,7 +72,10 @@ struct CDCM_Outputs { CDCM_Output Y7{ false, false, 0, 0, 0, 0, 30.72e6, 0 }; ///< The value of the Y7 output }; -/** @brief Class for controlling the CDCM6208 2:8 Clock Generator, Jitter Cleaner With Fractional Dividers */ +/** @brief Class for controlling the CDCM6208 2:8 Clock Generator, Jitter Cleaner With Fractional Dividers. + * + * More information: https://www.ti.com/product/CDCM6208 + */ class LIME_API CDCM_Dev { public: diff --git a/src/Si5351C/Si5351C.h b/src/Si5351C/Si5351C.h index d1557e2e0..6b016d961 100644 --- a/src/Si5351C/Si5351C.h +++ b/src/Si5351C/Si5351C.h @@ -56,7 +56,10 @@ struct Si5351_PLL { class II2C; -/** @brief Class for controlling the Si5351C I2C-programmable any-frequency CMOS clock generator + VCXO */ +/** @brief Class for controlling the Si5351C I2C-programmable any-frequency CMOS clock generator + VCXO + * + * More information: https://www.skyworksinc.com/en/Products/Timing/CMOS-Clock-Generators/Si5351C-GM1 + */ class LIME_API Si5351C { public: diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.h b/src/boards/LimeSDR_X3/LimeSDR_X3.h index a14a1560d..79be9fd4c 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.h +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.h @@ -16,6 +16,7 @@ class LitePCIe; class Equalizer; class SlaveSelectShim; +/** @brief Class for managing the LimeSDR X3 device. */ class LimeSDR_X3 : public LMS7002M_SDRDevice { public: diff --git a/src/include/limesuite/LMS7002M.h b/src/include/limesuite/LMS7002M.h index 4996510c6..dee8bd350 100644 --- a/src/include/limesuite/LMS7002M.h +++ b/src/include/limesuite/LMS7002M.h @@ -40,7 +40,10 @@ struct RSSI_measurements { typedef double float_type; -/** @brief Class for communicating with the LMS7002M chip. */ +/** @brief Class for communicating with the LMS7002M chip. + * + * More information: https://limemicro.com/technology/lms7002m/ +*/ class LIME_API LMS7002M { public: diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index e58318aeb..9aab27293 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -20,8 +20,8 @@ namespace lime { class DeviceNode; -/// SDRDevice can have multiple modules (RF chips), that can operate independently +/** @brief SDRDevice can have multiple modules (RF chips), that can operate independently. */ class LIME_API SDRDevice { public: @@ -34,6 +34,7 @@ class LIME_API SDRDevice typedef std::map SlaveNameIds_t; + /** @brief General information about the Radio-Frequency System-on-Chip (RFSoC). */ struct RFSOCDescriptor { std::string name; uint8_t channelCount; @@ -45,6 +46,7 @@ class LIME_API SDRDevice std::unordered_map> antennaRange; }; + /** @brief Structure for the information of a custom parameter. */ struct CustomParameter { std::string name; int32_t id; @@ -53,11 +55,13 @@ class LIME_API SDRDevice bool readOnly; }; + /** @brief Structure for storing the information of a memory region. */ struct Region { int32_t address; int32_t size; }; + /** @brief Describes a data storage of a certain type a device holds. */ struct DataStorage { SDRDevice* ownerDevice; eMemoryDevice memoryDeviceType; @@ -98,7 +102,9 @@ class LIME_API SDRDevice static const char PATH_SEPARATOR_SYMBOL; }; + /** @brief Structure for holding the statistics of a stream */ struct StreamStats { + /** @brief Structure for storing the first in first out queue statistics */ struct FIFOStats { std::size_t totalCount; std::size_t usedCount; @@ -118,6 +124,7 @@ class LIME_API SDRDevice uint32_t late; }; + /** @brief Describes the status of the GPS. */ struct GPS_Lock { enum class LockStatus : uint8_t { Undefined, NotAvailable, Has2D, Has3D }; @@ -127,8 +134,9 @@ class LIME_API SDRDevice LockStatus gps; }; - // channels order and data transmission formats setup + /** @brief Configuration settings for a stream. */ struct StreamConfig { + /** @brief Extra configuration settings for a stream. */ struct Extras { Extras(); bool usePoll; @@ -174,19 +182,24 @@ class LIME_API SDRDevice Extras* extraConfig; }; + /** @brief The metadata of a stream packet. */ struct StreamMeta { int64_t timestamp; bool useTimestamp; bool flush; // submit data to hardware without waiting for full buffer }; + /** @brief Configuration of a general finite impulse response (FIR) filter. */ struct GFIRFilter { double bandwidth; bool enabled; }; + /** @brief Configuration of a single channel. */ struct ChannelConfig { ChannelConfig() { memset(this, 0, sizeof(ChannelConfig)); } + + /** @brief Configuration for a direction in a channel. */ struct Direction { double centerFrequency; double NCOoffset; @@ -204,6 +217,7 @@ class LIME_API SDRDevice Direction tx; }; + /** @brief Configuration of an SDR device. */ struct SDRConfig { SDRConfig() : referenceClockFreq(0) From 4a6f9071ced9beb204cf5fdcb83753d2c126f891 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 19 Dec 2023 16:39:54 +0200 Subject: [PATCH 02/46] Separate PCIe classes into separate files --- src/boards/LimeSDR_X3/LimeSDR_X3Entry.cpp | 4 +- src/boards/LimeSDR_XTRX/LimeSDR_XTRXEntry.cpp | 4 +- src/boards/MMX8/CMakeLists.txt | 5 +- src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.cpp | 19 ++++ src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h | 29 ++++++ .../MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp | 45 +++++++++ src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h | 38 +++++++ .../MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.cpp | 24 +++++ .../MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h | 29 ++++++ src/boards/MMX8/MM_X8Entry.cpp | 99 +------------------ src/comms/PCIe/CMakeLists.txt | 4 +- ...IeCommon.cpp => LMS64C_FPGA_Over_PCIe.cpp} | 31 +----- src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h | 37 +++++++ src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.cpp | 18 ++++ src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h | 27 +++++ src/comms/PCIe/PCIE_CSR_Pipe.cpp | 17 ++++ src/comms/PCIe/PCIE_CSR_Pipe.h | 22 +++++ src/comms/PCIe/PCIeCommon.h | 56 ----------- src/tests/comms/PCIe/PCIE_CSR_PipeTest.cpp | 2 +- 19 files changed, 324 insertions(+), 186 deletions(-) create mode 100644 src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.cpp create mode 100644 src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h create mode 100644 src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp create mode 100644 src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h create mode 100644 src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.cpp create mode 100644 src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h rename src/comms/PCIe/{PCIeCommon.cpp => LMS64C_FPGA_Over_PCIe.cpp} (62%) create mode 100644 src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h create mode 100644 src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.cpp create mode 100644 src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h create mode 100644 src/comms/PCIe/PCIE_CSR_Pipe.cpp create mode 100644 src/comms/PCIe/PCIE_CSR_Pipe.h delete mode 100644 src/comms/PCIe/PCIeCommon.h diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3Entry.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3Entry.cpp index b4f2c3820..785da3e23 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3Entry.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3Entry.cpp @@ -5,7 +5,9 @@ #include "LimeSDR_X3Entry.h" #include "LitePCIe.h" #include "LimeSDR_X3.h" -#include "PCIeCommon.h" +#include "PCIE_CSR_Pipe.h" +#include "LMS64C_FPGA_Over_PCIe.h" +#include "LMS64C_LMS7002M_Over_PCIe.h" #include #include diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRXEntry.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRXEntry.cpp index 3b28851b9..72ba9ac1c 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRXEntry.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRXEntry.cpp @@ -6,7 +6,9 @@ #include "LitePCIe.h" #include "LimeSDR_XTRX.h" #include "protocols/LMS64CProtocol.h" -#include "PCIeCommon.h" +#include "PCIE_CSR_Pipe.h" +#include "LMS64C_FPGA_Over_PCIe.h" +#include "LMS64C_LMS7002M_Over_PCIe.h" #include #include diff --git a/src/boards/MMX8/CMakeLists.txt b/src/boards/MMX8/CMakeLists.txt index 2bced2d27..1c1091f2b 100644 --- a/src/boards/MMX8/CMakeLists.txt +++ b/src/boards/MMX8/CMakeLists.txt @@ -5,8 +5,11 @@ set(THIS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/boards/MMX8) set(MM_X8_SOURCES - ${THIS_SOURCE_DIR}/MM_X8Entry.cpp + ${THIS_SOURCE_DIR}/LMS64C_ADF_Over_PCIe_MMX8.cpp + ${THIS_SOURCE_DIR}/LMS64C_FPGA_Over_PCIe_MMX8.cpp + ${THIS_SOURCE_DIR}/LMS64C_LMS7002M_Over_PCIe_MMX8.cpp ${THIS_SOURCE_DIR}/MM_X8.cpp + ${THIS_SOURCE_DIR}/MM_X8Entry.cpp ) ######################################################################## diff --git a/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.cpp b/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.cpp new file mode 100644 index 000000000..8237ed1c6 --- /dev/null +++ b/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.cpp @@ -0,0 +1,19 @@ +#include "LMS64C_ADF_Over_PCIe_MMX8.h" + +using namespace lime; + +LMS64C_ADF_Over_PCIe_MMX8::LMS64C_ADF_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex) + : pipe(dataPort) + , subdeviceIndex(subdeviceIndex) +{ +} + +int LMS64C_ADF_Over_PCIe_MMX8::SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return LMS64CProtocol::ADF4002_SPI(pipe, MOSI, count, subdeviceIndex); +} + +int LMS64C_ADF_Over_PCIe_MMX8::SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return LMS64CProtocol::ADF4002_SPI(pipe, MOSI, count, subdeviceIndex); +} diff --git a/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h b/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h new file mode 100644 index 000000000..fb350c1ad --- /dev/null +++ b/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h @@ -0,0 +1,29 @@ +#ifndef LIME_LMS64C_ADF_OVER_PCIE_MMX8_H +#define LIME_LMS64C_ADF_OVER_PCIE_MMX8_H + +#include "limesuite/IComms.h" +#include "LitePCIe.h" +#include "PCIE_CSR_Pipe.h" + +#include +#include + +namespace lime { + +/** @brief A class for communicating with MMX8's subdevice's ADF4002 chips. */ +class LMS64C_ADF_Over_PCIe_MMX8 : public ISPI +{ + public: + LMS64C_ADF_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex); + + virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + + private: + PCIE_CSR_Pipe pipe; + uint32_t subdeviceIndex; +}; + +} // namespace lime + +#endif // LIME_LMS64C_ADF_OVER_PCIE_MMX8_H \ No newline at end of file diff --git a/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp new file mode 100644 index 000000000..10b60a779 --- /dev/null +++ b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp @@ -0,0 +1,45 @@ +#include "LMS64C_FPGA_Over_PCIe_MMX8.h" + +using namespace lime; + +LMS64C_FPGA_Over_PCIe_MMX8::LMS64C_FPGA_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex) + : pipe(dataPort) + , subdeviceIndex(subdeviceIndex) +{ +} + +int LMS64C_FPGA_Over_PCIe_MMX8::SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return LMS64CProtocol::FPGA_SPI(pipe, MOSI, MISO, count, subdeviceIndex); +} + +int LMS64C_FPGA_Over_PCIe_MMX8::SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return LMS64CProtocol::FPGA_SPI(pipe, MOSI, MISO, count, subdeviceIndex); +} + +int LMS64C_FPGA_Over_PCIe_MMX8::CustomParameterWrite(const std::vector& parameters) +{ + return LMS64CProtocol::CustomParameterWrite(pipe, parameters, subdeviceIndex); +} + +int LMS64C_FPGA_Over_PCIe_MMX8::CustomParameterRead(std::vector& parameters) +{ + return LMS64CProtocol::CustomParameterRead(pipe, parameters, subdeviceIndex); +} + +int LMS64C_FPGA_Over_PCIe_MMX8::ProgramWrite(const char* data, size_t length, int prog_mode, int target, ProgressCallback callback) +{ + return LMS64CProtocol::ProgramWrite( + pipe, data, length, prog_mode, static_cast(target), callback, subdeviceIndex); +} + +int LMS64C_FPGA_Over_PCIe_MMX8::MemoryWrite(uint32_t address, const void* data, uint32_t dataLength) +{ + return LMS64CProtocol::MemoryWrite(pipe, address, data, dataLength, subdeviceIndex); +} + +int LMS64C_FPGA_Over_PCIe_MMX8::MemoryRead(uint32_t address, void* data, uint32_t dataLength) +{ + return LMS64CProtocol::MemoryRead(pipe, address, data, dataLength, subdeviceIndex); +} diff --git a/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h new file mode 100644 index 000000000..3fd44b1ce --- /dev/null +++ b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h @@ -0,0 +1,38 @@ +#ifndef LIME_LMS64C_FPGA_OVER_PCIE_MMX8_H +#define LIME_LMS64C_FPGA_OVER_PCIE_MMX8_H + +#include "limesuite/IComms.h" +#include "LitePCIe.h" +#include "PCIE_CSR_Pipe.h" + +#include +#include + +namespace lime { + +/** @brief A class for communicating with MMX8's subdevice's FPGA chips. */ +class LMS64C_FPGA_Over_PCIe_MMX8 : public IComms +{ + public: + LMS64C_FPGA_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex); + + virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + + virtual int CustomParameterWrite(const std::vector& parameters) override; + virtual int CustomParameterRead(std::vector& parameters) override; + + virtual int ProgramWrite( + const char* data, size_t length, int prog_mode, int target, ProgressCallback callback = nullptr) override; + + virtual int MemoryWrite(uint32_t address, const void* data, uint32_t dataLength) override; + virtual int MemoryRead(uint32_t address, void* data, uint32_t dataLength) override; + + private: + PCIE_CSR_Pipe pipe; + uint32_t subdeviceIndex; +}; + +} // namespace lime + +#endif // LIME_LMS64C_FPGA_OVER_PCIE_MMX8_H \ No newline at end of file diff --git a/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.cpp b/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.cpp new file mode 100644 index 000000000..48fc37d66 --- /dev/null +++ b/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.cpp @@ -0,0 +1,24 @@ +#include "LMS64C_LMS7002M_Over_PCIe_MMX8.h" + +using namespace lime; + +LMS64C_LMS7002M_Over_PCIe_MMX8::LMS64C_LMS7002M_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex) + : pipe(dataPort) + , subdeviceIndex(subdeviceIndex) +{ +} + +int LMS64C_LMS7002M_Over_PCIe_MMX8::SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return SPI(0, MOSI, MISO, count); +} + +int LMS64C_LMS7002M_Over_PCIe_MMX8::SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return LMS64CProtocol::LMS7002M_SPI(pipe, spiBusAddress, MOSI, MISO, count, subdeviceIndex); +} + +int LMS64C_LMS7002M_Over_PCIe_MMX8::ResetDevice(int chipSelect) +{ + return LMS64CProtocol::DeviceReset(pipe, chipSelect, subdeviceIndex); +} diff --git a/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h b/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h new file mode 100644 index 000000000..83d11bed2 --- /dev/null +++ b/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h @@ -0,0 +1,29 @@ +#ifndef LIME_LMS64C_LMS7002M_OVER_PCIE_MMX8_H +#define LIME_LMS64C_LMS7002M_OVER_PCIE_MMX8_H + +#include "limesuite/IComms.h" +#include "LitePCIe.h" +#include "PCIE_CSR_Pipe.h" + +#include +#include + +namespace lime { + +/** @brief A class for communicating with MMX8's subdevice's LMS7002M chips. */ +class LMS64C_LMS7002M_Over_PCIe_MMX8 : public IComms +{ + public: + LMS64C_LMS7002M_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex); + virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + virtual int ResetDevice(int chipSelect) override; + + private: + PCIE_CSR_Pipe pipe; + uint32_t subdeviceIndex; +}; + +} // namespace lime + +#endif // LIME_LMS64C_LMS7002M_OVER_PCIE_MMX8_H \ No newline at end of file diff --git a/src/boards/MMX8/MM_X8Entry.cpp b/src/boards/MMX8/MM_X8Entry.cpp index 0dc93eb27..c27a4f436 100644 --- a/src/boards/MMX8/MM_X8Entry.cpp +++ b/src/boards/MMX8/MM_X8Entry.cpp @@ -5,7 +5,10 @@ #include "MM_X8Entry.h" #include "LitePCIe.h" #include "MM_X8.h" -#include "PCIeCommon.h" +#include "PCIE_CSR_Pipe.h" +#include "LMS64C_ADF_Over_PCIe_MMX8.h" +#include "LMS64C_FPGA_Over_PCIe_MMX8.h" +#include "LMS64C_LMS7002M_Over_PCIe_MMX8.h" #include #include @@ -75,100 +78,6 @@ std::vector LimeSDR_MMX8Entry::enumerate(const DeviceHandle& hint) return handles; } -/** @brief A class for communicating with MMX8's subdevice's LMS7002M chips. */ -class LMS64C_LMS7002M_Over_PCIe_MMX8 : public lime::IComms -{ - public: - LMS64C_LMS7002M_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex) - : pipe(dataPort) - , subdeviceIndex(subdeviceIndex) - { - } - virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override { return SPI(0, MOSI, MISO, count); } - virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override - { - return LMS64CProtocol::LMS7002M_SPI(pipe, spiBusAddress, MOSI, MISO, count, subdeviceIndex); - } - virtual int ResetDevice(int chipSelect) override { return LMS64CProtocol::DeviceReset(pipe, chipSelect, subdeviceIndex); }; - - private: - PCIE_CSR_Pipe pipe; - uint32_t subdeviceIndex; -}; - -/** @brief A class for communicating with MMX8's subdevice's FPGA chips. */ -class LMS64C_FPGA_Over_PCIe_MMX8 : public lime::IComms -{ - public: - LMS64C_FPGA_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex) - : pipe(dataPort) - , subdeviceIndex(subdeviceIndex) - { - } - int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override - { - return LMS64CProtocol::FPGA_SPI(pipe, MOSI, MISO, count, subdeviceIndex); - } - - int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override - { - return LMS64CProtocol::FPGA_SPI(pipe, MOSI, MISO, count, subdeviceIndex); - } - - virtual int CustomParameterWrite(const std::vector& parameters) override - { - return LMS64CProtocol::CustomParameterWrite(pipe, parameters, subdeviceIndex); - }; - virtual int CustomParameterRead(std::vector& parameters) override - { - return LMS64CProtocol::CustomParameterRead(pipe, parameters, subdeviceIndex); - } - virtual int ProgramWrite( - const char* data, size_t length, int prog_mode, int target, ProgressCallback callback = nullptr) override - { - return LMS64CProtocol::ProgramWrite( - pipe, data, length, prog_mode, (LMS64CProtocol::ProgramWriteTarget)target, callback, subdeviceIndex); - } - - int MemoryWrite(uint32_t address, const void* data, uint32_t dataLength) - { - return LMS64CProtocol::MemoryWrite(pipe, address, data, dataLength, subdeviceIndex); - } - - int MemoryRead(uint32_t address, void* data, uint32_t dataLength) - { - return LMS64CProtocol::MemoryRead(pipe, address, data, dataLength, subdeviceIndex); - } - - private: - PCIE_CSR_Pipe pipe; - uint32_t subdeviceIndex; -}; - -/** @brief A class for communicating with MMX8's subdevice's ADF4002 chips. */ -class LMS64C_ADF_Over_PCIe_MMX8 : public lime::ISPI -{ - public: - LMS64C_ADF_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex) - : pipe(dataPort) - , subdeviceIndex(subdeviceIndex) - { - } - - int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override - { - return LMS64CProtocol::ADF4002_SPI(pipe, MOSI, count, subdeviceIndex); - } - int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override - { - return LMS64CProtocol::ADF4002_SPI(pipe, MOSI, count, subdeviceIndex); - } - - private: - PCIE_CSR_Pipe pipe; - uint32_t subdeviceIndex; -}; - SDRDevice* LimeSDR_MMX8Entry::make(const DeviceHandle& handle) { auto control = std::make_shared(); diff --git a/src/comms/PCIe/CMakeLists.txt b/src/comms/PCIe/CMakeLists.txt index 4ef848a2d..d3ded6092 100644 --- a/src/comms/PCIe/CMakeLists.txt +++ b/src/comms/PCIe/CMakeLists.txt @@ -4,9 +4,11 @@ set(THIS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/comms/PCIe) set(COMMS_LITE_PCIE_SOURCES + ${THIS_SOURCE_DIR}/LMS64C_FPGA_Over_PCIe.cpp + ${THIS_SOURCE_DIR}/LMS64C_LMS7002M_Over_PCIe.cpp ${THIS_SOURCE_DIR}/LitePCIe.cpp + ${THIS_SOURCE_DIR}/PCIE_CSR_Pipe.cpp ${THIS_SOURCE_DIR}/TRXLooper_PCIE.cpp - ${THIS_SOURCE_DIR}/PCIeCommon.cpp ) ######################################################################## diff --git a/src/comms/PCIe/PCIeCommon.cpp b/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.cpp similarity index 62% rename from src/comms/PCIe/PCIeCommon.cpp rename to src/comms/PCIe/LMS64C_FPGA_Over_PCIe.cpp index e2caee401..6dac98f55 100644 --- a/src/comms/PCIe/PCIeCommon.cpp +++ b/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.cpp @@ -1,36 +1,7 @@ -#include "PCIeCommon.h" +#include "LMS64C_FPGA_Over_PCIe.h" using namespace lime; -PCIE_CSR_Pipe::PCIE_CSR_Pipe(std::shared_ptr port) - : port(port) -{ -} - -int PCIE_CSR_Pipe::Write(const uint8_t* data, size_t length, int timeout_ms) -{ - return port->WriteControl(data, length, timeout_ms); -} -int PCIE_CSR_Pipe::Read(uint8_t* data, size_t length, int timeout_ms) -{ - return port->ReadControl(data, length, timeout_ms); -} - -LMS64C_LMS7002M_Over_PCIe::LMS64C_LMS7002M_Over_PCIe(std::shared_ptr dataPort) - : pipe(dataPort) -{ -} - -int LMS64C_LMS7002M_Over_PCIe::SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) -{ - return SPI(0, MOSI, MISO, count); -} - -int LMS64C_LMS7002M_Over_PCIe::SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) -{ - return LMS64CProtocol::LMS7002M_SPI(pipe, spiBusAddress, MOSI, MISO, count); -} - LMS64C_FPGA_Over_PCIe::LMS64C_FPGA_Over_PCIe(std::shared_ptr dataPort) : pipe(dataPort) { diff --git a/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h b/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h new file mode 100644 index 000000000..fe527b4be --- /dev/null +++ b/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h @@ -0,0 +1,37 @@ +#ifndef LIME_LMS64C_FPGA_OVER_PCIE_H +#define LIME_LMS64C_FPGA_OVER_PCIE_H + +#include "limesuite/IComms.h" +#include "LitePCIe.h" +#include "PCIE_CSR_Pipe.h" + +#include +#include + +namespace lime { + +/** @brief A class for communicating with a device's FPGA over a PCIe interface. */ +class LMS64C_FPGA_Over_PCIe : public IComms +{ + public: + LMS64C_FPGA_Over_PCIe(std::shared_ptr dataPort); + + virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + + virtual int CustomParameterWrite(const std::vector& parameters) override; + virtual int CustomParameterRead(std::vector& parameters) override; + + virtual int ProgramWrite( + const char* data, size_t length, int prog_mode, int target, ProgressCallback callback = nullptr) override; + + virtual int MemoryWrite(uint32_t address, const void* data, uint32_t dataLength) override; + virtual int MemoryRead(uint32_t address, void* data, uint32_t dataLength) override; + + private: + PCIE_CSR_Pipe pipe; +}; + +} // namespace lime + +#endif // LIME_LMS64C_FPGA_OVER_PCIE_H diff --git a/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.cpp b/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.cpp new file mode 100644 index 000000000..8a859e17f --- /dev/null +++ b/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.cpp @@ -0,0 +1,18 @@ +#include "LMS64C_LMS7002M_Over_PCIe.h" + +using namespace lime; + +LMS64C_LMS7002M_Over_PCIe::LMS64C_LMS7002M_Over_PCIe(std::shared_ptr dataPort) + : pipe(dataPort) +{ +} + +int LMS64C_LMS7002M_Over_PCIe::SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return SPI(0, MOSI, MISO, count); +} + +int LMS64C_LMS7002M_Over_PCIe::SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) +{ + return LMS64CProtocol::LMS7002M_SPI(pipe, spiBusAddress, MOSI, MISO, count); +} diff --git a/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h b/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h new file mode 100644 index 000000000..bc2f5a772 --- /dev/null +++ b/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h @@ -0,0 +1,27 @@ +#ifndef LIME_LMS64C_LMS7002M_OVER_PCIE_H +#define LIME_LMS64C_LMS7002M_OVER_PCIE_H + +#include "limesuite/IComms.h" +#include "LitePCIe.h" +#include "PCIE_CSR_Pipe.h" + +#include +#include + +namespace lime { + +/** @brief A class for communicating with a device's LMS7002M chip over a PCIe interface. */ +class LMS64C_LMS7002M_Over_PCIe : public IComms +{ + public: + LMS64C_LMS7002M_Over_PCIe(std::shared_ptr dataPort); + virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + + private: + PCIE_CSR_Pipe pipe; +}; + +} // namespace lime + +#endif // LIME_LMS64C_LMS7002M_OVER_PCIE_H diff --git a/src/comms/PCIe/PCIE_CSR_Pipe.cpp b/src/comms/PCIe/PCIE_CSR_Pipe.cpp new file mode 100644 index 000000000..d033e67ce --- /dev/null +++ b/src/comms/PCIe/PCIE_CSR_Pipe.cpp @@ -0,0 +1,17 @@ +#include "PCIE_CSR_Pipe.h" + +using namespace lime; + +PCIE_CSR_Pipe::PCIE_CSR_Pipe(std::shared_ptr port) + : port(port) +{ +} + +int PCIE_CSR_Pipe::Write(const uint8_t* data, size_t length, int timeout_ms) +{ + return port->WriteControl(data, length, timeout_ms); +} +int PCIE_CSR_Pipe::Read(uint8_t* data, size_t length, int timeout_ms) +{ + return port->ReadControl(data, length, timeout_ms); +} diff --git a/src/comms/PCIe/PCIE_CSR_Pipe.h b/src/comms/PCIe/PCIE_CSR_Pipe.h new file mode 100644 index 000000000..22dcf4167 --- /dev/null +++ b/src/comms/PCIe/PCIE_CSR_Pipe.h @@ -0,0 +1,22 @@ +#ifndef PCIE_CSR_PIPE_H +#define PCIE_CSR_PIPE_H + +#include "limesuite/IComms.h" +#include "LMS64CProtocol.h" +#include "LitePCIe.h" + +using namespace lime; + +/** @brief An abstract class for interfacing with Control/Status registers (CSR) of a PCIe device. */ +class PCIE_CSR_Pipe : public ISerialPort +{ + public: + explicit PCIE_CSR_Pipe(std::shared_ptr port); + virtual int Write(const uint8_t* data, size_t length, int timeout_ms) override; + virtual int Read(uint8_t* data, size_t length, int timeout_ms) override; + + protected: + std::shared_ptr port; +}; + +#endif // PCIE_CSR_PIPE_H diff --git a/src/comms/PCIe/PCIeCommon.h b/src/comms/PCIe/PCIeCommon.h deleted file mode 100644 index 4f131ea58..000000000 --- a/src/comms/PCIe/PCIeCommon.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef PCIECOMMON_H -#define PCIECOMMON_H - -#include "limesuite/IComms.h" -#include "LMS64CProtocol.h" -#include "LitePCIe.h" - -using namespace lime; - -/** @brief An abstract class for interfacing with Control/Status registers (CSR) of a PCIe device. */ -class PCIE_CSR_Pipe : public ISerialPort -{ - public: - explicit PCIE_CSR_Pipe(std::shared_ptr port); - virtual int Write(const uint8_t* data, size_t length, int timeout_ms) override; - virtual int Read(uint8_t* data, size_t length, int timeout_ms) override; - - protected: - std::shared_ptr port; -}; - -/** @brief A class for communicating with a device's LMS7002M chip over a PCIe interface. */ -class LMS64C_LMS7002M_Over_PCIe : public lime::IComms -{ - public: - LMS64C_LMS7002M_Over_PCIe(std::shared_ptr dataPort); - virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - - private: - PCIE_CSR_Pipe pipe; -}; - -/** @brief A class for communicating with a device's FPGA over a PCIe interface. */ -class LMS64C_FPGA_Over_PCIe : public lime::IComms -{ - public: - LMS64C_FPGA_Over_PCIe(std::shared_ptr dataPort); - - virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; - - virtual int CustomParameterWrite(const std::vector& parameters) override; - virtual int CustomParameterRead(std::vector& parameters) override; - - virtual int ProgramWrite( - const char* data, size_t length, int prog_mode, int target, ProgressCallback callback = nullptr) override; - - virtual int MemoryWrite(uint32_t address, const void* data, uint32_t dataLength) override; - virtual int MemoryRead(uint32_t address, void* data, uint32_t dataLength) override; - - private: - PCIE_CSR_Pipe pipe; -}; - -#endif // PCIECOMMON_H \ No newline at end of file diff --git a/src/tests/comms/PCIe/PCIE_CSR_PipeTest.cpp b/src/tests/comms/PCIe/PCIE_CSR_PipeTest.cpp index 3d0bbb609..0d7f3b019 100644 --- a/src/tests/comms/PCIe/PCIE_CSR_PipeTest.cpp +++ b/src/tests/comms/PCIe/PCIE_CSR_PipeTest.cpp @@ -2,7 +2,7 @@ #include #include "LitePCIeMock.h" -#include "PCIeCommon.h" +#include "PCIE_CSR_Pipe.h" #include "LMS64CProtocol.h" using namespace lime; From 0cc5e94c7c0ef1d2929555e7abd3e5b08dc40bfb Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 19 Dec 2023 16:55:35 +0200 Subject: [PATCH 03/46] Document a few functions --- src/CDCM6208/CDCM6208_Dev.h | 6 ++++++ src/comms/PCIe/PCIE_CSR_Pipe.h | 9 ++++++++- src/protocols/ISerialPort.h | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/CDCM6208/CDCM6208_Dev.h b/src/CDCM6208/CDCM6208_Dev.h index b49b6d429..ae8f9f64d 100644 --- a/src/CDCM6208/CDCM6208_Dev.h +++ b/src/CDCM6208/CDCM6208_Dev.h @@ -79,6 +79,12 @@ struct CDCM_Outputs { class LIME_API CDCM_Dev { public: + /** + @brief Constructs a new CDCM_Dev object. + + @param comms The communications path to use. + @param SPI_BASE_ADDR The base address for the API interface. + */ CDCM_Dev(std::shared_ptr comms, uint16_t SPI_BASE_ADDR); int Init(double primaryFreq, double secondaryFreq); diff --git a/src/comms/PCIe/PCIE_CSR_Pipe.h b/src/comms/PCIe/PCIE_CSR_Pipe.h index 22dcf4167..d9cc51bc7 100644 --- a/src/comms/PCIe/PCIE_CSR_Pipe.h +++ b/src/comms/PCIe/PCIE_CSR_Pipe.h @@ -5,12 +5,17 @@ #include "LMS64CProtocol.h" #include "LitePCIe.h" -using namespace lime; +namespace lime { /** @brief An abstract class for interfacing with Control/Status registers (CSR) of a PCIe device. */ class PCIE_CSR_Pipe : public ISerialPort { public: + /** + @brief Constructs a new PCIE_CSR_Pipe object. + + @param port The LitePCIe port to use with this pipe. + */ explicit PCIE_CSR_Pipe(std::shared_ptr port); virtual int Write(const uint8_t* data, size_t length, int timeout_ms) override; virtual int Read(uint8_t* data, size_t length, int timeout_ms) override; @@ -19,4 +24,6 @@ class PCIE_CSR_Pipe : public ISerialPort std::shared_ptr port; }; +} // namespace lime + #endif // PCIE_CSR_PIPE_H diff --git a/src/protocols/ISerialPort.h b/src/protocols/ISerialPort.h index 0b1ce4c96..35c627058 100644 --- a/src/protocols/ISerialPort.h +++ b/src/protocols/ISerialPort.h @@ -10,7 +10,24 @@ namespace lime { class ISerialPort { public: + /** + @brief Writes the specified data into whatever device is implementing this interface. + + @param data The data to write to the device. + @param length The length of the data. + @param timeout_ms The timeout (in ms) to wait until the transfer times out. + @return int The amount of bytes written. + */ virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) = 0; + + /** + @brief Reads some data from the device. + + @param data The buffer in which to store the read data. + @param length The length of the data to store. + @param timeout_ms The timeout (in ms) to wait until the transfer times out. + @return int The amount of bytes read. + */ virtual int Read(uint8_t* data, std::size_t length, int timeout_ms) = 0; }; From 1371c1bbeab796e7623edc6e8faab9506ab25a3f Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 20 Dec 2023 10:18:08 +0200 Subject: [PATCH 04/46] Split TRXLooper_PCIE classes out into their own files and document AvgRmsCounter --- src/comms/PCIe/AvgRmsCounter.cpp | 58 +++++++ src/comms/PCIe/AvgRmsCounter.h | 52 +++++++ src/comms/PCIe/CMakeLists.txt | 1 + src/comms/PCIe/TRXLooper_PCIE.cpp | 249 +++--------------------------- src/comms/PCIe/TxBufferManager.h | 150 ++++++++++++++++++ 5 files changed, 282 insertions(+), 228 deletions(-) create mode 100644 src/comms/PCIe/AvgRmsCounter.cpp create mode 100644 src/comms/PCIe/AvgRmsCounter.h create mode 100644 src/comms/PCIe/TxBufferManager.h diff --git a/src/comms/PCIe/AvgRmsCounter.cpp b/src/comms/PCIe/AvgRmsCounter.cpp new file mode 100644 index 000000000..dd749f209 --- /dev/null +++ b/src/comms/PCIe/AvgRmsCounter.cpp @@ -0,0 +1,58 @@ +#include "AvgRmsCounter.h" + +#include + +using namespace lime; + +AvgRmsCounter::AvgRmsCounter() + : counter(0) + , avgAccumulator(0) + , rmsAccumulator(0) + , min(1e16) + , max(1e-16){}; + +void AvgRmsCounter::Add(double value) +{ + avgAccumulator += value; + rmsAccumulator += value * value; + ++counter; + + if (value < min) + { + min = value; + } + + if (value > max) + { + max = value; + } +} + +void AvgRmsCounter::GetResult(double& avg, double& rms) +{ + if (counter == 0) + { + return; + } + + avg = avgAccumulator / counter; + rms = std::sqrt(rmsAccumulator / counter); + + avgAccumulator = 0; + rmsAccumulator = 0; + counter = 0; +} + +double AvgRmsCounter::Min() +{ + auto temp = min; + min = 1e16; + return temp; +} + +double AvgRmsCounter::Max() +{ + auto temp = max; + max = 1e-16; + return temp; +} diff --git a/src/comms/PCIe/AvgRmsCounter.h b/src/comms/PCIe/AvgRmsCounter.h new file mode 100644 index 000000000..737e89f5e --- /dev/null +++ b/src/comms/PCIe/AvgRmsCounter.h @@ -0,0 +1,52 @@ +#ifndef LIME_AVGRMSCOUNTER_H +#define LIME_AVGRMSCOUNTER_H + +#include + +namespace lime { + +/** @brief A helper class for calculating the Average and the Root Mean Square */ +class AvgRmsCounter +{ + public: + AvgRmsCounter(); + + /** + @brief Adds the given value to the accumulators. + + @param value The value to add. + */ + void Add(double value); + + /** + @brief Gets the results of the counters and resets them. + + @param[out] avg The average of all the submitted numbers. + @param[out] rms The Root Mean Square Average of all the submitted numbers. + */ + void GetResult(double& avg, double& rms); + + /** + @brief Gets the current minimum value and resets it. + + @return double The minimum value recorded. + */ + double Min(); + + /** + @brief Gets the current maximum value and resets it. + + @return double The maximum value recorded. + */ + double Max(); + private: + int32_t counter; + double avgAccumulator; + double rmsAccumulator; + double min; + double max; +}; + +} // namespace lime + +#endif // LIME_AVGRMSCOUNTER_H \ No newline at end of file diff --git a/src/comms/PCIe/CMakeLists.txt b/src/comms/PCIe/CMakeLists.txt index d3ded6092..51bce0518 100644 --- a/src/comms/PCIe/CMakeLists.txt +++ b/src/comms/PCIe/CMakeLists.txt @@ -4,6 +4,7 @@ set(THIS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/comms/PCIe) set(COMMS_LITE_PCIE_SOURCES + ${THIS_SOURCE_DIR}/AvgRmsCounter.cpp ${THIS_SOURCE_DIR}/LMS64C_FPGA_Over_PCIe.cpp ${THIS_SOURCE_DIR}/LMS64C_LMS7002M_Over_PCIe.cpp ${THIS_SOURCE_DIR}/LitePCIe.cpp diff --git a/src/comms/PCIe/TRXLooper_PCIE.cpp b/src/comms/PCIe/TRXLooper_PCIE.cpp index 2e445f8a5..67ab61bff 100644 --- a/src/comms/PCIe/TRXLooper_PCIE.cpp +++ b/src/comms/PCIe/TRXLooper_PCIE.cpp @@ -1,24 +1,28 @@ -#include -#include "FPGA_common.h" -#include "limesuite/LMS7002M.h" -#include -#include "Logger.h" -#include -#include -#include +#include "TRXLooper_PCIE.h" + +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include #include +#include -#include "TRXLooper_PCIE.h" -#include "limesuite/SDRDevice.h" -#include "LitePCIe.h" -#include "Profiler.h" +#include "AvgRmsCounter.h" +#include "BufferInterleaving.h" #include "DataPacket.h" -#include "SamplesPacket.h" +#include "FPGA_common.h" +#include "LitePCIe.h" #include "limesuite/commonTypes.h" +#include "limesuite/complex.h" +#include "limesuite/LMS7002M.h" +#include "limesuite/SDRDevice.h" +#include "Logger.h" +#include "MemoryPool.h" +#include "TxBufferManager.h" static bool showStats = false; static const int statsPeriod_ms = 1000; // at 122.88 MHz MIMO, fpga tx pkt counter overflows every 272ms @@ -28,59 +32,6 @@ using namespace std::chrono; namespace lime { -/** @brief A helper class for calculating the Average and the Root Mean Square */ -class AvgRmsCounter -{ - public: - AvgRmsCounter() - : counter(0) - , avgAccumulator(0) - , rmsAccumulator(0) - , min(1e16) - , max(1e-16){}; - - void Add(double value) - { - avgAccumulator += value; - rmsAccumulator += value * value; - ++counter; - if (value < min) - min = value; - if (value > max) - max = value; - } - void GetResult(double& avg, double& rms) - { - if (counter == 0) - return; - avg = avgAccumulator / (double)counter; - rms = sqrt(rmsAccumulator / (double)counter); - avgAccumulator = 0; - rmsAccumulator = 0; - counter = 0; - } - - double Min() - { - auto temp = min; - min = 1e16; - return temp; - } - double Max() - { - auto temp = max; - max = 1e-16; - return temp; - } - - private: - int32_t counter; - double avgAccumulator; - double rmsAccumulator; - double min; - double max; -}; - static inline int64_t ts_to_us(int64_t fs, int64_t ts) { int n, r; @@ -123,8 +74,7 @@ void TRXLooper_PCIE::Setup(const SDRDevice::StreamConfig& config) if (combinedSampleRate != 0) { batchSize = combinedSampleRate / 61.44e6; - batchSize = std::min(batchSize, 4); - batchSize = std::max(1, batchSize); + batchSize = clamp(batchSize, 1, 4); } if (config.hintSampleRate) @@ -213,163 +163,6 @@ int TRXLooper_PCIE::TxSetup() return 0; } -/** - @brief A class for managing the transmission buffer for the PCIe transfer. - @tparam T The samples packet input type. - */ -template class TxBufferManager -{ - public: - TxBufferManager(bool mimo, - bool compressed, - uint32_t maxSamplesInPkt, - uint32_t maxPacketsInBatch, - SDRDevice::StreamConfig::DataFormat inputFormat) - : header(nullptr) - , payloadPtr(nullptr) - , mData(nullptr) - , bytesUsed(0) - , mCapacity(0) - , maxPacketsInBatch(maxPacketsInBatch) - , maxSamplesInPkt(maxSamplesInPkt) - , packetsCreated(0) - , payloadSize(0) - { - bytesForFrame = (compressed ? 3 : 4) * (mimo ? 2 : 1); - conversion.srcFormat = inputFormat; //SDRDevice::StreamConfig::DataFormat::F32; - conversion.destFormat = compressed ? SDRDevice::StreamConfig::DataFormat::I12 : SDRDevice::StreamConfig::DataFormat::I16; - conversion.channelCount = mimo ? 2 : 1; - maxPayloadSize = std::min(4080u, bytesForFrame * maxSamplesInPkt); - } - - void Reset(uint8_t* memPtr, uint32_t capacity) - { - packetsCreated = 0; - bytesUsed = 0; - mData = memPtr; - mCapacity = capacity; - memset(mData, 0, capacity); - header = reinterpret_cast(mData); - header->Clear(); - payloadSize = 0; - payloadPtr = (uint8_t*)header + sizeof(StreamHeader); - } - - inline bool hasSpace() const - { - const bool packetNotFull = payloadSize < maxPayloadSize; - const bool spaceAvailable = mCapacity - bytesUsed > sizeof(StreamHeader); - return packetNotFull && spaceAvailable; - } - - inline bool consume(T* src) - { - bool sendBuffer = false; - while (!src->empty()) - { - if (payloadSize >= maxPayloadSize || payloadSize == maxSamplesInPkt * bytesForFrame) - { - header = reinterpret_cast(mData + bytesUsed); - header->Clear(); - payloadPtr = (uint8_t*)header + sizeof(StreamHeader); - payloadSize = 0; - } - - header->ignoreTimestamp(!src->useTimestamp); - if (payloadSize == 0) - { - ++packetsCreated; - header->counter = src->timestamp; - bytesUsed += sizeof(StreamHeader); - } - const int freeSpace = std::min(maxPayloadSize - payloadSize, mCapacity - bytesUsed - 16); - uint32_t transferCount = std::min(freeSpace / bytesForFrame, src->size()); - transferCount = std::min(transferCount, maxSamplesInPkt); - if (transferCount > 0) - { - int samplesDataSize = Interleave(src, transferCount, conversion, payloadPtr); - payloadPtr = payloadPtr + samplesDataSize; - payloadSize += samplesDataSize; - bytesUsed += samplesDataSize; - header->SetPayloadSize(payloadSize); - assert(payloadSize > 0); - assert(payloadSize <= maxPayloadSize); - } - else - sendBuffer = true; - - if (packetsCreated >= maxPacketsInBatch && !hasSpace()) - sendBuffer = true; - - if (bytesUsed >= mCapacity - sizeof(StreamHeader)) - sendBuffer = true; // not enough space for more packets, need to flush - if ((uint64_t)payloadPtr & 0xF) - sendBuffer = true; // next packets payload memory is not suitably aligned for vectorized filling - - if (sendBuffer) - { - const int busWidthBytes = 16; - int extraBytes = bytesUsed % busWidthBytes; - if (extraBytes != 0) - { - //printf("Patch buffer, bytes %i, extra: %i, last payload: %i\n", bytesUsed, extraBytes, payloadSize); - // patch last packet so that whole buffer size would be multiple of bus width - int padding = busWidthBytes - extraBytes; - memset(payloadPtr, 0, padding); - payloadSize += padding; - bytesUsed += padding; - header->SetPayloadSize(payloadSize); - //printf("Patch buffer, bytes %i, last payload: %i\n", bytesUsed, payloadSize); - } - break; - } - } - if (!hasSpace()) - return true; - return src->flush || sendBuffer; - } - - inline int size() const { return bytesUsed; }; - inline uint8_t* data() const { return mData; }; - inline int packetCount() const { return packetsCreated; }; - - private: - DataConversion conversion; - StreamHeader* header; - uint8_t* payloadPtr; - uint8_t* mData; - uint32_t bytesUsed; - uint32_t mCapacity; - uint32_t maxPacketsInBatch; - uint32_t maxSamplesInPkt; - uint32_t maxPayloadSize; - uint16_t packetsCreated; - uint16_t payloadSize; - uint8_t bytesForFrame; -}; - -void FPGATxState(FPGA* fpga) -{ - uint32_t words[4]; - for (int i = 0; i < 5; ++i) - { - uint64_t pendingTxTS = 0; - const uint32_t addrs[4] = { 0x61u + i * 4, 0x62u + i * 4, 0x63u + i * 4, 0x64u + i * 4 }; - fpga->ReadRegisters(addrs, words, 4); - pendingTxTS |= words[0]; - pendingTxTS |= words[1] << 16; - pendingTxTS |= (uint64_t)words[2] << 32; - pendingTxTS |= (uint64_t)words[3] << 48; - if (i < 4) - printf("Buf%i: %08lX\n", i, pendingTxTS); - else - printf("Rx: %08lX\n", pendingTxTS); - } - - uint16_t bufs = fpga->ReadRegister(0x0075); - printf("currentIndex: %i, ready: %0X\n", bufs & 0xF, (bufs >> 4) & 0xF); -} - void TRXLooper_PCIE::TransmitPacketsLoop() { const bool mimo = std::max(mConfig.txCount, mConfig.rxCount) > 1; diff --git a/src/comms/PCIe/TxBufferManager.h b/src/comms/PCIe/TxBufferManager.h new file mode 100644 index 000000000..47c2d7251 --- /dev/null +++ b/src/comms/PCIe/TxBufferManager.h @@ -0,0 +1,150 @@ +#ifndef LIME_TXBUFFERMANAGER_H +#define LIME_TXBUFFERMANAGER_H + +#include +#include + +#include "BufferInterleaving.h" +#include "limesuite/SDRDevice.h" +#include "protocols/DataPacket.h" + +namespace lime { + +/** + @brief A class for managing the transmission buffer for the PCIe transfer. + @tparam T The samples packet input type. + */ +template class TxBufferManager +{ + public: + TxBufferManager(bool mimo, + bool compressed, + uint32_t maxSamplesInPkt, + uint32_t maxPacketsInBatch, + SDRDevice::StreamConfig::DataFormat inputFormat) + : header(nullptr) + , payloadPtr(nullptr) + , mData(nullptr) + , bytesUsed(0) + , mCapacity(0) + , maxPacketsInBatch(maxPacketsInBatch) + , maxSamplesInPkt(maxSamplesInPkt) + , packetsCreated(0) + , payloadSize(0) + { + bytesForFrame = (compressed ? 3 : 4) * (mimo ? 2 : 1); + conversion.srcFormat = inputFormat; //SDRDevice::StreamConfig::DataFormat::F32; + conversion.destFormat = compressed ? SDRDevice::StreamConfig::DataFormat::I12 : SDRDevice::StreamConfig::DataFormat::I16; + conversion.channelCount = mimo ? 2 : 1; + maxPayloadSize = std::min(4080u, bytesForFrame * maxSamplesInPkt); + } + + void Reset(uint8_t* memPtr, uint32_t capacity) + { + packetsCreated = 0; + bytesUsed = 0; + mData = memPtr; + mCapacity = capacity; + std::memset(mData, 0, capacity); + header = reinterpret_cast(mData); + header->Clear(); + payloadSize = 0; + payloadPtr = reinterpret_cast(header) + sizeof(StreamHeader); + } + + inline bool hasSpace() const + { + const bool packetNotFull = payloadSize < maxPayloadSize; + const bool spaceAvailable = mCapacity - bytesUsed > sizeof(StreamHeader); + return packetNotFull && spaceAvailable; + } + + inline bool consume(T* src) + { + bool sendBuffer = false; + while (!src->empty()) + { + if (payloadSize >= maxPayloadSize || payloadSize == maxSamplesInPkt * bytesForFrame) + { + header = reinterpret_cast(mData + bytesUsed); + header->Clear(); + payloadPtr = reinterpret_cast(header) + sizeof(StreamHeader); + payloadSize = 0; + } + + header->ignoreTimestamp(!src->useTimestamp); + if (payloadSize == 0) + { + ++packetsCreated; + header->counter = src->timestamp; + bytesUsed += sizeof(StreamHeader); + } + const int freeSpace = std::min(maxPayloadSize - payloadSize, mCapacity - bytesUsed - 16); + uint32_t transferCount = std::min(freeSpace / bytesForFrame, src->size()); + transferCount = std::min(transferCount, maxSamplesInPkt); + if (transferCount > 0) + { + int samplesDataSize = Interleave(src, transferCount, conversion, payloadPtr); + payloadPtr = payloadPtr + samplesDataSize; + payloadSize += samplesDataSize; + bytesUsed += samplesDataSize; + header->SetPayloadSize(payloadSize); + assert(payloadSize > 0); + assert(payloadSize <= maxPayloadSize); + } + else + sendBuffer = true; + + if (packetsCreated >= maxPacketsInBatch && !hasSpace()) + sendBuffer = true; + + if (bytesUsed >= mCapacity - sizeof(StreamHeader)) + sendBuffer = true; // not enough space for more packets, need to flush + if ((uint64_t)payloadPtr & 0xF) + sendBuffer = true; // next packets payload memory is not suitably aligned for vectorized filling + + if (sendBuffer) + { + const int busWidthBytes = 16; + int extraBytes = bytesUsed % busWidthBytes; + if (extraBytes != 0) + { + //printf("Patch buffer, bytes %i, extra: %i, last payload: %i\n", bytesUsed, extraBytes, payloadSize); + // patch last packet so that whole buffer size would be multiple of bus width + int padding = busWidthBytes - extraBytes; + std::memset(payloadPtr, 0, padding); + payloadSize += padding; + bytesUsed += padding; + header->SetPayloadSize(payloadSize); + //printf("Patch buffer, bytes %i, last payload: %i\n", bytesUsed, payloadSize); + } + break; + } + } + if (!hasSpace()) + return true; + return src->flush || sendBuffer; + } + + inline int size() const { return bytesUsed; }; + inline uint8_t* data() const { return mData; }; + inline int packetCount() const { return packetsCreated; }; + + private: + DataConversion conversion; + StreamHeader* header; + uint8_t* payloadPtr; + uint8_t* mData; + uint32_t bytesUsed; + uint32_t mCapacity; + uint32_t maxPacketsInBatch; + uint32_t maxSamplesInPkt; + uint32_t maxPayloadSize; + uint16_t packetsCreated; + uint16_t payloadSize; + uint8_t bytesForFrame; +}; + +} // namespace lime + +#endif // LIME_TXBUFFERMANAGER_H \ No newline at end of file From b5cc9e23daf0dfb49f5547f722a112d813b59086 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 20 Dec 2023 12:36:26 +0200 Subject: [PATCH 05/46] Document USB Generic --- src/comms/USB/FT601/FT601.cpp | 2 +- src/comms/USB/FT601/FT601.h | 10 ++++- src/comms/USB/FX3/FX3.cpp | 2 +- src/comms/USB/FX3/FX3.h | 6 ++- src/comms/USB/USBGeneric.cpp | 2 +- src/comms/USB/USBGeneric.h | 76 ++++++++++++++++++++++++++++++++--- 6 files changed, 88 insertions(+), 10 deletions(-) diff --git a/src/comms/USB/FT601/FT601.cpp b/src/comms/USB/FT601/FT601.cpp index 8891ffdc1..90892ffc3 100644 --- a/src/comms/USB/FT601/FT601.cpp +++ b/src/comms/USB/FT601/FT601.cpp @@ -172,7 +172,7 @@ int FT601::BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPointAddr) return index; } -bool FT601::WaitForXfer(int contextHandle, uint32_t timeout_ms) +bool FT601::WaitForXfer(int contextHandle, int32_t timeout_ms) { if (contextHandle >= 0 && contexts[contextHandle].used == true) { diff --git a/src/comms/USB/FT601/FT601.h b/src/comms/USB/FT601/FT601.h index 2070a7b06..bdb295570 100644 --- a/src/comms/USB/FT601/FT601.h +++ b/src/comms/USB/FT601/FT601.h @@ -13,6 +13,10 @@ namespace lime { class FT601 : public USBGeneric { public: + /** + @brief Constructs the class for communicating with the FT601 controller. + @param usbContext The USB context to use for the communication. + */ FT601(void* usbContext = nullptr); virtual ~FT601(); @@ -34,11 +38,15 @@ class FT601 : public USBGeneric #ifndef __unix__ virtual int BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPointAddr) override; - virtual bool WaitForXfer(int contextHandle, uint32_t timeout_ms) override; + virtual bool WaitForXfer(int contextHandle, int32_t timeout_ms) override; virtual int FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) override; virtual void AbortEndpointXfers(uint8_t endPointAddr) override; #endif + /** + @brief Resets the stream buffers of the device. + @return int Status of the operation (0 - success; -1 - failure). + */ int ResetStreamBuffers(); protected: diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index 31f5418e4..9f755fadf 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -59,7 +59,7 @@ int FX3::BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPointAddr) return index; } -bool FX3::WaitForXfer(int contextHandle, uint32_t timeout_ms) +bool FX3::WaitForXfer(int contextHandle, int32_t timeout_ms) { if (contextHandle >= 0 && contexts[contextHandle].used == true) { diff --git a/src/comms/USB/FX3/FX3.h b/src/comms/USB/FX3/FX3.h index e4d6f792c..0b901634f 100644 --- a/src/comms/USB/FX3/FX3.h +++ b/src/comms/USB/FX3/FX3.h @@ -15,6 +15,10 @@ namespace lime { class FX3 : public USBGeneric { public: + /** + @brief Constructs the class for communicating with the FX3 controller. + @param usbContext The USB context to use for the communication. + */ FX3(void* usbContext = nullptr); virtual ~FX3(); @@ -23,7 +27,7 @@ class FX3 : public USBGeneric #ifndef __unix__ virtual int BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPointAddr) override; - virtual bool WaitForXfer(int contextHandle, uint32_t timeout_ms) override; + virtual bool WaitForXfer(int contextHandle, int32_t timeout_ms) override; virtual int FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) override; virtual void AbortEndpointXfers(uint8_t endPointAddr) override; #endif diff --git a/src/comms/USB/USBGeneric.cpp b/src/comms/USB/USBGeneric.cpp index c215df222..d324b161e 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -294,7 +294,7 @@ int USBGeneric::BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPoint #endif } -bool USBGeneric::WaitForXfer(int contextHandle, uint32_t timeout_ms) +bool USBGeneric::WaitForXfer(int contextHandle, int32_t timeout_ms) { #ifdef __unix__ if (contextHandle >= 0 && contexts[contextHandle].used == true) diff --git a/src/comms/USB/USBGeneric.h b/src/comms/USB/USBGeneric.h index 8c9cf4c97..98eec81a1 100644 --- a/src/comms/USB/USBGeneric.h +++ b/src/comms/USB/USBGeneric.h @@ -23,24 +23,90 @@ class USBGeneric { public: USBGeneric() = delete; + + /** + @brief Construct a new USBGeneric object. + + If this is the first object of this kind being constructed on a UNIX system + it also creates the thread to handle USB events. + @param usbContext The USB context to use. + */ USBGeneric(void* usbContext); virtual ~USBGeneric(); - static const int32_t defaultTimeout = 1000; - + static constexpr int32_t defaultTimeout = 1000; ///< The default timeout to use if none is specified. + + /** + @brief Connects to a given USB device. + @param vid The vendor ID of the device. + @param pid The prduct ID of the device. + @param serial The serial number of the device. + @return bool The status of the operation (true on success). + */ virtual bool Connect(uint16_t vid, uint16_t pid, const std::string& serial = ""); + + /** + @brief Returns whether this instance is connected to a device. + @return bool The state of the connection (true = connected). + */ virtual bool IsConnected(); + + /** @brief Disconnects from the USB device. */ virtual void Disconnect(); - // return actual number of bytes transferred + /** + @brief Transfers data using the bulk transfer USB protocol. + @param endPoint The address to use for the transfer. + @param data The pointer to the data buffer. + @param length The length of data being transferred. + @param timeout_ms The amount of time to wait (in ms) until the transfer is considered failed. + @return int32_t Actual number of bytes transferred. + */ virtual int32_t BulkTransfer(uint8_t endPoint, uint8_t* data, int length, int32_t timeout_ms = defaultTimeout); - // return actual number of bytes transferred + /** + @brief Transfers data using the control transfer USB protocol. + @param requestType The request type to use in the setup packet. + @param request The type of request being made. + @param value The value of the request being made. + @param index The index of the request being made. + @param data The pointer to the data buffer. + @param length The length of data being transferred. + @param timeout_ms The amount of time to wait (in ms) until the transfer is considered failed. + @return int32_t Actual number of bytes transferred. + */ virtual int32_t ControlTransfer( int requestType, int request, int value, int index, uint8_t* data, uint32_t length, int32_t timeout_ms = defaultTimeout); + /** + @brief Begins an asynchronous data transfer. + @param buffer The pointer to the data buffer. + @param length The length of the data being transferred. + @param endPointAddr The endpoint address to use for the transfer. + @return int The handle of the transfer context to pass to WaitForXfer and FinishDataXfer functions. + */ virtual int BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPointAddr); - virtual bool WaitForXfer(int contextHandle, uint32_t timeout_ms); + + /** + @brief Waits until an asynchronous data transfer finishes. + @param contextHandle The context handle to wait for (received from BeginDataXfer). + @param timeout_ms The timeout (in ms) to wait for the transfer. + @return bool Indication whether the transfer is finished or not (true = finished). + */ + virtual bool WaitForXfer(int contextHandle, int32_t timeout_ms = defaultTimeout); + + /** + @brief Finishes an asynchronous data transfer. + @param buffer The pointer to the data buffer. + @param length The length of the data being transferred. + @param contextHandle The handle of the transfer (received from BeginDataXfer). + @return int The amount of bytes transferred in the transfer. + */ virtual int FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle); + + /** + @brief Aborts all current asynchronous transfers at the given endpoint. + @param endPointAddr The endpoint to abort all transfers from. + */ virtual void AbortEndpointXfers(uint8_t endPointAddr); protected: From 568a223a709be217311e3cb6366e9ed101dbb0eb Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 20 Dec 2023 12:36:51 +0200 Subject: [PATCH 06/46] Clean up Device REgistry and Handle documentation --- src/include/limesuite/DeviceHandle.h | 4 +++- src/include/limesuite/DeviceRegistry.h | 28 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/include/limesuite/DeviceHandle.h b/src/include/limesuite/DeviceHandle.h index 151c88311..a798f3982 100644 --- a/src/include/limesuite/DeviceHandle.h +++ b/src/include/limesuite/DeviceHandle.h @@ -45,12 +45,14 @@ class LIME_API DeviceHandle /*! * Serialize this connection handle into a string format. * This string format can be used to represent the handle. + * + * @return The handle in string format. */ std::string Serialize(void) const; /*! * Get a displayable string for this handle. - * @return a string that may be printed + * @return A string that may be printed. */ std::string ToString(void) const; }; diff --git a/src/include/limesuite/DeviceRegistry.h b/src/include/limesuite/DeviceRegistry.h index 9a56d3743..3ae87212f 100644 --- a/src/include/limesuite/DeviceRegistry.h +++ b/src/include/limesuite/DeviceRegistry.h @@ -21,26 +21,30 @@ class LIME_API DeviceRegistry public: /*! * Discovery identifiers that can be used to create a connection. - * The hint may contain a connection type, serial number, ip address, etc. - * \param hint an optional connection handle with some fields filled-in - * \return a list of handles which can be used to make a connection + * The hint may contain a connection type, serial number, IP address, etc. + * \param hint An optional connection handle with some fields filled-in + * \return A list of handles which can be used to make a connection */ static std::vector enumerate(const DeviceHandle& hint = DeviceHandle()); /*! * Create a connection from an identifying handle. - * Return a null pointer when no factories are available. - * \param handle a connection handle with fields filled-in - * \return a pointer to a connection instance (or null) + * Returns a null pointer when no factories are available. + * \param handle A connection handle with fields filled-in + * \return A pointer to a connection instance (or null) */ static SDRDevice* makeDevice(const DeviceHandle& handle); /*! * Free an connection created by makeConnection(). + * \param conn The connection to free. */ static void freeDevice(SDRDevice* conn); - //! Get a list of available registry entry modules by name + /*! + * Get a list of available registry entry modules by name. + * \return std::vector The list of available registry modules. + */ static std::vector moduleNames(void); }; @@ -64,6 +68,8 @@ class LIME_API DeviceRegistryEntry * registers it into the connection registry. * The name describes the device board type, * that should be unique to the entry instance. + * + * \param name The name of the device entry. */ DeviceRegistryEntry(const std::string& name); @@ -74,15 +80,15 @@ class LIME_API DeviceRegistryEntry * A discovery function takes a connection handle hint * and returns a list of identifiers that can be used * to create connection with makeConnection(). - * \param hint an optional connection handle with some fields filled-in - * \return a list of handles which can be used to make a connection + * \param hint An optional connection handle with some fields filled-in. + * \return A list of handles which can be used to make a connection. */ virtual std::vector enumerate(const DeviceHandle& hint) = 0; /*! * A factory function creates a SDRDevice from a device handle. - * \param handle a device handle with fields filled-in - * \return a pointer to a SDRDevice instance + * \param handle A device handle with fields filled-in. + * \return A pointer to a SDRDevice instance. */ virtual SDRDevice* make(const DeviceHandle& handle) = 0; From 288567d250083b88b90f91097a1ac68a894e9755 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 20 Dec 2023 12:36:59 +0200 Subject: [PATCH 07/46] Document DeltaVariable --- src/include/limesuite/commonTypes.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/include/limesuite/commonTypes.h b/src/include/limesuite/commonTypes.h index e4951cea3..ae4761002 100644 --- a/src/include/limesuite/commonTypes.h +++ b/src/include/limesuite/commonTypes.h @@ -21,13 +21,39 @@ struct Range { template class DeltaVariable { public: + /** + @brief Construct a new DeltaVariable object. + @param init The initial value of the variable. + */ DeltaVariable(T init) : mValue(init) , mLastValue(0){}; + + /** + @brief Sets the value of the delta variable. + @param val The value to set the delta variable to. + */ void set(T val) { mValue = val; } + + /** + @brief Adds the given value to the delta variable + @param val The value to add to the delta variable. + */ void add(T val) { mValue += val; } - T delta() { return mValue - mLastValue; } // value change since last reset + + /** + @brief Gets the difference between the value at last reset and current value. + @return T The delta between the last time the delta variable was reset and the current value. + */ + T delta() const { return mValue - mLastValue; } + + /** + @brief Gets the current value of the delta variable. + @return T The current stored value of the delta variable. + */ T value() const { return mValue; } + + /** @brief Resets the delta variable to start measuring from its current value. */ void checkpoint() { mLastValue = mValue; } private: From 84e9477d39650040f310532b443d5fac8e691734 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 21 Dec 2023 11:40:07 +0200 Subject: [PATCH 08/46] Add SlaveSelectShim documentation --- src/boards/LimeSDR_X3/SlaveSelectShim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/boards/LimeSDR_X3/SlaveSelectShim.h b/src/boards/LimeSDR_X3/SlaveSelectShim.h index 8b2656a53..2be4ab2d0 100644 --- a/src/boards/LimeSDR_X3/SlaveSelectShim.h +++ b/src/boards/LimeSDR_X3/SlaveSelectShim.h @@ -10,9 +10,19 @@ namespace lime { class SlaveSelectShim : public ISPI { public: + /** + @brief Construct a new Slave Select Shim object + @param comms The communications interface to use. + @param slaveId The ID of the slave for this shim. + */ SlaveSelectShim(std::shared_ptr comms, uint32_t slaveId); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; + + /** + @brief Send the reset device command to the device under this shim. + @return int The success status of the operation (0 on success), + */ virtual int ResetDevice(); private: From 93fec50cc659811968b59cc01458c3bd3039c40b Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 21 Dec 2023 11:40:43 +0200 Subject: [PATCH 09/46] Add USB Pipe and USBTransferContext documentation --- src/boards/LimeSDR/USB_CSR_Pipe_SDR.h | 4 ++-- src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h | 4 ++-- src/comms/USB/FT601/USBTransferContext_FT601.cpp | 1 + src/comms/USB/FX3/USBTransferContext_FX3.cpp | 7 ++++++- src/comms/USB/USBGeneric.cpp | 16 ++++++++-------- src/comms/USB/USBTransferContext.cpp | 8 ++++++-- src/comms/USB/USBTransferContext.h | 2 +- src/comms/USB/USB_CSR_Pipe.h | 4 ++-- 8 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h b/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h index 92a70a121..8da59dfd9 100644 --- a/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h +++ b/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h @@ -14,8 +14,8 @@ class USB_CSR_Pipe_SDR : public USB_CSR_Pipe public: explicit USB_CSR_Pipe_SDR(FX3& port); - virtual int Write(const uint8_t* data, size_t length, int timeout_ms) override; - virtual int Read(uint8_t* data, size_t length, int timeout_ms) override; + virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) override; + virtual int Read(uint8_t* data, std::size_t length, int timeout_ms) override; protected: FX3& port; diff --git a/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h b/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h index e46e567ca..ce57dd7d0 100644 --- a/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h +++ b/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h @@ -12,8 +12,8 @@ class USB_CSR_Pipe_Mini : public USB_CSR_Pipe public: explicit USB_CSR_Pipe_Mini(FT601& port); - virtual int Write(const uint8_t* data, size_t length, int timeout_ms) override; - virtual int Read(uint8_t* data, size_t length, int timeout_ms) override; + virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) override; + virtual int Read(uint8_t* data, std::size_t length, int timeout_ms) override; protected: FT601& port; diff --git a/src/comms/USB/FT601/USBTransferContext_FT601.cpp b/src/comms/USB/FT601/USBTransferContext_FT601.cpp index 05c9e5319..2bd520e41 100644 --- a/src/comms/USB/FT601/USBTransferContext_FT601.cpp +++ b/src/comms/USB/FT601/USBTransferContext_FT601.cpp @@ -2,6 +2,7 @@ using namespace lime; +/** @brief Constructs a new USBTransferContext_FT601 object */ USBTransferContext_FT601::USBTransferContext_FT601() : USBTransferContext() { diff --git a/src/comms/USB/FX3/USBTransferContext_FX3.cpp b/src/comms/USB/FX3/USBTransferContext_FX3.cpp index e6660313d..40d189816 100644 --- a/src/comms/USB/FX3/USBTransferContext_FX3.cpp +++ b/src/comms/USB/FX3/USBTransferContext_FX3.cpp @@ -22,9 +22,14 @@ USBTransferContext_FX3::~USBTransferContext_FX3() } #endif +/** + On Windows systems, resets the FX3 USB controller device. + + @return Opposite of `isTransferUsed`. + */ bool USBTransferContext_FX3::Reset() { - if (used) + if (isTransferUsed) { return false; } diff --git a/src/comms/USB/USBGeneric.cpp b/src/comms/USB/USBGeneric.cpp index d324b161e..30c2cef92 100644 --- a/src/comms/USB/USBGeneric.cpp +++ b/src/comms/USB/USBGeneric.cpp @@ -286,7 +286,7 @@ int USBGeneric::BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPoint if (status != 0) { printf("BEGIN DATA TRANSFER %s\n", libusb_error_name(status)); - contexts[i].used = false; + contexts[i].isTransferUsed = false; return -1; } @@ -297,7 +297,7 @@ int USBGeneric::BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPoint bool USBGeneric::WaitForXfer(int contextHandle, int32_t timeout_ms) { #ifdef __unix__ - if (contextHandle >= 0 && contexts[contextHandle].used == true) + if (contextHandle >= 0 && contexts[contextHandle].isTransferUsed == true) { // Blocking not to waste CPU std::unique_lock lck(contexts[contextHandle].transferLock); @@ -311,10 +311,10 @@ bool USBGeneric::WaitForXfer(int contextHandle, int32_t timeout_ms) int USBGeneric::FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) { #ifdef __unix__ - if (contextHandle >= 0 && contexts[contextHandle].used == true) + if (contextHandle >= 0 && contexts[contextHandle].isTransferUsed == true) { length = contexts[contextHandle].bytesXfered; - contexts[contextHandle].used = false; + contexts[contextHandle].isTransferUsed = false; contexts[contextHandle].Reset(); return length; } @@ -328,7 +328,7 @@ void USBGeneric::AbortEndpointXfers(uint8_t endPointAddr) #ifdef __unix__ for (int i = 0; i < USB_MAX_CONTEXTS; ++i) { - if (contexts[i].used && contexts[i].transfer->endpoint == endPointAddr) + if (contexts[i].isTransferUsed && contexts[i].transfer->endpoint == endPointAddr) { libusb_cancel_transfer(contexts[i].transfer); } @@ -346,7 +346,7 @@ int USBGeneric::GetUSBContextIndex() // Find not used context for (i = 0; i < USB_MAX_CONTEXTS; i++) { - if (!contexts[i].used) + if (!contexts[i].isTransferUsed) { contextFound = true; break; @@ -359,7 +359,7 @@ int USBGeneric::GetUSBContextIndex() return -1; } - contexts[i].used = true; + contexts[i].isTransferUsed = true; return i; } @@ -368,7 +368,7 @@ void USBGeneric::WaitForXfers(uint8_t endPointAddr) { for (int i = 0; i < USB_MAX_CONTEXTS; ++i) { - if (contexts[i].used && contexts[i].transfer->endpoint == endPointAddr) + if (contexts[i].isTransferUsed && contexts[i].transfer->endpoint == endPointAddr) { WaitForXfer(i, 250); FinishDataXfer(nullptr, 0, i); diff --git a/src/comms/USB/USBTransferContext.cpp b/src/comms/USB/USBTransferContext.cpp index 685416883..dd36b7b3d 100644 --- a/src/comms/USB/USBTransferContext.cpp +++ b/src/comms/USB/USBTransferContext.cpp @@ -3,7 +3,7 @@ using namespace lime; USBTransferContext::USBTransferContext() - : used(false) + : isTransferUsed(false) { #ifdef __unix__ transfer = libusb_alloc_transfer(0); @@ -22,7 +22,11 @@ USBTransferContext::~USBTransferContext() #endif } +/** + @brief Abstract method to override to reset the USB device. + @returns Opposite of `isTransferUsed`. + */ bool USBTransferContext::Reset() { - return !used; + return !isTransferUsed; } diff --git a/src/comms/USB/USBTransferContext.h b/src/comms/USB/USBTransferContext.h index e85086da9..541abbaba 100644 --- a/src/comms/USB/USBTransferContext.h +++ b/src/comms/USB/USBTransferContext.h @@ -26,7 +26,7 @@ class USBTransferContext virtual ~USBTransferContext(); virtual bool Reset(); - bool used; + bool isTransferUsed; ///< A flag to mark if this transfer is currently being used. #ifdef __unix__ libusb_transfer* transfer; diff --git a/src/comms/USB/USB_CSR_Pipe.h b/src/comms/USB/USB_CSR_Pipe.h index d5852df75..34520a1e5 100644 --- a/src/comms/USB/USB_CSR_Pipe.h +++ b/src/comms/USB/USB_CSR_Pipe.h @@ -11,8 +11,8 @@ class USB_CSR_Pipe : public ISerialPort public: explicit USB_CSR_Pipe(){}; - virtual int Write(const uint8_t* data, size_t length, int timeout_ms) override = 0; - virtual int Read(uint8_t* data, size_t length, int timeout_ms) override = 0; + virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) override = 0; + virtual int Read(uint8_t* data, std::size_t length, int timeout_ms) override = 0; }; } // namespace lime From 74d0f38664f324e6db2d191ff3fa59089b9c5f41 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 21 Dec 2023 13:00:04 +0200 Subject: [PATCH 10/46] Add missing command into the documentation generation documentation --- docs/setup/documentation.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/setup/documentation.rst b/docs/setup/documentation.rst index 9a779ab7f..4ce48899b 100644 --- a/docs/setup/documentation.rst +++ b/docs/setup/documentation.rst @@ -40,6 +40,7 @@ In the `docs` folder, located in the root folder of the repository, while in the cmake -S .. -B ../build # Generate the make file for the suite. make --no-print-directory -C ../build doc # Build Doxygen documentation breathe-apidoc --generate class --members --force --output-dir apidoc ../build/xml/ # Generate the class API pages + python add_undoc_members.py # Add a flag to add all undocumented members into the page make html # Generate the documentation itself .. important:: From 3724d62c6f0af83987ff745ae3c038af772a29cb Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 21 Dec 2023 13:02:47 +0200 Subject: [PATCH 11/46] Finish documenting all the connection classes --- src/boards/LimeSDR/USB_CSR_Pipe_SDR.h | 4 ++++ src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h | 4 ++++ src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h | 5 +++++ src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h | 5 +++++ src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h | 5 +++++ src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h | 4 ++++ src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h | 4 ++++ src/comms/PCIe/PCIE_CSR_Pipe.h | 4 ++-- src/comms/USB/LMS64C_FPGA_Over_USB.h | 4 ++++ src/comms/USB/LMS64C_LMS7002M_Over_USB.h | 4 ++++ src/comms/USB/USBEntry.h | 5 +++++ 11 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h b/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h index 8da59dfd9..1645dae16 100644 --- a/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h +++ b/src/boards/LimeSDR/USB_CSR_Pipe_SDR.h @@ -12,6 +12,10 @@ namespace lime { class USB_CSR_Pipe_SDR : public USB_CSR_Pipe { public: + /** + @brief Constructs a new USB_CSR_Pipe_SDR object + @param port The FX3 communications port to use. + */ explicit USB_CSR_Pipe_SDR(FX3& port); virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) override; diff --git a/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h b/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h index ce57dd7d0..5bb0e3ad3 100644 --- a/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h +++ b/src/boards/LimeSDR_Mini/USB_CSR_Pipe_Mini.h @@ -10,6 +10,10 @@ namespace lime { class USB_CSR_Pipe_Mini : public USB_CSR_Pipe { public: + /** + @brief Constructs a new USB_CSR_Pipe_Mini object + @param port The FT601 communications port to use. + */ explicit USB_CSR_Pipe_Mini(FT601& port); virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) override; diff --git a/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h b/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h index fb350c1ad..34eeb0701 100644 --- a/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h +++ b/src/boards/MMX8/LMS64C_ADF_Over_PCIe_MMX8.h @@ -14,6 +14,11 @@ namespace lime { class LMS64C_ADF_Over_PCIe_MMX8 : public ISPI { public: + /** + @brief Constructs a new LMS64C_ADF_Over_PCIe_MMX8 object + @param dataPort The PCIe data bus to use. + @param subdeviceIndex The subdevice index for which this class is created. + */ LMS64C_ADF_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h index 3fd44b1ce..efec16017 100644 --- a/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h +++ b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.h @@ -14,6 +14,11 @@ namespace lime { class LMS64C_FPGA_Over_PCIe_MMX8 : public IComms { public: + /** + @brief Constructs a new LMS64C_FPGA_Over_PCIe_MMX8 object. + @param dataPort The PCIe data bus to use. + @param subdeviceIndex The subdevice index for which this class is created. + */ LMS64C_FPGA_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h b/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h index 83d11bed2..dbb0a921a 100644 --- a/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h +++ b/src/boards/MMX8/LMS64C_LMS7002M_Over_PCIe_MMX8.h @@ -14,6 +14,11 @@ namespace lime { class LMS64C_LMS7002M_Over_PCIe_MMX8 : public IComms { public: + /** + @brief Construct a new LMS64C_LMS7002M_Over_PCIe_MMX8 object + @param dataPort The PCIe data bus to use. + @param subdeviceIndex The subdevice index for which this class is created. + */ LMS64C_LMS7002M_Over_PCIe_MMX8(std::shared_ptr dataPort, uint32_t subdeviceIndex); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h b/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h index fe527b4be..e463f7922 100644 --- a/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h +++ b/src/comms/PCIe/LMS64C_FPGA_Over_PCIe.h @@ -14,6 +14,10 @@ namespace lime { class LMS64C_FPGA_Over_PCIe : public IComms { public: + /** + @brief Constructs a new LMS64C_FPGA_Over_PCIe object. + @param dataPort The PCIe data bus to use. + */ LMS64C_FPGA_Over_PCIe(std::shared_ptr dataPort); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h b/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h index bc2f5a772..6e26fd4d9 100644 --- a/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h +++ b/src/comms/PCIe/LMS64C_LMS7002M_Over_PCIe.h @@ -14,6 +14,10 @@ namespace lime { class LMS64C_LMS7002M_Over_PCIe : public IComms { public: + /** + @brief Constructs a new LMS64C_LMS7002M_Over_PCIe object + @param dataPort The PCIe data connection to use. + */ LMS64C_LMS7002M_Over_PCIe(std::shared_ptr dataPort); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/comms/PCIe/PCIE_CSR_Pipe.h b/src/comms/PCIe/PCIE_CSR_Pipe.h index d9cc51bc7..639986635 100644 --- a/src/comms/PCIe/PCIE_CSR_Pipe.h +++ b/src/comms/PCIe/PCIE_CSR_Pipe.h @@ -17,8 +17,8 @@ class PCIE_CSR_Pipe : public ISerialPort @param port The LitePCIe port to use with this pipe. */ explicit PCIE_CSR_Pipe(std::shared_ptr port); - virtual int Write(const uint8_t* data, size_t length, int timeout_ms) override; - virtual int Read(uint8_t* data, size_t length, int timeout_ms) override; + virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) override; + virtual int Read(uint8_t* data, std::size_t length, int timeout_ms) override; protected: std::shared_ptr port; diff --git a/src/comms/USB/LMS64C_FPGA_Over_USB.h b/src/comms/USB/LMS64C_FPGA_Over_USB.h index bce87b8a0..7a52245a6 100644 --- a/src/comms/USB/LMS64C_FPGA_Over_USB.h +++ b/src/comms/USB/LMS64C_FPGA_Over_USB.h @@ -11,6 +11,10 @@ namespace lime { class LMS64C_FPGA_Over_USB : public IComms { public: + /** + @brief Constructs a new LMS64C_FPGA_Over_USB object. + @param dataPort The USB communications pipe to use. + */ LMS64C_FPGA_Over_USB(std::shared_ptr dataPort); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/comms/USB/LMS64C_LMS7002M_Over_USB.h b/src/comms/USB/LMS64C_LMS7002M_Over_USB.h index 1e23e6641..550a5bd12 100644 --- a/src/comms/USB/LMS64C_LMS7002M_Over_USB.h +++ b/src/comms/USB/LMS64C_LMS7002M_Over_USB.h @@ -11,6 +11,10 @@ namespace lime { class LMS64C_LMS7002M_Over_USB : public IComms { public: + /** + @brief Constructs a new LMS64C_LMS7002M_Over_USB object + @param dataPort The USB communications pipe to use. + */ LMS64C_LMS7002M_Over_USB(std::shared_ptr dataPort); virtual int SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/comms/USB/USBEntry.h b/src/comms/USB/USBEntry.h index 65390876c..aa0867a16 100644 --- a/src/comms/USB/USBEntry.h +++ b/src/comms/USB/USBEntry.h @@ -37,6 +37,11 @@ struct VidPid { class USBEntry : public DeviceRegistryEntry { public: + /** + @brief Constructs a new USBEntry object. + @param name The name of the device. + @param deviceIds The device Vendor and Product ID pairs to match to. + */ USBEntry(const std::string& name, const std::set& deviceIds); virtual ~USBEntry(); From 791f6a73cf4b8bab4c37bbf39207002b0a0783c9 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 21 Dec 2023 14:43:22 +0200 Subject: [PATCH 12/46] Clean up extraneous return type documentation --- src/boards/LimeSDR_X3/SlaveSelectShim.h | 2 +- src/comms/PCIe/AvgRmsCounter.h | 4 ++-- src/comms/USB/FT601/FT601.h | 2 +- src/comms/USB/USBGeneric.h | 14 +++++++------- src/include/limesuite/DeviceRegistry.h | 2 +- src/include/limesuite/commonTypes.h | 4 ++-- src/protocols/ISerialPort.h | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/boards/LimeSDR_X3/SlaveSelectShim.h b/src/boards/LimeSDR_X3/SlaveSelectShim.h index 2be4ab2d0..299df0d0c 100644 --- a/src/boards/LimeSDR_X3/SlaveSelectShim.h +++ b/src/boards/LimeSDR_X3/SlaveSelectShim.h @@ -21,7 +21,7 @@ class SlaveSelectShim : public ISPI /** @brief Send the reset device command to the device under this shim. - @return int The success status of the operation (0 on success), + @return The success status of the operation (0 on success), */ virtual int ResetDevice(); diff --git a/src/comms/PCIe/AvgRmsCounter.h b/src/comms/PCIe/AvgRmsCounter.h index 737e89f5e..01ef08b4b 100644 --- a/src/comms/PCIe/AvgRmsCounter.h +++ b/src/comms/PCIe/AvgRmsCounter.h @@ -29,14 +29,14 @@ class AvgRmsCounter /** @brief Gets the current minimum value and resets it. - @return double The minimum value recorded. + @return The minimum value recorded. */ double Min(); /** @brief Gets the current maximum value and resets it. - @return double The maximum value recorded. + @return The maximum value recorded. */ double Max(); private: diff --git a/src/comms/USB/FT601/FT601.h b/src/comms/USB/FT601/FT601.h index bdb295570..3ef28c550 100644 --- a/src/comms/USB/FT601/FT601.h +++ b/src/comms/USB/FT601/FT601.h @@ -45,7 +45,7 @@ class FT601 : public USBGeneric /** @brief Resets the stream buffers of the device. - @return int Status of the operation (0 - success; -1 - failure). + @return Status of the operation (0 - success; -1 - failure). */ int ResetStreamBuffers(); diff --git a/src/comms/USB/USBGeneric.h b/src/comms/USB/USBGeneric.h index 98eec81a1..bcc25e14c 100644 --- a/src/comms/USB/USBGeneric.h +++ b/src/comms/USB/USBGeneric.h @@ -40,13 +40,13 @@ class USBGeneric @param vid The vendor ID of the device. @param pid The prduct ID of the device. @param serial The serial number of the device. - @return bool The status of the operation (true on success). + @return The status of the operation (true on success). */ virtual bool Connect(uint16_t vid, uint16_t pid, const std::string& serial = ""); /** @brief Returns whether this instance is connected to a device. - @return bool The state of the connection (true = connected). + @return The state of the connection (true = connected). */ virtual bool IsConnected(); @@ -59,7 +59,7 @@ class USBGeneric @param data The pointer to the data buffer. @param length The length of data being transferred. @param timeout_ms The amount of time to wait (in ms) until the transfer is considered failed. - @return int32_t Actual number of bytes transferred. + @return Actual number of bytes transferred. */ virtual int32_t BulkTransfer(uint8_t endPoint, uint8_t* data, int length, int32_t timeout_ms = defaultTimeout); @@ -72,7 +72,7 @@ class USBGeneric @param data The pointer to the data buffer. @param length The length of data being transferred. @param timeout_ms The amount of time to wait (in ms) until the transfer is considered failed. - @return int32_t Actual number of bytes transferred. + @return Actual number of bytes transferred. */ virtual int32_t ControlTransfer( int requestType, int request, int value, int index, uint8_t* data, uint32_t length, int32_t timeout_ms = defaultTimeout); @@ -82,7 +82,7 @@ class USBGeneric @param buffer The pointer to the data buffer. @param length The length of the data being transferred. @param endPointAddr The endpoint address to use for the transfer. - @return int The handle of the transfer context to pass to WaitForXfer and FinishDataXfer functions. + @return The handle of the transfer context to pass to WaitForXfer and FinishDataXfer functions. */ virtual int BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPointAddr); @@ -90,7 +90,7 @@ class USBGeneric @brief Waits until an asynchronous data transfer finishes. @param contextHandle The context handle to wait for (received from BeginDataXfer). @param timeout_ms The timeout (in ms) to wait for the transfer. - @return bool Indication whether the transfer is finished or not (true = finished). + @return Indication whether the transfer is finished or not (true = finished). */ virtual bool WaitForXfer(int contextHandle, int32_t timeout_ms = defaultTimeout); @@ -99,7 +99,7 @@ class USBGeneric @param buffer The pointer to the data buffer. @param length The length of the data being transferred. @param contextHandle The handle of the transfer (received from BeginDataXfer). - @return int The amount of bytes transferred in the transfer. + @return The amount of bytes transferred in the transfer. */ virtual int FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle); diff --git a/src/include/limesuite/DeviceRegistry.h b/src/include/limesuite/DeviceRegistry.h index 3ae87212f..22f5a3742 100644 --- a/src/include/limesuite/DeviceRegistry.h +++ b/src/include/limesuite/DeviceRegistry.h @@ -43,7 +43,7 @@ class LIME_API DeviceRegistry /*! * Get a list of available registry entry modules by name. - * \return std::vector The list of available registry modules. + * \return The list of available registry modules. */ static std::vector moduleNames(void); }; diff --git a/src/include/limesuite/commonTypes.h b/src/include/limesuite/commonTypes.h index ae4761002..e6f51fd18 100644 --- a/src/include/limesuite/commonTypes.h +++ b/src/include/limesuite/commonTypes.h @@ -43,13 +43,13 @@ template class DeltaVariable /** @brief Gets the difference between the value at last reset and current value. - @return T The delta between the last time the delta variable was reset and the current value. + @return The delta between the last time the delta variable was reset and the current value. */ T delta() const { return mValue - mLastValue; } /** @brief Gets the current value of the delta variable. - @return T The current stored value of the delta variable. + @return The current stored value of the delta variable. */ T value() const { return mValue; } diff --git a/src/protocols/ISerialPort.h b/src/protocols/ISerialPort.h index 35c627058..6ea0cedbf 100644 --- a/src/protocols/ISerialPort.h +++ b/src/protocols/ISerialPort.h @@ -16,7 +16,7 @@ class ISerialPort @param data The data to write to the device. @param length The length of the data. @param timeout_ms The timeout (in ms) to wait until the transfer times out. - @return int The amount of bytes written. + @return The amount of bytes written. */ virtual int Write(const uint8_t* data, std::size_t length, int timeout_ms) = 0; @@ -26,7 +26,7 @@ class ISerialPort @param data The buffer in which to store the read data. @param length The length of the data to store. @param timeout_ms The timeout (in ms) to wait until the transfer times out. - @return int The amount of bytes read. + @return The amount of bytes read. */ virtual int Read(uint8_t* data, std::size_t length, int timeout_ms) = 0; }; From a38eb873cd3169d2e300b76449678e0f678a089e Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 21 Dec 2023 16:43:39 +0200 Subject: [PATCH 13/46] Document and clean up SamplesPacket and PacketsFIFO --- amarisoft-plugin/trx_limesuite.cpp | 8 +- src/API/LMS_APIWrapper.cpp | 4 +- src/FPGA_common/FPGA_common.cpp | 5 +- src/FPGA_common/FPGA_common.h | 5 +- src/cli/limeTRX.cpp | 6 +- src/comms/PCIe/TRXLooper_PCIE.cpp | 14 +-- src/comms/PCIe/TxBufferManager.h | 10 +- src/comms/USB/TRXLooper_USB.cpp | 8 +- src/examples/basicTX.cpp | 4 +- src/examples/dualRXTX.cpp | 4 +- src/fftviewer_wxgui/fftviewer_frFFTviewer.cpp | 4 +- src/include/limesuite/SDRDevice.h | 21 +++- src/protocols/BufferInterleaving.cpp | 9 +- src/protocols/PacketsFIFO.h | 50 ++++---- src/protocols/SamplesPacket.h | 118 ++++++++++++++---- src/protocols/TRXLooper.cpp | 36 +++--- src/utilities/rfTest.cpp | 14 +-- 17 files changed, 209 insertions(+), 111 deletions(-) diff --git a/amarisoft-plugin/trx_limesuite.cpp b/amarisoft-plugin/trx_limesuite.cpp index 804763f39..0f74d8d75 100644 --- a/amarisoft-plugin/trx_limesuite.cpp +++ b/amarisoft-plugin/trx_limesuite.cpp @@ -349,8 +349,8 @@ static void trx_lms7002m_write( SDRDevice::StreamMeta meta; meta.timestamp = timestamp; - meta.useTimestamp = true; - meta.flush = (md->flags & TRX_WRITE_MD_FLAG_END_OF_BURST); + meta.waitForTimestamp = true; + meta.flushPartialPacket = (md->flags & TRX_WRITE_MD_FLAG_END_OF_BURST); // samples format conversion is done internally LimeState* lime = (LimeState*)s->opaque; @@ -377,8 +377,8 @@ static int trx_lms7002m_read(TRXState* s, trx_timestamp_t* ptimestamp, void** sa LimeState* lime = (LimeState*)s->opaque; SDRDevice::StreamMeta meta; - meta.useTimestamp = false; - meta.flush = false; + meta.waitForTimestamp = false; + meta.flushPartialPacket = false; md->flags = 0; int samplesGot = diff --git a/src/API/LMS_APIWrapper.cpp b/src/API/LMS_APIWrapper.cpp index 05befa6c6..c00bff865 100644 --- a/src/API/LMS_APIWrapper.cpp +++ b/src/API/LMS_APIWrapper.cpp @@ -1281,8 +1281,8 @@ int SendStream(lms_stream_t* stream, const void* samples, size_t sample_count, c if (meta != nullptr) { - metadata.flush = meta->flushPartialPacket; - metadata.useTimestamp = meta->waitForTimestamp; + metadata.flushPartialPacket = meta->flushPartialPacket; + metadata.waitForTimestamp = meta->waitForTimestamp; metadata.timestamp = meta->timestamp; } diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 8f3a13a41..6e6e6f725 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -643,7 +643,7 @@ int FPGA::SetDirectClocking(int clockIndex) /** @brief Parses FPGA packet payload into samples */ -int FPGA::FPGAPacketPayload2Samples(const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex16_t** samples) +int FPGA::FPGAPacketPayload2Samples(const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex16_t* const* samples) { if (compressed) //compressed samples { @@ -694,7 +694,8 @@ int FPGA::FPGAPacketPayload2Samples(const uint8_t* buffer, int bufLen, bool mimo /** @brief Parses FPGA packet payload into samples */ -int FPGA::FPGAPacketPayload2SamplesFloat(const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex32f_t** samples) +int FPGA::FPGAPacketPayload2SamplesFloat( + const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex32f_t* const* samples) { const float normalizationAmplitude = compressed ? 2048 : 32768; if (compressed) //compressed samples diff --git a/src/FPGA_common/FPGA_common.h b/src/FPGA_common/FPGA_common.h index e9eb9e4f8..584fde966 100644 --- a/src/FPGA_common/FPGA_common.h +++ b/src/FPGA_common/FPGA_common.h @@ -52,9 +52,10 @@ class FPGA virtual int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, int ch = 0); double DetectRefClk(double fx3Clk = 100e6); - static int FPGAPacketPayload2Samples(const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex16_t** samples); + static int FPGAPacketPayload2Samples( + const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex16_t* const* samples); static int FPGAPacketPayload2SamplesFloat( - const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex32f_t** samples); + const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex32f_t* const* samples); static int Samples2FPGAPacketPayload( const complex16_t* const* samples, int samplesCount, bool mimo, bool compressed, uint8_t* buffer); static int Samples2FPGAPacketPayloadFloat( diff --git a/src/cli/limeTRX.cpp b/src/cli/limeTRX.cpp index 27de37282..0a4951189 100644 --- a/src/cli/limeTRX.cpp +++ b/src/cli/limeTRX.cpp @@ -594,7 +594,7 @@ int main(int argc, char** argv) SDRDevice::StreamMeta rxMeta; SDRDevice::StreamMeta txMeta; - txMeta.useTimestamp = true; + txMeta.waitForTimestamp = true; txMeta.timestamp = sampleRate / 100; // send tx samples 10ms after start #ifdef USE_GNU_PLOT @@ -653,8 +653,8 @@ int main(int argc, char** argv) if (tx && repeater) { txMeta.timestamp = rxMeta.timestamp + samplesRead + repeaterDelay; - txMeta.useTimestamp = true; - txMeta.flush = true; + txMeta.waitForTimestamp = true; + txMeta.flushPartialPacket = true; if (useComposite) composite->StreamTx(rxSamples, samplesRead, &txMeta); else diff --git a/src/comms/PCIe/TRXLooper_PCIE.cpp b/src/comms/PCIe/TRXLooper_PCIE.cpp index 3e5185721..1c57a1b59 100644 --- a/src/comms/PCIe/TRXLooper_PCIE.cpp +++ b/src/comms/PCIe/TRXLooper_PCIE.cpp @@ -179,7 +179,7 @@ void TRXLooper_PCIE::TransmitPacketsLoop() int64_t totalBytesSent = 0; //for data rate calculation int packetsSent = 0; int totalPacketSent = 0; - uint32_t maxFIFOlevel = 0; + std::size_t maxFIFOlevel = 0; int64_t lastTS = 0; struct PendingWrite { @@ -270,10 +270,10 @@ void TRXLooper_PCIE::TransmitPacketsLoop() } // drop old packets before forming, Rx is needed to get current timestamp - if (srcPkt->useTimestamp && mConfig.rxCount > 0) + if (srcPkt->metadata.waitForTimestamp && mConfig.rxCount > 0) { int64_t rxNow = mRx.lastTimestamp.load(std::memory_order_relaxed); - const int64_t txAdvance = srcPkt->timestamp - rxNow; + const int64_t txAdvance = srcPkt->metadata.timestamp - rxNow; if (mConfig.hintSampleRate) { int64_t timeAdvance = ts_to_us(mConfig.hintSampleRate, txAdvance); @@ -403,7 +403,7 @@ void TRXLooper_PCIE::TransmitPacketsLoop() snprintf(msg, sizeof(msg) - 1, "%s Tx: %3.3f MB/s | TS:%li pkt:%li o:%i shw:%u/%u(%+i) u:%i(%+i) l:%i(%+i) tsAdvance:%+.0f/%+.0f/%+.0f%s, " - "f:%i", + "f:%li", mRxArgs.port->GetPathName().c_str(), dataRate / 1000000.0, lastTS, @@ -567,7 +567,7 @@ void TRXLooper_PCIE::ReceivePacketsLoop() SDRDevice::StreamStats& stats = mRx.stats; auto fifo = mRx.fifo; - const int outputSampleSize = + const uint8_t outputSampleSize = mConfig.format == SDRDevice::StreamConfig::DataFormat::F32 ? sizeof(complex32f_t) : sizeof(complex16_t); const int32_t outputPktSize = SamplesPacketType::headerSize + mRxArgs.packetsToBatch * samplesInPkt * outputSampleSize; @@ -626,7 +626,7 @@ void TRXLooper_PCIE::ReceivePacketsLoop() char msg[512]; snprintf(msg, sizeof(msg) - 1, - "%s Rx: %3.3f MB/s | TS:%li pkt:%li o:%i(%+i) l:%i(%+i) dma:%u/%u(%u) swFIFO:%i", + "%s Rx: %3.3f MB/s | TS:%li pkt:%li o:%i(%+i) l:%i(%+i) dma:%u/%u(%u) swFIFO:%li", mRxArgs.port->GetPathName().c_str(), stats.dataRate_Bps / 1e6, stats.timestamp, @@ -680,7 +680,7 @@ void TRXLooper_PCIE::ReceivePacketsLoop() uint8_t* buffer = dmaBuffers[dma.swIndex % bufferCount]; const FPGA_RxDataPacket* pkt = reinterpret_cast(buffer); if (outputPkt) - outputPkt->timestamp = pkt->counter; + outputPkt->metadata.timestamp = pkt->counter; const int srcPktCount = mRxArgs.packetsToBatch; for (int i = 0; i < srcPktCount; ++i) diff --git a/src/comms/PCIe/TxBufferManager.h b/src/comms/PCIe/TxBufferManager.h index 47c2d7251..ae45ddf79 100644 --- a/src/comms/PCIe/TxBufferManager.h +++ b/src/comms/PCIe/TxBufferManager.h @@ -72,14 +72,14 @@ template class TxBufferManager payloadSize = 0; } - header->ignoreTimestamp(!src->useTimestamp); + header->ignoreTimestamp(!src->metadata.waitForTimestamp); if (payloadSize == 0) { ++packetsCreated; - header->counter = src->timestamp; + header->counter = src->metadata.timestamp; bytesUsed += sizeof(StreamHeader); } - const int freeSpace = std::min(maxPayloadSize - payloadSize, mCapacity - bytesUsed - 16); + const uint32_t freeSpace = std::min(maxPayloadSize - payloadSize, mCapacity - bytesUsed - 16); uint32_t transferCount = std::min(freeSpace / bytesForFrame, src->size()); transferCount = std::min(transferCount, maxSamplesInPkt); if (transferCount > 0) @@ -123,7 +123,7 @@ template class TxBufferManager } if (!hasSpace()) return true; - return src->flush || sendBuffer; + return src->metadata.flushPartialPacket || sendBuffer; } inline int size() const { return bytesUsed; }; @@ -141,7 +141,7 @@ template class TxBufferManager uint32_t maxSamplesInPkt; uint32_t maxPayloadSize; uint16_t packetsCreated; - uint16_t payloadSize; + uint32_t payloadSize; uint8_t bytesForFrame; }; diff --git a/src/comms/USB/TRXLooper_USB.cpp b/src/comms/USB/TRXLooper_USB.cpp index c018a20ce..f0e932e11 100644 --- a/src/comms/USB/TRXLooper_USB.cpp +++ b/src/comms/USB/TRXLooper_USB.cpp @@ -166,11 +166,11 @@ void TRXLooper_USB::TransmitPacketsLoop() { header->Clear(); ++packetsCreated; - header->counter = srcPkt->timestamp; + header->counter = srcPkt->metadata.timestamp; bytesUsed += sizeof(StreamHeader); } - header->ignoreTimestamp(!srcPkt->useTimestamp); + header->ignoreTimestamp(!srcPkt->metadata.waitForTimestamp); const uint freeSpace = std::min(maxPayloadSize - payloadSize, bufferSize - bytesUsed); uint transferCount = std::min(freeSpace / bytesForFrame, static_cast(srcPkt->size())); @@ -208,7 +208,7 @@ void TRXLooper_USB::TransmitPacketsLoop() payloadSize = 0; packetsCreated = 0; - mTx.stats.timestamp = srcPkt->timestamp; + mTx.stats.timestamp = srcPkt->metadata.timestamp; header = reinterpret_cast(&buffers[bufferIndex * bufferSize]); payloadPtr = reinterpret_cast(header) + sizeof(StreamHeader); @@ -276,7 +276,7 @@ void TRXLooper_USB::ReceivePacketsLoop() const int samplesInPkt = (mConfig.linkFormat == SDRDevice::StreamConfig::DataFormat::I16 ? 1020 : 1360) / conversion.channelCount; - const int outputSampleSize = + const uint8_t outputSampleSize = mConfig.format == SDRDevice::StreamConfig::DataFormat::F32 ? sizeof(complex32f_t) : sizeof(complex16_t); const int32_t outputPktSize = SamplesPacketType::headerSize + packetsToBatch * samplesInPkt * outputSampleSize; diff --git a/src/examples/basicTX.cpp b/src/examples/basicTX.cpp index 8c059988b..20ca67be5 100644 --- a/src/examples/basicTX.cpp +++ b/src/examples/basicTX.cpp @@ -128,8 +128,8 @@ int main(int argc, char** argv) SDRDevice::StreamMeta txMeta; txMeta.timestamp = 0; - txMeta.useTimestamp = true; - txMeta.flush = true; + txMeta.waitForTimestamp = true; + txMeta.flushPartialPacket = true; int totalSamplesSent = 0; diff --git a/src/examples/dualRXTX.cpp b/src/examples/dualRXTX.cpp index d29e393ba..68e42b96b 100644 --- a/src/examples/dualRXTX.cpp +++ b/src/examples/dualRXTX.cpp @@ -146,8 +146,8 @@ int main(int argc, char** argv) SDRDevice::StreamMeta txMeta; txMeta.timestamp = rxMeta.timestamp + samplesInBuffer * 64; - txMeta.useTimestamp = true; - txMeta.flush = false; + txMeta.waitForTimestamp = true; + txMeta.flushPartialPacket = false; int samplesSent = device->StreamTx(chipIndex, rxSamples, samplesInBuffer, &txMeta); if (samplesSent < 0) { diff --git a/src/fftviewer_wxgui/fftviewer_frFFTviewer.cpp b/src/fftviewer_wxgui/fftviewer_frFFTviewer.cpp index 4c68caed4..da6af96e6 100644 --- a/src/fftviewer_wxgui/fftviewer_frFFTviewer.cpp +++ b/src/fftviewer_wxgui/fftviewer_frFFTviewer.cpp @@ -472,8 +472,8 @@ void fftviewer_frFFTviewer::StreamingLoop( pthis->mStreamRunning.store(true); SDRDevice::StreamMeta txMeta; - txMeta.useTimestamp = syncTx; - txMeta.flush = true; + txMeta.waitForTimestamp = syncTx; + txMeta.flushPartialPacket = true; int fftCounter = 0; SDRDevice::StreamMeta rxMeta; diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index ea7381854..945934f61 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -182,9 +182,24 @@ class LIME_API SDRDevice /** @brief The metadata of a stream packet. */ struct StreamMeta { - int64_t timestamp; - bool useTimestamp; - bool flush; // submit data to hardware without waiting for full buffer + /** + * Timestamp is a value of HW counter with a tick based on sample rate. + * In RX: time when the first sample in the returned buffer was received. + * In TX: time when the first sample in the submitted buffer should be send. + */ + uint64_t timestamp; + + /** + * In RX: not used/ignored. + * In TX: wait for the specified HW timestamp before broadcasting data over the air. + */ + bool waitForTimestamp; + + /** + * In RX: not used/ignored. + * In TX: send samples to HW even if packet is not completely filled (end TX burst). + */ + bool flushPartialPacket; }; /** @brief Configuration of a general finite impulse response (FIR) filter. */ diff --git a/src/protocols/BufferInterleaving.cpp b/src/protocols/BufferInterleaving.cpp index 27d9e98fc..956d088db 100644 --- a/src/protocols/BufferInterleaving.cpp +++ b/src/protocols/BufferInterleaving.cpp @@ -61,15 +61,16 @@ int Deinterleave(const DataConversion& fmt, const uint8_t* buffer, uint32_t leng int samplesProduced; if (fmt.destFormat == SDRDevice::StreamConfig::DataFormat::F32) { - complex32f_t** dest = reinterpret_cast(output->back()); + complex32f_t* const* dest = reinterpret_cast(output->back()); if (!compressed) { samplesProduced = length / sizeof(complex16_t); if (!mimo) - complex16_to_complex32f(dest[0], (const complex16_t*)buffer, length / sizeof(complex16_t)); + complex16_to_complex32f(dest[0], reinterpret_cast(buffer), length / sizeof(complex16_t)); else { - complex16_to_complex32f_unzip(dest[0], dest[1], (const complex16_t*)buffer, length / sizeof(complex16_t)); + complex16_to_complex32f_unzip( + dest[0], dest[1], reinterpret_cast(buffer), length / sizeof(complex16_t)); samplesProduced /= 2; } } @@ -78,7 +79,7 @@ int Deinterleave(const DataConversion& fmt, const uint8_t* buffer, uint32_t leng } else { - complex16_t** dest = reinterpret_cast(output->back()); + complex16_t* const* dest = reinterpret_cast(output->back()); samplesProduced = FPGA::FPGAPacketPayload2Samples(buffer, length, mimo, compressed, dest); } output->SetSize(output->size() + samplesProduced); diff --git a/src/protocols/PacketsFIFO.h b/src/protocols/PacketsFIFO.h index e761507f2..93b693bb5 100644 --- a/src/protocols/PacketsFIFO.h +++ b/src/protocols/PacketsFIFO.h @@ -42,19 +42,21 @@ template class PacketsFIFO ///--------------------------------------------------------------------------- /// @brief Constructor. Asserts when the underlying type is not lock free - PacketsFIFO(size_t fixedSize) + PacketsFIFO(std::size_t fixedSize) : RingBufferSize(fixedSize + 1) { m_ringBuffer.resize(RingBufferSize); #ifndef NDEBUG - std::atomic test; + std::atomic test; assert(test.is_lock_free()); #endif } PacketsFIFO(const PacketsFIFO& src) = delete; - virtual ~PacketsFIFO() {} + virtual ~PacketsFIFO() + { + } ///--------------------------------------------------------------------------- /// @brief Returns whether the queue is empty @@ -62,8 +64,8 @@ template class PacketsFIFO bool empty() const noexcept { bool isEmpty = false; - const size_t readPosition = m_readPosition.load(); - const size_t writePosition = m_writePosition.load(); + const std::size_t readPosition = m_readPosition.load(); + const std::size_t writePosition = m_writePosition.load(); if (readPosition == writePosition) { @@ -82,9 +84,9 @@ template class PacketsFIFO bool push(const T element, bool wait = false, int timeout = 250) { std::unique_lock lk(mwr); - const size_t oldWritePosition = m_writePosition.load(); - const size_t newWritePosition = getPositionAfter(oldWritePosition); - const size_t readPosition = m_readPosition.load(); + const std::size_t oldWritePosition = m_writePosition.load(); + const std::size_t newWritePosition = getPositionAfter(oldWritePosition); + const std::size_t readPosition = m_readPosition.load(); if (newWritePosition == readPosition) { @@ -138,7 +140,7 @@ template class PacketsFIFO } } - const size_t readPosition = m_readPosition.load(); + const std::size_t readPosition = m_readPosition.load(); *element = (m_ringBuffer[readPosition]); m_readPosition.store(getPositionAfter(readPosition)); canWrite.notify_one(); @@ -149,8 +151,8 @@ template class PacketsFIFO /// @brief Clears the content from the queue void clear() noexcept { - const size_t readPosition = m_readPosition.load(); - const size_t writePosition = m_writePosition.load(); + const std::size_t readPosition = m_readPosition.load(); + const std::size_t writePosition = m_writePosition.load(); if (readPosition != writePosition) { @@ -161,22 +163,25 @@ template class PacketsFIFO ///--------------------------------------------------------------------------- /// @brief Returns the maximum size of the queue /// @return The maximum number of elements the queue can hold - constexpr uint32_t max_size() const noexcept { return RingBufferSize - 1; } + constexpr std::size_t max_size() const noexcept + { + return RingBufferSize - 1; + } ///--------------------------------------------------------------------------- /// @brief Returns the actual number of elements in the queue /// @return The actual size or 0 when empty - uint32_t size() const noexcept + std::size_t size() const noexcept { - const size_t readPosition = m_readPosition.load(); - const size_t writePosition = m_writePosition.load(); + const std::size_t readPosition = m_readPosition.load(); + const std::size_t writePosition = m_writePosition.load(); if (readPosition == writePosition) { return 0; } - size_t size = 0; + std::size_t size = 0; if (writePosition < readPosition) { size = RingBufferSize - readPosition + writePosition; @@ -189,14 +194,17 @@ template class PacketsFIFO return size; } - size_t getPositionAfter(size_t pos) noexcept { return ((pos + 1 == RingBufferSize) ? 0 : pos + 1); } - private: // A lock-free queue is basically a ring buffer. - size_t RingBufferSize; + std::size_t RingBufferSize; std::vector m_ringBuffer; - std::atomic m_readPosition = { 0 }; - std::atomic m_writePosition = { 0 }; + std::atomic m_readPosition = { 0 }; + std::atomic m_writePosition = { 0 }; + + constexpr std::size_t getPositionAfter(std::size_t pos) const noexcept + { + return ((pos + 1 == RingBufferSize) ? 0 : pos + 1); + } }; } // namespace lime diff --git a/src/protocols/SamplesPacket.h b/src/protocols/SamplesPacket.h index afc73cf8f..55acafa07 100644 --- a/src/protocols/SamplesPacket.h +++ b/src/protocols/SamplesPacket.h @@ -4,6 +4,8 @@ #include #include +#include "limesuite/SDRDevice.h" + namespace lime { /** @@ -13,7 +15,16 @@ namespace lime { template class SamplesPacket { public: + /** The size of the structure that holds the sample packet information. */ static constexpr int headerSize = sizeof(SamplesPacket); + + /** + @brief Constructs the sample packet class. + @param vptr Pointer to the sample data. + @param samplesCount The amount of samples to store. + @param frameSize The size of a single sample. + @return A pointer to the SamplePacket class. + */ static SamplesPacket* ConstructSamplesPacket(void* vptr, uint32_t samplesCount, uint8_t frameSize) { uint8_t* ptr = reinterpret_cast(vptr); @@ -32,22 +43,54 @@ template class SamplesPacket SamplesPacket() = delete; ~SamplesPacket() = delete; - inline int size() const + /** + @brief Gets the remaining amount of samples in the packet. + @return The amount of samples remaining. + */ + inline constexpr uint32_t size() const { assert(length >= offset); return length - offset; }; - inline bool empty() const { return size() == 0; }; - inline int capacity() const { return mCapacity; }; - inline bool isFull() const { return mCapacity - length == 0; }; + + /** + @brief Gets whether the packet is empty or not. + @return True if empty. + @return false if it has elements. + */ + inline constexpr bool empty() const { return size() == 0; }; + + /** + @brief Gets the maximum amount of samples this packet can hold. + @return The amount of samples the packet can hold. + */ + inline constexpr int capacity() const { return mCapacity; }; + + /** + @brief Gets whether the packet is full or not. + @return True if full. + @return False if there is still space.. + */ + inline constexpr bool isFull() const { return mCapacity - length == 0; }; + + /** + @brief Gets the channel count of this packet. + @return The amount of channels this packet holds the information for. + */ inline constexpr int channelCount() const { return chCount; }; - // copies samples data to buffer, returns actual copied samples count + /** + @brief Copies samples data to buffer. + @tparam T The type of samples to copy. + @param src The source array of the samples. + @param count The amount of samples to copy. + @return Actual copied samples count + */ template inline int push(const T* const* src, uint16_t count) { const uint16_t freeSamples = mCapacity - length; - const int samplesToCopy = std::min(freeSamples, count); - constexpr int alignment = sizeof(T); + const uint16_t samplesToCopy = std::min(freeSamples, count); + constexpr std::size_t alignment = sizeof(T); for (uint8_t i = 0; i < chCount; ++i) { if (src[i] == nullptr) @@ -58,18 +101,35 @@ template class SamplesPacket length += samplesToCopy; return samplesToCopy; } - // returns number of samples removed - inline int pop(int count) + + /** + @brief Removes a given amount of samples from the packet. + @param count The number of samples to remove. + @return Number of samples actually removed. + */ + inline uint32_t pop(uint32_t count) { - const uint16_t toPop = std::min(count, length - offset); + const uint32_t toPop = std::min(count, length - offset); for (uint8_t i = 0; i < chCount; ++i) head[i] += toPop * frameSize; offset += toPop; - timestamp += toPop; // also offset timestamp + metadata.timestamp += toPop; // Also offset timestamp return toPop; } - inline void* const* front() const { return reinterpret_cast(head); } - inline void** back() { return reinterpret_cast(tail); } + + /** + @brief Gets a pointer to the front element of the packet. + @return A pointer to the front of the packet elements. + */ + inline constexpr void* const* front() const { return reinterpret_cast(head); } + + /** + @brief Gets a pointer to the back element of the packet. + @return A pointer to the back of the packet elements. + */ + inline constexpr void* const* back() const { return reinterpret_cast(tail); } + + /** @brief Resets all the packet to be blank. */ inline void Reset() { offset = 0; @@ -78,15 +138,28 @@ template class SamplesPacket tail[i] = head[i] = channel[i]; } - inline void SetSize(uint32_t sz) + /** + @brief Sets the amount of samples of this packet. + @param sampleCount The amount of samples this packet has. + */ + inline void SetSize(uint32_t sampleCount) { - length = sz; + length = sampleCount; for (uint8_t i = 0; i < chCount; ++i) - tail[i] = channel[i] + sz * frameSize; + tail[i] = channel[i] + sampleCount * frameSize; } + /** + @brief Scales the packet's samples' I and Q values by the given multiplier. + @tparam T The type of samples the packet is holding. + @param iScale The multiplier with which to multiply all the I values. + @param qScale The multiplier with which to multiply all the Q values. + @param channelCount The amount of channels to multiply the values for. + */ template void Scale(float iScale, float qScale, int channelCount) { + assert(channelCount <= chCount); + int samplesCount = size(); for (int c = 0; c < channelCount; ++c) { @@ -104,14 +177,13 @@ template class SamplesPacket uint8_t* tail[chCount]; uint8_t* channel[chCount]; + uint32_t offset; + uint32_t length; + uint32_t mCapacity; + uint8_t frameSize; + public: - int64_t timestamp; - uint16_t offset; - uint16_t length; - uint16_t mCapacity; - uint16_t frameSize; - bool useTimestamp; - bool flush; + SDRDevice::StreamMeta metadata; ///< The stream metadata of the packet. }; } // namespace lime diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index 17aa2622a..fa2dbb6e2 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -630,12 +630,12 @@ int TRXLooper::StreamRx(lime::complex32f_t** dest, uint32_t count, SDRDevice::St return samplesProduced; if (!timestampSet && meta) { - meta->timestamp = mRx.stagingPacket->timestamp; + meta->timestamp = mRx.stagingPacket->metadata.timestamp; timestampSet = true; } - int expectedCount = count - samplesProduced; - const int samplesToCopy = std::min(expectedCount, mRx.stagingPacket->size()); + uint32_t expectedCount = count - samplesProduced; + const uint32_t samplesToCopy = std::min(expectedCount, mRx.stagingPacket->size()); lime::complex32f_t* const* f32_src = reinterpret_cast(mRx.stagingPacket->front()); @@ -672,12 +672,12 @@ int TRXLooper::StreamRx(lime::complex16_t** dest, uint32_t count, SDRDevice::Str return samplesProduced; if (!timestampSet && meta) { - meta->timestamp = mRx.stagingPacket->timestamp; + meta->timestamp = mRx.stagingPacket->metadata.timestamp; timestampSet = true; } - int expectedCount = count - samplesProduced; - const int samplesToCopy = std::min(expectedCount, mRx.stagingPacket->size()); + uint32_t expectedCount = count - samplesProduced; + const uint32_t samplesToCopy = std::min(expectedCount, mRx.stagingPacket->size()); lime::complex16_t* const* src = reinterpret_cast(mRx.stagingPacket->front()); @@ -703,8 +703,8 @@ int TRXLooper::StreamRx(lime::complex16_t** dest, uint32_t count, SDRDevice::Str int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { const bool useChannelB = mConfig.txCount > 1; - const bool useTimestamp = meta ? meta->useTimestamp : false; - const bool flush = meta && meta->flush; + const bool useTimestamp = meta ? meta->waitForTimestamp : false; + const bool flush = meta && meta->flushPartialPacket; int64_t ts = meta ? meta->timestamp : 0; int samplesRemaining = count; @@ -713,7 +713,7 @@ int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count const int packetsToBatch = mTx.packetsToBatch; const int32_t outputPktSize = SamplesPacketType::headerSize + packetsToBatch * samplesInPkt * sizeof(complex32f_t); - if (mTx.stagingPacket && mTx.stagingPacket->timestamp + mTx.stagingPacket->size() != meta->timestamp) + if (mTx.stagingPacket && mTx.stagingPacket->metadata.timestamp + mTx.stagingPacket->size() != meta->timestamp) { if (!mTx.fifo->push(mTx.stagingPacket)) return 0; @@ -730,8 +730,8 @@ int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count if (!mTx.stagingPacket) break; mTx.stagingPacket->Reset(); - mTx.stagingPacket->timestamp = ts; - mTx.stagingPacket->useTimestamp = useTimestamp; + mTx.stagingPacket->metadata.timestamp = ts; + mTx.stagingPacket->metadata.waitForTimestamp = useTimestamp; } int consumed = mTx.stagingPacket->push(src, samplesRemaining); @@ -745,7 +745,7 @@ int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count if (mTx.stagingPacket->isFull() || flush) { if (samplesRemaining == 0) - mTx.stagingPacket->flush = flush; + mTx.stagingPacket->metadata.flushPartialPacket = flush; if (!mTx.fifo->push(mTx.stagingPacket)) break; @@ -758,8 +758,8 @@ int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count int TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { const bool useChannelB = mConfig.txCount > 1; - const bool useTimestamp = meta ? meta->useTimestamp : false; - const bool flush = meta && meta->flush; + const bool useTimestamp = meta ? meta->waitForTimestamp : false; + const bool flush = meta && meta->flushPartialPacket; int64_t ts = meta ? meta->timestamp : 0; int samplesRemaining = count; @@ -767,7 +767,7 @@ int TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, const int packetsToBatch = mTx.packetsToBatch; const int32_t outputPktSize = SamplesPacketType::headerSize + packetsToBatch * samplesInPkt * sizeof(complex16_t); - if (mTx.stagingPacket && mTx.stagingPacket->timestamp + mTx.stagingPacket->size() != meta->timestamp) + if (mTx.stagingPacket && mTx.stagingPacket->metadata.timestamp + mTx.stagingPacket->size() != meta->timestamp) { if (!mTx.fifo->push(mTx.stagingPacket)) return 0; @@ -784,8 +784,8 @@ int TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, if (!mTx.stagingPacket) break; mTx.stagingPacket->Reset(); - mTx.stagingPacket->timestamp = ts; - mTx.stagingPacket->useTimestamp = useTimestamp; + mTx.stagingPacket->metadata.timestamp = ts; + mTx.stagingPacket->metadata.waitForTimestamp = useTimestamp; } int consumed = mTx.stagingPacket->push(src, samplesRemaining); @@ -799,7 +799,7 @@ int TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, if (mTx.stagingPacket->isFull() || flush) { if (samplesRemaining == 0) - mTx.stagingPacket->flush = flush; + mTx.stagingPacket->metadata.flushPartialPacket = flush; if (!mTx.fifo->push(mTx.stagingPacket)) break; diff --git a/src/utilities/rfTest.cpp b/src/utilities/rfTest.cpp index 3ab0c6d1a..0a8ba8917 100644 --- a/src/utilities/rfTest.cpp +++ b/src/utilities/rfTest.cpp @@ -182,7 +182,7 @@ bool FullStreamTxRx(SDRDevice& dev, bool MIMO) } // skip some packets at the start in case of leftover data garbage - int64_t ignoreSamplesAtStart = 0; + uint64_t ignoreSamplesAtStart = 0; //Initialize stream bool streamHadIssues = false; @@ -211,7 +211,7 @@ bool FullStreamTxRx(SDRDevice& dev, bool MIMO) bool show = false; int fired = 0; - int64_t lastRxTS = 0; + uint64_t lastRxTS = 0; int badSignal = 0; while (runForever.load()) @@ -255,8 +255,8 @@ bool FullStreamTxRx(SDRDevice& dev, bool MIMO) ++fired; int64_t rxNow = rxMeta.timestamp + samplesInPkt; txMeta.timestamp = rxNow + txDeltaTS; - txMeta.useTimestamp = true; - txMeta.flush = false; // not really matters because of continuous trasmitting + txMeta.waitForTimestamp = true; + txMeta.flushPartialPacket = false; // not really matters because of continuous trasmitting auto tt1 = std::chrono::high_resolution_clock::now(); int samplesSent = dev.StreamTx(testStreamIndex, src, samplesInPkt * txPacketCount, &txMeta); @@ -369,7 +369,7 @@ bool TxTiming(SDRDevice& dev, bool MIMO, float tsDelay_ms) } // skip some packets at the start in case of leftover data garbage - int64_t ignoreSamplesAtStart = 0; //samplesInPkt*1024; + uint64_t ignoreSamplesAtStart = 0; //samplesInPkt*1024; //printf("Skipping %i rx samples at the beginning", ignoreSamplesAtStart); //Initialize stream @@ -412,8 +412,8 @@ bool TxTiming(SDRDevice& dev, bool MIMO, float tsDelay_ms) if (!txPending) { txMeta.timestamp = rxNow + txDeltaTS; - txMeta.useTimestamp = true; - txMeta.flush = true; + txMeta.waitForTimestamp = true; + txMeta.flushPartialPacket = true; int samplesSent = dev.StreamTx(chipIndex, src, samplesInPkt, &txMeta); if (samplesSent <= 0) { From e4304411ba6bc4e47e859c98878a1307d72eba9e Mon Sep 17 00:00:00 2001 From: Dominykas Date: Fri, 22 Dec 2023 12:17:46 +0200 Subject: [PATCH 14/46] Remove unused channel parameter from LMS7002M::Get/SetClockFreq --- src/boards/LimeSDR/LimeSDR.cpp | 6 +++--- src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp | 6 +++--- src/boards/LimeSDR_X3/LimeSDR_X3.cpp | 6 +++--- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 8 ++++---- src/include/limesuite/LMS7002M.h | 4 ++-- src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp | 2 +- src/lms7002m/LMS7002M.cpp | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/boards/LimeSDR/LimeSDR.cpp b/src/boards/LimeSDR/LimeSDR.cpp index a9d394300..f646be2d7 100644 --- a/src/boards/LimeSDR/LimeSDR.cpp +++ b/src/boards/LimeSDR/LimeSDR.cpp @@ -222,7 +222,7 @@ void LimeSDR::Configure(const SDRConfig& cfg, uint8_t moduleIndex = 0) // config validation complete, now do the actual configuration if (cfg.referenceClockFreq != 0) - mLMSChips[0]->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq, 0); + mLMSChips[0]->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq); if (rxUsed && cfg.channel[0].rx.centerFrequency > 0) mLMSChips[0]->SetFrequencySX(TRXDir::Rx, cfg.channel[0].rx.centerFrequency); @@ -421,12 +421,12 @@ uint8_t LimeSDR::GetPath(SDRDevice::Dir dir, uint8_t channel) const double LimeSDR::GetClockFreq(uint8_t clk_id, uint8_t channel) { - return mLMSChips[0]->GetClockFreq(static_cast(clk_id), channel); + return mLMSChips[0]->GetClockFreq(static_cast(clk_id)); } void LimeSDR::SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) { - mLMSChips[0]->SetClockFreq(static_cast(clk_id), freq, channel); + mLMSChips[0]->SetClockFreq(static_cast(clk_id), freq); } void LimeSDR::Synchronize(bool toChip) diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp index 131af744b..6993490da 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp @@ -238,7 +238,7 @@ void LimeSDR_Mini::Configure(const SDRConfig& cfg, uint8_t moduleIndex = 0) if (cfg.referenceClockFreq != 0) { - mLMSChips[0]->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq, 0); + mLMSChips[0]->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq); } if (rxUsed) @@ -348,12 +348,12 @@ void LimeSDR_Mini::Reset() double LimeSDR_Mini::GetClockFreq(uint8_t clk_id, uint8_t channel) { - return mLMSChips[0]->GetClockFreq(static_cast(clk_id), channel); + return mLMSChips[0]->GetClockFreq(static_cast(clk_id)); } void LimeSDR_Mini::SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) { - mLMSChips[0]->SetClockFreq(static_cast(clk_id), freq, channel); + mLMSChips[0]->SetClockFreq(static_cast(clk_id), freq); } void LimeSDR_Mini::Synchronize(bool toChip) diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp index c22c33b35..7ca92b15f 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp @@ -551,7 +551,7 @@ void LimeSDR_X3::Configure(const SDRConfig& cfg, uint8_t socIndex) } if (cfg.referenceClockFreq != 0) - chip->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq, 0); + chip->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq); const bool tddMode = cfg.channel[0].rx.centerFrequency == cfg.channel[0].tx.centerFrequency; if (rxUsed && cfg.channel[0].rx.centerFrequency > 0) @@ -802,14 +802,14 @@ double LimeSDR_X3::GetClockFreq(uint8_t clk_id, uint8_t channel) { ValidateChannel(channel); LMS7002M* chip = mLMSChips[channel / 2]; - return chip->GetClockFreq(static_cast(clk_id), channel & 1); + return chip->GetClockFreq(static_cast(clk_id)); } void LimeSDR_X3::SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) { ValidateChannel(channel); LMS7002M* chip = mLMSChips[channel / 2]; - chip->SetClockFreq(static_cast(clk_id), freq, channel & 1); + chip->SetClockFreq(static_cast(clk_id), freq); } int LimeSDR_X3::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index 572701b38..985643c7a 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -158,7 +158,7 @@ LimeSDR_XTRX::LimeSDR_XTRX( for (auto iter : mLMSChips) { iter->SetReferenceClk_SX(TRXDir::Rx, refClk); - iter->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, refClk, 0); + iter->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, refClk); } const int chipCount = mLMSChips.size(); @@ -238,7 +238,7 @@ void LimeSDR_XTRX::Configure(const SDRConfig& cfg, uint8_t socIndex) } if (cfg.referenceClockFreq != 0) - chip->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq, 0); + chip->SetClockFreq(LMS7002M::ClockID::CLK_REFERENCE, cfg.referenceClockFreq); const bool tddMode = cfg.channel[0].rx.centerFrequency == cfg.channel[0].tx.centerFrequency; if (rxUsed && cfg.channel[0].rx.centerFrequency > 0) @@ -379,14 +379,14 @@ double LimeSDR_XTRX::GetClockFreq(uint8_t clk_id, uint8_t channel) { ValidateChannel(channel); LMS7002M* chip = mLMSChips[channel / 2]; - return chip->GetClockFreq(static_cast(clk_id), channel & 1); + return chip->GetClockFreq(static_cast(clk_id)); } void LimeSDR_XTRX::SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) { ValidateChannel(channel); LMS7002M* chip = mLMSChips[channel / 2]; - chip->SetClockFreq(static_cast(clk_id), freq, channel & 1); + chip->SetClockFreq(static_cast(clk_id), freq); } int LimeSDR_XTRX::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) diff --git a/src/include/limesuite/LMS7002M.h b/src/include/limesuite/LMS7002M.h index dee8bd350..36fcb48d7 100644 --- a/src/include/limesuite/LMS7002M.h +++ b/src/include/limesuite/LMS7002M.h @@ -368,8 +368,8 @@ class LIME_API LMS7002M */ void GetIQBalance(const TRXDir dir, float_type& phase, float_type& gainI, float_type& gainQ); - double GetClockFreq(ClockID clk_id, uint8_t channel); - void SetClockFreq(ClockID clk_id, double freq, uint8_t channel); + double GetClockFreq(ClockID clk_id); + void SetClockFreq(ClockID clk_id, double freq); ///enumeration to indicate module registers intervals enum MemorySection { diff --git a/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp b/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp index bbf805eef..33fe53679 100644 --- a/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp +++ b/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp @@ -1928,7 +1928,7 @@ void lms7002_pnlRXTSP_view::UpdateGUI() if (lmsControl == nullptr) return; LMS7002_WXGUI::UpdateControlsByMap(this, lmsControl, wndId2Enum, mChannel); - double freq = lmsControl->GetClockFreq(LMS7002M::ClockID::CLK_RXTSP, mChannel); + double freq = lmsControl->GetClockFreq(LMS7002M::ClockID::CLK_RXTSP); lblRefClk->SetLabel(wxString::Format(_("%3.3f"), freq / 1e6)); int16_t iqcorr_value; diff --git a/src/lms7002m/LMS7002M.cpp b/src/lms7002m/LMS7002M.cpp index cb2aac292..8b598c378 100644 --- a/src/lms7002m/LMS7002M.cpp +++ b/src/lms7002m/LMS7002M.cpp @@ -3232,7 +3232,7 @@ int LMS7002M::CalibrateAnalogRSSI_DC_Offset() return 0; } -double LMS7002M::GetClockFreq(ClockID clk_id, uint8_t channel) +double LMS7002M::GetClockFreq(ClockID clk_id) { switch (clk_id) { @@ -3254,7 +3254,7 @@ double LMS7002M::GetClockFreq(ClockID clk_id, uint8_t channel) } } -void LMS7002M::SetClockFreq(ClockID clk_id, double freq, uint8_t channel) +void LMS7002M::SetClockFreq(ClockID clk_id, double freq) { switch (clk_id) { From da38b43b3109bfd1382b04c42574f7c8cc84f9f3 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Fri, 22 Dec 2023 14:24:27 +0200 Subject: [PATCH 15/46] Document and slightly refactor SDRDevice --- amarisoft-plugin/trx_limesuite.cpp | 12 +- src/boards/LMS7002M_SDRDevice.cpp | 2 +- src/boards/LMS7002M_SDRDevice.h | 2 +- src/boards/LimeSDR/LimeSDR.cpp | 12 - src/boards/LimeSDR/LimeSDR.h | 3 - src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp | 15 - src/boards/LimeSDR_Mini/LimeSDR_Mini.h | 3 - src/boards/LimeSDR_X3/LimeSDR_X3.cpp | 2 +- src/boards/LimeSDR_X3/LimeSDR_X3.h | 2 +- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 2 +- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h | 2 +- src/boards/MMX8/MM_X8.cpp | 2 +- src/boards/MMX8/MM_X8.h | 2 +- src/cli/limeTRX.cpp | 8 +- src/comms/PCIe/TRXLooper_PCIE.cpp | 16 +- src/include/limesuite/SDRDevice.h | 382 +++++++++++++++-------- src/lms7002m/LMS7002M.cpp | 8 +- src/protocols/TRXLooper.cpp | 144 +++------ src/protocols/TRXLooper.h | 4 + 19 files changed, 328 insertions(+), 295 deletions(-) diff --git a/amarisoft-plugin/trx_limesuite.cpp b/amarisoft-plugin/trx_limesuite.cpp index 0f74d8d75..a0a34fd45 100644 --- a/amarisoft-plugin/trx_limesuite.cpp +++ b/amarisoft-plugin/trx_limesuite.cpp @@ -501,9 +501,9 @@ static int trx_lms7002m_get_tx_samples_per_packet_func(TRXState* s1) { LimeState* lime = (LimeState*)s1->opaque; int txExpectedSamples = lime->samplesInPacket[0]; - if (lime->streamExtras[0] && lime->streamExtras[0]->txSamplesInPacket > 0) + if (lime->streamExtras[0] && lime->streamExtras[0]->tx.samplesInPacket > 0) { - txExpectedSamples = lime->streamExtras[0]->txSamplesInPacket; + txExpectedSamples = lime->streamExtras[0]->tx.samplesInPacket; } Log(LogLevel::DEBUG, "Hardware expected samples count in Tx packet : %i\n", txExpectedSamples); return txExpectedSamples; @@ -1197,25 +1197,25 @@ int __attribute__((visibility("default"))) trx_driver_init(TRXState* hostState) sprintf(varname, "port%i_rxSamplesInPacket", p); if (trx_get_param_double(hostState, &val, varname) == 0) { - extra->rxSamplesInPacket = val; + extra->rx.samplesInPacket = val; s->streamExtras[p] = extra; } sprintf(varname, "port%i_rxPacketsInBatch", p); if (trx_get_param_double(hostState, &val, varname) == 0) { - extra->rxPacketsInBatch = val; + extra->rx.packetsInBatch = val; s->streamExtras[p] = extra; } sprintf(varname, "port%i_txMaxPacketsInBatch", p); if (trx_get_param_double(hostState, &val, varname) == 0) { - extra->txMaxPacketsInBatch = val; + extra->tx.packetsInBatch = val; s->streamExtras[p] = extra; } sprintf(varname, "port%i_txSamplesInPacket", p); if (trx_get_param_double(hostState, &val, varname) == 0) { - extra->txSamplesInPacket = val; + extra->tx.samplesInPacket = val; s->streamExtras[p] = extra; } sprintf(varname, "port%i_double_freq_conversion_to_lower_side", p); diff --git a/src/boards/LMS7002M_SDRDevice.cpp b/src/boards/LMS7002M_SDRDevice.cpp index 4fbeefae9..bf0f719bd 100644 --- a/src/boards/LMS7002M_SDRDevice.cpp +++ b/src/boards/LMS7002M_SDRDevice.cpp @@ -213,7 +213,7 @@ void LMS7002M_SDRDevice::StreamStatus(uint8_t moduleIndex, SDRDevice::StreamStat } } -bool LMS7002M_SDRDevice::UploadMemory( +int LMS7002M_SDRDevice::UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) { throw(OperationNotSupported("UploadMemory not implemented")); diff --git a/src/boards/LMS7002M_SDRDevice.h b/src/boards/LMS7002M_SDRDevice.h index 3ca0dd3a3..b35020441 100644 --- a/src/boards/LMS7002M_SDRDevice.h +++ b/src/boards/LMS7002M_SDRDevice.h @@ -63,7 +63,7 @@ class LIME_API LMS7002M_SDRDevice : public SDRDevice virtual void* GetInternalChip(uint32_t index); - virtual bool UploadMemory( + virtual int UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) override; virtual int ReadFPGARegister(uint32_t address); diff --git a/src/boards/LimeSDR/LimeSDR.cpp b/src/boards/LimeSDR/LimeSDR.cpp index f646be2d7..2265d8c5f 100644 --- a/src/boards/LimeSDR/LimeSDR.cpp +++ b/src/boards/LimeSDR/LimeSDR.cpp @@ -443,13 +443,6 @@ void LimeSDR::Synchronize(bool toChip) mLMSChips[0]->DownloadAll(); } -void LimeSDR::EnableCache(bool enable) -{ - mLMSChips[0]->EnableValuesCache(enable); - if (mFPGA) - mFPGA->EnableValuesCache(enable); -} - int LimeSDR::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) { assert(mSerialPort); @@ -666,11 +659,6 @@ void LimeSDR::StreamStop(uint8_t moduleIndex) mStreamers[0] = nullptr; } -void* LimeSDR::GetInternalChip(uint32_t index) -{ - return mLMSChips.at(index); -} - int LimeSDR::GPIODirRead(uint8_t* buffer, const size_t bufLength) { return mfpgaPort->GPIODirRead(buffer, bufLength); diff --git a/src/boards/LimeSDR/LimeSDR.h b/src/boards/LimeSDR/LimeSDR.h index af0830c1d..6a422271a 100644 --- a/src/boards/LimeSDR/LimeSDR.h +++ b/src/boards/LimeSDR/LimeSDR.h @@ -30,7 +30,6 @@ class LimeSDR : public LMS7002M_SDRDevice virtual void SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) override; virtual void Synchronize(bool toChip) override; - virtual void EnableCache(bool enable) override; virtual int SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; @@ -39,8 +38,6 @@ class LimeSDR : public LMS7002M_SDRDevice virtual void StreamStart(uint8_t moduleIndex) override; virtual void StreamStop(uint8_t moduleIndex) override; - virtual void* GetInternalChip(uint32_t index) override; - virtual int GPIODirRead(uint8_t* buffer, const size_t bufLength) override; virtual int GPIORead(uint8_t* buffer, const size_t bufLength) override; virtual int GPIODirWrite(const uint8_t* buffer, const size_t bufLength) override; diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp index 6993490da..99ad7d1f9 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp @@ -372,16 +372,6 @@ void LimeSDR_Mini::Synchronize(bool toChip) } } -void LimeSDR_Mini::EnableCache(bool enable) -{ - mLMSChips[0]->EnableValuesCache(enable); - - if (mFPGA) - { - mFPGA->EnableValuesCache(enable); - } -} - int LimeSDR_Mini::SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) { assert(mStreamPort); @@ -646,11 +636,6 @@ void LimeSDR_Mini::StreamStop(uint8_t moduleIndex) mStreamers[0] = nullptr; } -void* LimeSDR_Mini::GetInternalChip(uint32_t index) -{ - return mLMSChips.at(index); -} - int LimeSDR_Mini::GPIODirRead(uint8_t* buffer, const size_t bufLength) { if (!buffer || bufLength == 0) diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.h b/src/boards/LimeSDR_Mini/LimeSDR_Mini.h index df34a4c73..b6f09cc99 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.h +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.h @@ -30,7 +30,6 @@ class LimeSDR_Mini : public LMS7002M_SDRDevice virtual void SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) override; virtual void Synchronize(bool toChip) override; - virtual void EnableCache(bool enable) override; virtual int SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; @@ -39,8 +38,6 @@ class LimeSDR_Mini : public LMS7002M_SDRDevice virtual void StreamStart(uint8_t moduleIndex) override; virtual void StreamStop(uint8_t moduleIndex) override; - virtual void* GetInternalChip(uint32_t index) override; - virtual int GPIODirRead(uint8_t* buffer, const size_t bufLength) override; virtual int GPIORead(uint8_t* buffer, const size_t bufLength) override; virtual int GPIODirWrite(const uint8_t* buffer, const size_t bufLength) override; diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp index 7ca92b15f..048785126 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp @@ -1209,7 +1209,7 @@ int LimeSDR_X3::CustomParameterRead(std::vector& parameters) return mfpgaPort->CustomParameterRead(parameters); } -bool LimeSDR_X3::UploadMemory( +int LimeSDR_X3::UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) { int progMode; diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.h b/src/boards/LimeSDR_X3/LimeSDR_X3.h index d742bc8a6..01c087a83 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.h +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.h @@ -44,7 +44,7 @@ class LimeSDR_X3 : public LMS7002M_SDRDevice virtual int CustomParameterWrite(const std::vector& parameters) override; virtual int CustomParameterRead(std::vector& parameters) override; - virtual bool UploadMemory( + virtual int UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) override; virtual int MemoryWrite(std::shared_ptr storage, Region region, const void* data) override; virtual int MemoryRead(std::shared_ptr storage, Region region, void* data) override; diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index 985643c7a..ec17c8a7f 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -599,7 +599,7 @@ int LimeSDR_XTRX::CustomParameterRead(std::vector& parameters return fpgaPort->CustomParameterRead(parameters); } -bool LimeSDR_XTRX::UploadMemory( +int LimeSDR_XTRX::UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) { int progMode; diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h index 8f42dc32b..cc205a7e9 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.h @@ -41,7 +41,7 @@ class LimeSDR_XTRX : public LMS7002M_SDRDevice virtual int CustomParameterWrite(const std::vector& parameters) override; virtual int CustomParameterRead(std::vector& parameters) override; - virtual bool UploadMemory( + virtual int UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) override; virtual int MemoryWrite(std::shared_ptr storage, Region region, const void* data) override; virtual int MemoryRead(std::shared_ptr storage, Region region, void* data) override; diff --git a/src/boards/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index 4220e292b..e2cab937b 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -304,7 +304,7 @@ int LimeSDR_MMX8::CustomParameterRead(std::vector& parameters return ret; } -bool LimeSDR_MMX8::UploadMemory( +int LimeSDR_MMX8::UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) { if (device == eMemoryDevice::FPGA_FLASH && moduleIndex == 0) diff --git a/src/boards/MMX8/MM_X8.h b/src/boards/MMX8/MM_X8.h index 1655460bb..1fa32be08 100644 --- a/src/boards/MMX8/MM_X8.h +++ b/src/boards/MMX8/MM_X8.h @@ -68,7 +68,7 @@ class LimeSDR_MMX8 : public SDRDevice virtual void* GetInternalChip(uint32_t index) override; - virtual bool UploadMemory( + virtual int UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) override; virtual int MemoryWrite(std::shared_ptr storage, Region region, const void* data) override; virtual int MemoryRead(std::shared_ptr storage, Region region, void* data) override; diff --git a/src/cli/limeTRX.cpp b/src/cli/limeTRX.cpp index 0a4951189..9ca5f330a 100644 --- a/src/cli/limeTRX.cpp +++ b/src/cli/limeTRX.cpp @@ -500,10 +500,10 @@ int main(int argc, char** argv) { stream.extraConfig = new SDRDevice::StreamConfig::Extras(); stream.extraConfig->waitPPS = syncPPS; - stream.extraConfig->rxSamplesInPacket = rxSamplesInPacket; - stream.extraConfig->txSamplesInPacket = txSamplesInPacket; - stream.extraConfig->rxPacketsInBatch = rxPacketsInBatch; - stream.extraConfig->txMaxPacketsInBatch = txPacketsInBatch; + stream.extraConfig->rx.samplesInPacket = rxSamplesInPacket; + stream.extraConfig->tx.samplesInPacket = txSamplesInPacket; + stream.extraConfig->rx.packetsInBatch = rxPacketsInBatch; + stream.extraConfig->tx.packetsInBatch = txPacketsInBatch; } useComposite = chipIndexes.size() > 1; diff --git a/src/comms/PCIe/TRXLooper_PCIE.cpp b/src/comms/PCIe/TRXLooper_PCIE.cpp index 1c57a1b59..d898ef4db 100644 --- a/src/comms/PCIe/TRXLooper_PCIE.cpp +++ b/src/comms/PCIe/TRXLooper_PCIE.cpp @@ -117,9 +117,9 @@ int TRXLooper_PCIE::TxSetup() int samplesInPkt = 256; //(mConfig.linkFormat == SDRDevice::StreamConfig::DataFormat::I16 ? 1020 : 1360) / chCount; const int packetSize = sizeof(StreamHeader) + samplesInPkt * sampleSize * chCount; - if (mConfig.extraConfig && mConfig.extraConfig->txSamplesInPacket != 0) + if (mConfig.extraConfig && mConfig.extraConfig->tx.samplesInPacket != 0) { - samplesInPkt = mConfig.extraConfig->txSamplesInPacket; + samplesInPkt = mConfig.extraConfig->tx.samplesInPacket; printf("Tx samples overide %i\n", samplesInPkt); } @@ -127,8 +127,8 @@ int TRXLooper_PCIE::TxSetup() LitePCIe::DMAInfo dma = mTxArgs.port->GetDMAInfo(); - if (mConfig.extraConfig && mConfig.extraConfig->txMaxPacketsInBatch != 0) - mTx.packetsToBatch = mConfig.extraConfig->txMaxPacketsInBatch; + if (mConfig.extraConfig && mConfig.extraConfig->tx.packetsInBatch != 0) + mTx.packetsToBatch = mConfig.extraConfig->tx.packetsInBatch; mTx.packetsToBatch = clamp((int)mTx.packetsToBatch, 1, (int)(dma.bufferSize / packetSize)); @@ -475,8 +475,8 @@ int TRXLooper_PCIE::RxSetup() const int maxSamplesInPkt = 1024 / chCount; int requestSamplesInPkt = 256; //maxSamplesInPkt; - if (mConfig.extraConfig && mConfig.extraConfig->rxSamplesInPacket != 0) - requestSamplesInPkt = mConfig.extraConfig->rxSamplesInPacket; + if (mConfig.extraConfig && mConfig.extraConfig->rx.samplesInPacket != 0) + requestSamplesInPkt = mConfig.extraConfig->rx.samplesInPacket; int samplesInPkt = clamp(requestSamplesInPkt, 64, maxSamplesInPkt); int payloadSize = requestSamplesInPkt * sampleSize * chCount; @@ -497,8 +497,8 @@ int TRXLooper_PCIE::RxSetup() LitePCIe::DMAInfo dma = mRxArgs.port->GetDMAInfo(); - if (mConfig.extraConfig && mConfig.extraConfig->rxPacketsInBatch != 0) - mRx.packetsToBatch = mConfig.extraConfig->rxPacketsInBatch; + if (mConfig.extraConfig && mConfig.extraConfig->rx.packetsInBatch != 0) + mRx.packetsToBatch = mConfig.extraConfig->rx.packetsInBatch; mRx.packetsToBatch = clamp((int)mRx.packetsToBatch, 1, (int)(dma.bufferSize / packetSize)); int irqPeriod = 16; diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index 945934f61..cc9123374 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -19,52 +19,54 @@ namespace lime { struct DeviceNode; -/** @brief SDRDevice can have multiple modules (RF chips), that can operate independently. */ +/// @brief Class for holding information about an SDR (Software Defined Radio) device. +/// SDRDevice can have multiple modules (RF chips), that can operate independently. class LIME_API SDRDevice { public: - static constexpr uint8_t MAX_CHANNEL_COUNT = 16; - static constexpr uint8_t MAX_RFSOC_COUNT = 16; + static constexpr uint8_t MAX_CHANNEL_COUNT = 16; ///< Maximum amount of channels an SDR Device can hold + static constexpr uint8_t MAX_RFSOC_COUNT = 16; ///< Maximum amount of Radio-Frequency System-on-Chips + /// @brief Enumerator to define the log level of a log message. enum class LogLevel : uint8_t { CRITICAL, ERROR, WARNING, INFO, VERBOSE, DEBUG }; - typedef void (*DataCallbackType)(bool, const uint8_t*, const uint32_t); - typedef void (*LogCallbackType)(LogLevel, const char*); - typedef std::map SlaveNameIds_t; - - /** @brief General information about the Radio-Frequency System-on-Chip (RFSoC). */ + /// @brief General information about the Radio-Frequency System-on-Chip (RFSoC). struct RFSOCDescriptor { - std::string name; - uint8_t channelCount; - std::vector rxPathNames; - std::vector txPathNames; - - Range samplingRateRange; - Range frequencyRange; - std::unordered_map> antennaRange; + std::string name; ///< The name of the chip + uint8_t channelCount; ///< The channel amount the chip has + std::vector rxPathNames; ///< The names of receive paths + std::vector txPathNames; ///< The names of transmit paths + + Range samplingRateRange; ///< Sampling rate capabilities of the device + Range frequencyRange; ///< Deliverable frequency capabilities of the device + std::unordered_map> antennaRange; ///< Antenna recommended bandwidths }; - /** @brief Structure for the information of a custom parameter. */ + /// @brief Structure for the information of a custom parameter. struct CustomParameter { - std::string name; - int32_t id; - int32_t minValue; - int32_t maxValue; - bool readOnly; + std::string name; ///< The name of the custom parameter + int32_t id; ///< The identifier of the custom parameter + int32_t minValue; ///< The minimum possible value of the custom parameter + int32_t maxValue; ///< The maximum possible value of the custom parameter + bool readOnly; ///< Denotes whether this value is read only or not }; - /** @brief Structure for storing the information of a memory region. */ + /// @brief Structure for storing the information of a memory region. struct Region { - int32_t address; - int32_t size; + int32_t address; ///< Starting address of the memory region + int32_t size; ///< The size of the memory region }; - /** @brief Describes a data storage of a certain type a device holds. */ + /// @brief Describes a data storage of a certain type a device holds. struct DataStorage { - SDRDevice* ownerDevice; - eMemoryDevice memoryDeviceType; - std::unordered_map regions; - + SDRDevice* ownerDevice; ///< Pointer to the device that actually owns the data storage + eMemoryDevice memoryDeviceType; ///< The type of memory being described + std::unordered_map regions; ///< The documented memory regions of the data storage + + /// @brief Constructs a new Data Storage object + /// @param device The device this storage belongs to. + /// @param type The type of memory being described in this object. + /// @param regions The memory regions this memory contains. DataStorage(SDRDevice* device = nullptr, eMemoryDevice type = eMemoryDevice::COUNT, std::unordered_map regions = {}) @@ -75,112 +77,129 @@ class LIME_API SDRDevice } }; - /** @brief General information about device internals, static capabilities. */ + /// @brief General information about device internals, static capabilities. struct Descriptor { - std::string name; /// The displayable name for the device + std::string name; ///< The displayable name for the device /*! The displayable name for the expansion card - * Ex: if the RFIC is on a daughter-card + * Ex: if the RFIC is on a daughter-card. */ std::string expansionName; - std::string firmwareVersion; /// The firmware version as a string - std::string gatewareVersion; /// Gateware version as a string - std::string gatewareRevision; /// Gateware revision as a string - std::string gatewareTargetBoard; /// Which board should use this gateware - std::string hardwareVersion; /// The hardware version as a string - std::string protocolVersion; /// The protocol version as a string - uint64_t serialNumber{ 0 }; /// A unique board serial number - - SlaveNameIds_t spiSlaveIds; // names and SPI bus numbers of internal chips - std::vector rfSOC; - std::vector customParameters; + std::string firmwareVersion; ///< The firmware version as a string + std::string gatewareVersion; ///< Gateware version as a string + std::string gatewareRevision; ///< Gateware revision as a string + std::string gatewareTargetBoard; ///< Which board should use this gateware + std::string hardwareVersion; ///< The hardware version as a string + std::string protocolVersion; ///< The protocol version as a string + uint64_t serialNumber{ 0 }; ///< A unique board serial number + + std::map spiSlaveIds; ///< Names and SPI bus numbers of internal chips + std::vector rfSOC; ///< Descriptors of all RFSoC devices within this device + std::vector customParameters; ///< Descriptions of all custom parameters of this device + /** Descriptions of all memory storage devices on this device */ std::map> memoryDevices; - std::shared_ptr socTree; + std::shared_ptr socTree; ///< The device's subdevices tree view representation - static const char DEVICE_NUMBER_SEPARATOR_SYMBOL; - static const char PATH_SEPARATOR_SYMBOL; + static const char DEVICE_NUMBER_SEPARATOR_SYMBOL; ///< The symbol used to separate the device's name from its number + static const char PATH_SEPARATOR_SYMBOL; ///< The symbol that separates the device's name from its parent's name }; - /** @brief Structure for holding the statistics of a stream */ + /// @brief Structure for holding the statistics of a stream struct StreamStats { - /** @brief Structure for storing the first in first out queue statistics */ + /// @brief Structure for storing the first in first out queue statistics struct FIFOStats { - std::size_t totalCount; - std::size_t usedCount; + std::size_t totalCount; ///< The total amount of samples that can be in the FIFO queue. + std::size_t usedCount; ///< The amount of samples that is currently in the FIFO queue. - float ratio() { return static_cast(usedCount) / totalCount; } + /// @brief Gets the ratio of the amount of FIFO filled up. + /// @return The amount of FIFO filled up (0 - completely empty, 1 - completely full). + constexpr float ratio() const { return static_cast(usedCount) / totalCount; } }; - StreamStats() { memset(this, 0, sizeof(StreamStats)); } - uint64_t timestamp; - int64_t bytesTransferred; - int64_t packets; - FIFOStats FIFO; - float dataRate_Bps; - uint32_t overrun; - uint32_t underrun; - uint32_t loss; - uint32_t late; + StreamStats() { std::memset(this, 0, sizeof(StreamStats)); } + uint64_t timestamp; ///< The current timestamp of the stream. + int64_t bytesTransferred; ///< The total amount of bytes transferred. + int64_t packets; ///< The total amount of packets transferred. + FIFOStats FIFO; ///< The status of the FIFO queue. + float dataRate_Bps; ///< The current data transmission rate. + uint32_t overrun; ///< The amount of packets overrun. + uint32_t underrun; ///< The amount of packets underrun. + uint32_t loss; ///< The amount of packets that are lost. + uint32_t late; ///< The amount of packets that arrived late for transmitting and were dropped. }; - /** @brief Describes the status of the GPS. */ + /// @brief Describes the status of a global positioning system. struct GPS_Lock { + /// @brief Enumerator describing the possible status of a positioning system. enum class LockStatus : uint8_t { Undefined, NotAvailable, Has2D, Has3D }; - LockStatus galileo; - LockStatus beidou; - LockStatus glonass; - LockStatus gps; + LockStatus galileo; ///< Status for the Galileo system (European system). + LockStatus beidou; ///< Status for the BeiDou system (Chinese system). + LockStatus glonass; ///< Status for the GLONASS system (Russian system). + LockStatus gps; ///< Status for the GPS system (American system). }; - /** @brief Configuration settings for a stream. */ + /// @brief Configuration settings for a stream. struct StreamConfig { - /** @brief Extra configuration settings for a stream. */ + /// @brief Extra configuration settings for a stream. struct Extras { + struct PacketTransmission { + uint16_t samplesInPacket; ///< The amount of samples to transfer in a single packet. + uint32_t packetsInBatch; ///< The amount of packets to send in a single transfer. + }; + Extras(); - bool usePoll; - uint16_t rxSamplesInPacket; - uint32_t rxPacketsInBatch; - uint32_t txMaxPacketsInBatch; - uint16_t txSamplesInPacket; - bool negateQ; - bool waitPPS; // start sampling from next following PPS + bool usePoll; ///< Whether to use a polling strategy for PCIe devices. + + PacketTransmission rx; ///< Configuration of the receive transfer direction. + PacketTransmission tx; ///< Configuration of the transmit transfer direction. + + bool negateQ; ///< Whether to negate the Q element before sending the data or not. + bool waitPPS; ///< Start sampling from next following PPS. }; + + /// @brief The definition of the function that gets called whenever a stream status changes. typedef bool (*StatusCallbackFunc)(bool isTx, const StreamStats* stats, void* userData); + + /// @brief Enumerator describing the data format. enum class DataFormat : uint8_t { - I16, - I12, - F32, + I16, ///< Data is in a form of two 16-bit integers. + I12, ///< Data is in a form of two 12-bit integers. + F32, ///< Data is in a form of two 32-bit floating-point values. }; StreamConfig(); ~StreamConfig(); + + /// @brief The copy operator of of the class. + /// @param srd The + /// @return StreamConfig& operator=(const StreamConfig& srd); - uint8_t rxCount; - uint8_t rxChannels[MAX_CHANNEL_COUNT]; - uint8_t txCount; - uint8_t txChannels[MAX_CHANNEL_COUNT]; + uint8_t rxCount; ///< The amount of Receive channels being used. + uint8_t rxChannels[MAX_CHANNEL_COUNT]; ///< The list of Receive channels being used. + uint8_t txCount; ///< The amount of Transmit channels being used. + uint8_t txChannels[MAX_CHANNEL_COUNT]; ///< The list of Transmit channels being used. - DataFormat format; // samples format used for Read/Write functions - DataFormat linkFormat; // samples format used in transport layer Host<->FPGA + DataFormat format; ///< Samples format used for Read/Write functions + DataFormat linkFormat; ///< Samples format used in transport layer Host<->FPGA - /// memory size to allocate for each channel buffering - /// Default: 0 - allow to decide internally + /// @brief Memory size to allocate for each channel buffering. + /// Default: 0 - allow to decide internally. uint32_t bufferSize; - /// optional: expected sampling rate for data transfer optimizations. - /// Default: 0 - deicide internally + /// Optional: expected sampling rate for data transfer optimizations. + /// Default: 0 - decide internally. float hintSampleRate; - bool alignPhase; // attempt to do phases alignment between paired channels + bool alignPhase; ///< Attempt to do phases alignment between paired channels - StatusCallbackFunc statusCallback; - void* userData; // will be supplied to statusCallback + StatusCallbackFunc statusCallback; ///< Function to call on a status change. + void* userData; ///< Data that will be supplied to statusCallback // TODO: callback for drops and errors - Extras* extraConfig; + Extras* extraConfig; ///< A pointer to some extra stream configuration settings. }; - /** @brief The metadata of a stream packet. */ + /// @brief The metadata of a stream packet. struct StreamMeta { /** * Timestamp is a value of HW counter with a tick based on sample rate. @@ -202,129 +221,228 @@ class LIME_API SDRDevice bool flushPartialPacket; }; - /** @brief Configuration of a general finite impulse response (FIR) filter. */ + /// @brief Configuration of a general finite impulse response (FIR) filter. struct GFIRFilter { - double bandwidth; - bool enabled; + double bandwidth; ///< The bandwidth of the filter. + bool enabled; ///< Whether the filter is enabled or not. }; - /** @brief Configuration of a single channel. */ + /// @brief Configuration of a single channel. struct ChannelConfig { ChannelConfig() { memset(this, 0, sizeof(ChannelConfig)); } - /** @brief Configuration for a direction in a channel. */ + /// @brief Configuration for a direction in a channel. struct Direction { - double centerFrequency; - double NCOoffset; - double sampleRate; - double gain; - double lpf; - uint8_t path; - uint8_t oversample; - GFIRFilter gfir; - bool enabled; - bool calibrate; - bool testSignal; + double centerFrequency; ///< The center frequency of the direction of this channel. + double NCOoffset; ///< The offset from the channel's numerically controlled oscillator (NCO). + double sampleRate; ///< The sample rate of this direction of a channel. + double gain; ///< TODO: Not fully implemented yet + double lpf; ///< The bandwidth of the Low Pass Filter (LPF). + uint8_t path; ///< The antenna being used for this direction. + uint8_t oversample; ///< The oversample ratio of this direction. + GFIRFilter gfir; ///< The general finite impulse response (FIR) filter settings of this direction. + bool enabled; ///< Denotes whether this direction of a channel is enabled or not. + bool calibrate; ///< Denotes whether the device will be calibrated or not. + bool testSignal; ///< Denotes whether the signal being sent is a test signal or not. }; - Direction rx; - Direction tx; + + Direction rx; ///< Configuration settings for the Receive channel. + Direction tx; ///< Configuration settings for the Transmit channel. }; - /** @brief Configuration of an SDR device. */ + /// @brief Configuration of an SDR device. struct SDRConfig { SDRConfig() : referenceClockFreq(0) , skipDefaults(false){}; - double referenceClockFreq; - ChannelConfig channel[MAX_CHANNEL_COUNT]; + double referenceClockFreq; ///< The reference clock frequency of the device. + ChannelConfig channel[MAX_CHANNEL_COUNT]; ///< The configuration settings for each of the channels. // Loopback setup? - bool skipDefaults; // skip default values initialization and write on top of current config + bool skipDefaults; ///< Skip default values initialization and write on top of current config. }; virtual ~SDRDevice(){}; + /// @brief Configures the device using the given configuration. + /// @param config The configuration to set up the device with. + /// @param moduleIndex The device index to configure. virtual void Configure(const SDRConfig& config, uint8_t moduleIndex) = 0; - /** @brief Returns SPI slave names and chip select IDs for use with SDRDevice::SPI() */ + /// @brief Gets the Descriptor of the SDR Device. + /// @return The Descriptor of the device. virtual const Descriptor& GetDescriptor() = 0; + /// @brief Initializes the device with initial settings. + /// @return The success status of the initialization (0 on success). virtual int Init() = 0; + + /// @brief Resets the device. virtual void Reset() = 0; + + /// @brief Gets the current status of the GPS locks. + /// @param status The pointer to which to output the GPS status. virtual void GetGPSLock(GPS_Lock* status) = 0; + /// @brief Gets the current sample rate of the device. + /// @param moduleIndex The device index to get the sample rate of. + /// @param trx The direction of the sample rate to get. + /// @return The sample rate of the specified device and direction. virtual double GetSampleRate(uint8_t moduleIndex, TRXDir trx) = 0; + /// @brief Gets the frequency of a specified clock. + /// @param clk_id The clock ID to get the frequency of. + /// @param channel The channel to get the frequency of. + /// @return The frequency of the specified clock (in Hz). virtual double GetClockFreq(uint8_t clk_id, uint8_t channel) = 0; + + /// @brief Sets the frequency of a specified clock. + /// @param clk_id The clock ID to set the frequency of. + /// @param freq The new frequency of the specified clock (in Hz). + /// @param channel The channel to set the frequency of. virtual void SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) = 0; + /// @brief Synchronizes the cached changed register values on the host with the real values on the device. + /// @param toChip The direction in which to synchronize (true = uploads to the device). virtual void Synchronize(bool toChip) = 0; + + /// @brief Enable or disable register value caching on the host side. + /// @param enable Whether to enable or disable the register value caching (true = enabled). virtual void EnableCache(bool enable) = 0; + /// @brief Sets up all the streams on a device. + /// @param config The configuration to use for setting the streams up. + /// @param moduleIndex The index of the device to set up. + /// @return Success status (0 on success). virtual int StreamSetup(const StreamConfig& config, uint8_t moduleIndex) = 0; + + /// @brief Starts all the set up streams on the device. + /// @param moduleIndex The index of the device to start the streams on. virtual void StreamStart(uint8_t moduleIndex) = 0; + + /// @brief Stops all the set up streams on the device. + /// @param moduleIndex The index of the device to stop the streams on. virtual void StreamStop(uint8_t moduleIndex) = 0; + /// @brief Reveives samples from all the active streams in the device. + /// @param moduleIndex The index of the device to receive the samples from. + /// @param samples The buffer to put the received samples in. + /// @param count The amount of samples to reveive. + /// @param meta The metadata of the packets of the stream. + /// @return The amount of samples received. virtual int StreamRx(uint8_t moduleIndex, lime::complex32f_t** samples, uint32_t count, StreamMeta* meta) = 0; + /// @copydoc SDRDevice::StreamRx() virtual int StreamRx(uint8_t moduleIndex, lime::complex16_t** samples, uint32_t count, StreamMeta* meta) = 0; + + /// @brief Transmits packets from all the active streams in the device. + /// @param moduleIndex The index of the device to transmit the samples with. + /// @param samples The buffer of the samples to transmit. + /// @param count The amount of samples to transmit. + /// @param meta The metadata of the packets of the stream. + /// @return The amount of samples transmitted. virtual int StreamTx(uint8_t moduleIndex, const lime::complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) = 0; + /// @copydoc SDRDevice::StreamTx() virtual int StreamTx(uint8_t moduleIndex, const lime::complex16_t* const* samples, uint32_t count, const StreamMeta* meta) = 0; + + /// @brief Retrieves the current stream statistics. + /// @param moduleIndex The index of the device to retrieve the status from. + /// @param rx The pointer (or nullptr if not needed) to store the receive statistics to. + /// @param tx The pointer (or nullptr if not needed) to store the transmit statistics to. virtual void StreamStatus(uint8_t moduleIndex, SDRDevice::StreamStats* rx, SDRDevice::StreamStats* tx) = 0; + /// @brief Uploads waveform to on board memory for later use. + /// @param config The configuration of the stream. + /// @param moduleIndex The index of the device to upload the waveform to. + /// @param samples The samples to upload to the device. + /// @param count The amount of samples to upload to the device. + /// @return Operation status (0 on success). virtual int UploadTxWaveform(const StreamConfig& config, uint8_t moduleIndex, const void** samples, uint32_t count) { return -1; } + /// @copydoc ISPI::SPI() + /// @param spiBusAddress The SPI address of the device to use. virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) = 0; + + /// @copydoc II2C::I2CWrite() virtual int I2CWrite(int address, const uint8_t* data, uint32_t length) = 0; - virtual int I2CRead(int addres, uint8_t* dest, uint32_t length) = 0; + + /// @copydoc II2C::I2CRead() + virtual int I2CRead(int address, uint8_t* dest, uint32_t length) = 0; /*********************************************************************** * GPIO API **********************************************************************/ - /** \copydoc IComms::GPIOWrite() */ + /// @copydoc IComms::GPIOWrite() virtual int GPIOWrite(const uint8_t* buffer, const size_t bufLength) { return -1; }; - /** \copydoc IComms::GPIORead() */ + /// @copydoc IComms::GPIORead() virtual int GPIORead(uint8_t* buffer, const size_t bufLength) { return -1; }; - /** \copydoc IComms::GPIODirWrite() */ + /// @copydoc IComms::GPIODirWrite() virtual int GPIODirWrite(const uint8_t* buffer, const size_t bufLength) { return -1; }; - /** \copydoc IComms::GPIODirRead() */ + /// @copydoc IComms::GPIODirRead() virtual int GPIODirRead(uint8_t* buffer, const size_t bufLength) { return -1; }; /*********************************************************************** * Aribtrary settings API **********************************************************************/ - /** @brief Sets custom on board control to given value units - @param parameters A vector of parameters describing the parameter to write - @return The operation success state - */ + /// @copydoc IComms::CustomParameterWrite() virtual int CustomParameterWrite(const std::vector& parameters) { return -1; }; - /** @brief Returns value of custom on board control - @param parameters A vector of parameters describing the parameter to read - @return The operation success state - */ + /// @copydoc IComms::CustomParameterRead() virtual int CustomParameterRead(std::vector& parameters) { return -1; }; - /** @brief Sets callback function which gets called each time data is sent or received */ + /// @brief The definition of a function to run when data is received. + typedef void (*DataCallbackType)(bool, const uint8_t*, const uint32_t); + + /// @brief Sets callback function which gets called each time data is sent or received + /// @param callback The callback to use from this point onwards. virtual void SetDataLogCallback(DataCallbackType callback){}; + + /// @brief The definition of a function to call when a log message is generated. + typedef void (*LogCallbackType)(LogLevel, const char*); + + /// @brief Sets callback function which gets called each a log message is received + /// @param callback The callback to use from this point onwards. virtual void SetMessageLogCallback(LogCallbackType callback){}; + /// @brief Gets the pointer to an internal chip of the device. + /// @param index The index of the device to retreive. + /// @return The pointer to the internal device. virtual void* GetInternalChip(uint32_t index) { return nullptr; }; + /// @brief The definition of a function to call whenever memory is being uploaded. typedef bool (*UploadMemoryCallback)(size_t bsent, size_t btotal, const char* statusMessage); - virtual bool UploadMemory( + + /// @brief Uploads the given memory into the specified device. + /// @param device The memory device to upload the memory to. + /// @param moduleIndex The index of the main device to upload the memory to. + /// @param data The data to upload to the device. + /// @param length The length of the memory to upload. + /// @param callback The callback to call for status updates. + /// @return The success status of the operation (0 on success). + virtual int UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) { return -1; }; + /// @brief Writes given data into a given memory address in EEPROM memory. + /// @param storage The storage device to write to. + /// @param region Information of the region in which to write the data to. + /// @param data The data to write into the specified memory. + /// @return The operation success state. virtual int MemoryWrite(std::shared_ptr storage, Region region, const void* data) { return -1; }; + + /// @brief Reads data from a given memory address in EEPROM memory. + /// @param storage The storage device to read from. + /// @param region Information of the region from which to read the memory. + /// @param data The storage buffer for the data being read. + /// @return The operation success state. virtual int MemoryRead(std::shared_ptr storage, Region region, void* data) { return -1; }; }; diff --git a/src/lms7002m/LMS7002M.cpp b/src/lms7002m/LMS7002M.cpp index 8b598c378..662897fcf 100644 --- a/src/lms7002m/LMS7002M.cpp +++ b/src/lms7002m/LMS7002M.cpp @@ -2956,11 +2956,11 @@ int LMS7002M::SetInterfaceFrequency(float_type cgen_freq_Hz, const uint8_t inter float_type LMS7002M::GetSampleRate(TRXDir dir, Channel ch) { + ChannelScope(this, ch); float_type interface_Hz; int ratio; - auto chBck = GetActiveChannel(); - SetActiveChannel(ch); - //if decimation/interpolation is 0(2^1) or 7(bypass), interface clocks should not be divided + + // If decimation/interpolation is 0(2^1) or 7(bypass), interface clocks should not be divided if (dir == TRXDir::Tx) { ratio = Get_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP), true); @@ -2971,7 +2971,7 @@ float_type LMS7002M::GetSampleRate(TRXDir dir, Channel ch) ratio = Get_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), true); interface_Hz = GetReferenceClk_TSP(TRXDir::Rx); } - SetActiveChannel(chBck); + if (ratio != 7) interface_Hz /= pow(2.0, ratio); return interface_Hz / 2.0; diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index fa2dbb6e2..728129111 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -612,22 +612,22 @@ bool TRXLooper::IsStreamRunning() return mStreamEnabled; } -int TRXLooper::StreamRx(lime::complex32f_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) +template int TRXLooper::StreamRxTemplate(T** dest, uint32_t count, SDRDevice::StreamMeta* meta) { bool timestampSet = false; uint32_t samplesProduced = 0; const bool useChannelB = mConfig.rxCount > 1; - lime::complex32f_t* f32_dest[2] = { static_cast(dest[0]), - useChannelB ? static_cast(dest[1]) : nullptr }; - bool firstIteration = true; //auto start = high_resolution_clock::now(); while (samplesProduced < count) { - if (!mRx.stagingPacket && !mRx.fifo->pop(&mRx.stagingPacket, firstIteration, 2000)) + if (!mRx.stagingPacket && !mRx.fifo->pop(&mRx.stagingPacket, firstIteration, 250)) + { return samplesProduced; + } + if (!timestampSet && meta) { meta->timestamp = mRx.stagingPacket->metadata.timestamp; @@ -637,11 +637,15 @@ int TRXLooper::StreamRx(lime::complex32f_t** dest, uint32_t count, SDRDevice::St uint32_t expectedCount = count - samplesProduced; const uint32_t samplesToCopy = std::min(expectedCount, mRx.stagingPacket->size()); - lime::complex32f_t* const* f32_src = reinterpret_cast(mRx.stagingPacket->front()); + T* const* src = reinterpret_cast(mRx.stagingPacket->front()); + + std::memcpy(&dest[0][samplesProduced], src[0], samplesToCopy * sizeof(T)); - memcpy(&f32_dest[0][samplesProduced], f32_src[0], samplesToCopy * sizeof(complex32f_t)); if (useChannelB) - memcpy(&f32_dest[1][samplesProduced], f32_src[1], samplesToCopy * sizeof(complex32f_t)); + { + std::memcpy(&dest[1][samplesProduced], src[1], samplesToCopy * sizeof(T)); + } + mRx.stagingPacket->pop(samplesToCopy); samplesProduced += samplesToCopy; @@ -655,52 +659,21 @@ int TRXLooper::StreamRx(lime::complex32f_t** dest, uint32_t count, SDRDevice::St // if(duration > 300) // TODO: timeout duration in meta // return samplesProduced; } + return samplesProduced; } -int TRXLooper::StreamRx(lime::complex16_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) +int TRXLooper::StreamRx(complex32f_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) { - bool timestampSet = false; - uint32_t samplesProduced = 0; - const bool useChannelB = mConfig.rxCount > 1; - bool firstIteration = true; - - //auto start = high_resolution_clock::now(); - while (samplesProduced < count) - { - if (!mRx.stagingPacket && !mRx.fifo->pop(&mRx.stagingPacket, firstIteration, 250)) - return samplesProduced; - if (!timestampSet && meta) - { - meta->timestamp = mRx.stagingPacket->metadata.timestamp; - timestampSet = true; - } - - uint32_t expectedCount = count - samplesProduced; - const uint32_t samplesToCopy = std::min(expectedCount, mRx.stagingPacket->size()); - - lime::complex16_t* const* src = reinterpret_cast(mRx.stagingPacket->front()); - - memcpy(&dest[0][samplesProduced], src[0], samplesToCopy * sizeof(complex16_t)); - if (useChannelB) - memcpy(&dest[1][samplesProduced], src[1], samplesToCopy * sizeof(complex16_t)); - mRx.stagingPacket->pop(samplesToCopy); - samplesProduced += samplesToCopy; - - if (mRx.stagingPacket->empty()) - { - mRx.memPool->Free(mRx.stagingPacket); - mRx.stagingPacket = nullptr; - } + return StreamRxTemplate(dest, count, meta); +} - // int duration = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count(); - // if(duration > 300) // TODO: timeout duration in meta - // return samplesProduced; - } - return samplesProduced; +int TRXLooper::StreamRx(complex16_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) +{ + return StreamRxTemplate(dest, count, meta); } -int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) +template int TRXLooper::StreamTxTemplate(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { const bool useChannelB = mConfig.txCount > 1; const bool useTimestamp = meta ? meta->waitForTimestamp : false; @@ -711,24 +684,31 @@ int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count const int samplesInPkt = mTx.samplesInPkt; const int packetsToBatch = mTx.packetsToBatch; - const int32_t outputPktSize = SamplesPacketType::headerSize + packetsToBatch * samplesInPkt * sizeof(complex32f_t); + const int32_t outputPktSize = SamplesPacketType::headerSize + packetsToBatch * samplesInPkt * sizeof(T); if (mTx.stagingPacket && mTx.stagingPacket->metadata.timestamp + mTx.stagingPacket->size() != meta->timestamp) { if (!mTx.fifo->push(mTx.stagingPacket)) + { return 0; + } + mTx.stagingPacket = nullptr; } - const lime::complex32f_t* src[2] = { samples[0], useChannelB ? samples[1] : nullptr }; + const T* src[2] = { samples[0], useChannelB ? samples[1] : nullptr }; while (samplesRemaining) { if (!mTx.stagingPacket) { mTx.stagingPacket = SamplesPacketType::ConstructSamplesPacket( - mTx.memPool->Allocate(outputPktSize), samplesInPkt * packetsToBatch, sizeof(complex32f_t)); + mTx.memPool->Allocate(outputPktSize), samplesInPkt * packetsToBatch, sizeof(T)); + if (!mTx.stagingPacket) + { break; + } + mTx.stagingPacket->Reset(); mTx.stagingPacket->metadata.timestamp = ts; mTx.stagingPacket->metadata.waitForTimestamp = useTimestamp; @@ -737,7 +717,9 @@ int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count int consumed = mTx.stagingPacket->push(src, samplesRemaining); src[0] += consumed; if (useChannelB) + { src[1] += consumed; + } samplesRemaining -= consumed; ts += consumed; @@ -745,68 +727,30 @@ int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count if (mTx.stagingPacket->isFull() || flush) { if (samplesRemaining == 0) + { mTx.stagingPacket->metadata.flushPartialPacket = flush; + } if (!mTx.fifo->push(mTx.stagingPacket)) + { break; + } + mTx.stagingPacket = nullptr; } } + return count - samplesRemaining; } -int TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) +int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { - const bool useChannelB = mConfig.txCount > 1; - const bool useTimestamp = meta ? meta->waitForTimestamp : false; - const bool flush = meta && meta->flushPartialPacket; - int64_t ts = meta ? meta->timestamp : 0; - - int samplesRemaining = count; - const int samplesInPkt = mTx.samplesInPkt; - const int packetsToBatch = mTx.packetsToBatch; - const int32_t outputPktSize = SamplesPacketType::headerSize + packetsToBatch * samplesInPkt * sizeof(complex16_t); - - if (mTx.stagingPacket && mTx.stagingPacket->metadata.timestamp + mTx.stagingPacket->size() != meta->timestamp) - { - if (!mTx.fifo->push(mTx.stagingPacket)) - return 0; - mTx.stagingPacket = nullptr; - } - - const lime::complex16_t* src[2] = { samples[0], useChannelB ? samples[1] : nullptr }; - while (samplesRemaining) - { - if (!mTx.stagingPacket) - { - mTx.stagingPacket = SamplesPacketType::ConstructSamplesPacket( - mTx.memPool->Allocate(outputPktSize), samplesInPkt * packetsToBatch, sizeof(complex16_t)); - if (!mTx.stagingPacket) - break; - mTx.stagingPacket->Reset(); - mTx.stagingPacket->metadata.timestamp = ts; - mTx.stagingPacket->metadata.waitForTimestamp = useTimestamp; - } - - int consumed = mTx.stagingPacket->push(src, samplesRemaining); - src[0] += consumed; - if (useChannelB) - src[1] += consumed; - - samplesRemaining -= consumed; - ts += consumed; - - if (mTx.stagingPacket->isFull() || flush) - { - if (samplesRemaining == 0) - mTx.stagingPacket->metadata.flushPartialPacket = flush; + return StreamTxTemplate(samples, count, meta); +} - if (!mTx.fifo->push(mTx.stagingPacket)) - break; - mTx.stagingPacket = nullptr; - } - } - return count - samplesRemaining; +int TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) +{ + return StreamTxTemplate(samples, count, meta); } SDRDevice::StreamStats TRXLooper::GetStats(TRXDir dir) diff --git a/src/protocols/TRXLooper.h b/src/protocols/TRXLooper.h index 083784a1f..e3628fb6d 100644 --- a/src/protocols/TRXLooper.h +++ b/src/protocols/TRXLooper.h @@ -95,6 +95,10 @@ class TRXLooper Stream mRx; Stream mTx; + + private: + template int StreamRxTemplate(T** dest, uint32_t count, SDRDevice::StreamMeta* meta); + template int StreamTxTemplate(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); }; } // namespace lime From eba9cf91234f9d69a71da2158a6221cc2c3b2f50 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Fri, 22 Dec 2023 15:43:43 +0200 Subject: [PATCH 16/46] Document all the main device classes --- src/ADF4002/ADF4002.cpp | 7 ++++--- src/ADF4002/ADF4002.h | 7 ++++--- src/FPGA_common/FPGA_common.cpp | 15 +++++++++++---- src/boards/LMS7002M_SDRDevice.h | 2 ++ src/boards/LimeSDR/LimeSDR.cpp | 5 +++++ src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp | 5 +++++ src/boards/LimeSDR_X3/LimeSDR_X3.cpp | 14 ++++++++++---- src/boards/LimeSDR_X3/LimeSDR_X3.h | 1 - src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 10 ++++++++-- src/boards/MMX8/MM_X8.cpp | 12 +++++++++--- src/boards/MMX8/MM_X8.h | 2 +- src/boards/MMX8/MM_X8Entry.cpp | 2 +- 12 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/ADF4002/ADF4002.cpp b/src/ADF4002/ADF4002.cpp index 8a517a5e1..e67b0798e 100644 --- a/src/ADF4002/ADF4002.cpp +++ b/src/ADF4002/ADF4002.cpp @@ -8,8 +8,9 @@ #include #include -#include -#include +#include +#include +#include using namespace lime; @@ -22,7 +23,7 @@ ADF4002::~ADF4002() { } -void ADF4002::Initialize(ISPI* comms, double refClkHz) +void ADF4002::Initialize(std::shared_ptr comms, double refClkHz) { mComms = comms; txtFref = refClkHz / 1e6; diff --git a/src/ADF4002/ADF4002.h b/src/ADF4002/ADF4002.h index 57f3022fb..7417d6817 100644 --- a/src/ADF4002/ADF4002.h +++ b/src/ADF4002/ADF4002.h @@ -8,9 +8,10 @@ #define ADF_MODULE_H #include "limesuite/config.h" - #include "limesuite/IComms.h" +#include + namespace lime { /** @brief The class for controlling the ADF4002 frequency synthesizer. @@ -22,7 +23,7 @@ class LIME_API ADF4002 public: ADF4002(); ~ADF4002(); - void Initialize(ISPI* comms, double refClkHz); + void Initialize(std::shared_ptr comms, double refClkHz); int UploadConfig(); void SetFrefFvco(double Fref, double Fvco, int& rcount, int& ncount); @@ -71,7 +72,7 @@ class LIME_API ADF4002 double lblFvco; protected: - ISPI* mComms; + std::shared_ptr mComms; unsigned char m_registers[12]; }; diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 6e6e6f725..4d440113f 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -125,15 +125,22 @@ void FPGA::EnableValuesCache(bool enabled) regsCache.clear(); } -int FPGA::WriteRegister(uint32_t addr, uint32_t val) +/// @brief Writes the specified value into the specified address into the FPGA. +/// @param address The address to write to. +/// @param value The value to write. +/// @return The operation status (0 on success). +int FPGA::WriteRegister(uint32_t address, uint32_t value) { - return WriteRegisters(&addr, &val, 1); + return WriteRegisters(&address, &value, 1); } -int FPGA::ReadRegister(uint32_t addr) +/// @brief Reads a value from the specified address in the FPGA. +/// @param address The address to read from. +/// @return The value of the register (or -1 on failure). +int FPGA::ReadRegister(uint32_t address) { uint32_t val; - return ReadRegisters(&addr, &val, 1) != 0 ? -1 : val; + return ReadRegisters(&address, &val, 1) != 0 ? -1 : val; } int FPGA::WriteRegisters(const uint32_t* addrs, const uint32_t* data, unsigned cnt) diff --git a/src/boards/LMS7002M_SDRDevice.h b/src/boards/LMS7002M_SDRDevice.h index b35020441..72a2c1b3e 100644 --- a/src/boards/LMS7002M_SDRDevice.h +++ b/src/boards/LMS7002M_SDRDevice.h @@ -66,7 +66,9 @@ class LIME_API LMS7002M_SDRDevice : public SDRDevice virtual int UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) override; + /// @copydoc FPGA::ReadRegister() virtual int ReadFPGARegister(uint32_t address); + /// @copydoc FPGA::WriteRegister() virtual int WriteFPGARegister(uint32_t address, uint32_t value); protected: diff --git a/src/boards/LimeSDR/LimeSDR.cpp b/src/boards/LimeSDR/LimeSDR.cpp index 2265d8c5f..ce49a384d 100644 --- a/src/boards/LimeSDR/LimeSDR.cpp +++ b/src/boards/LimeSDR/LimeSDR.cpp @@ -107,6 +107,11 @@ static inline void ValidateChannel(uint8_t channel) throw std::logic_error("invalid channel index"); } +/// @brief Constructs a new LimeSDR object +/// @param spiLMS The communications port to the LMS7002M chip. +/// @param spiFPGA The communications port to the device's FPGA. +/// @param streamPort The communications port to send and receive sample data. +/// @param commsPort The communications port for direct communications with the device. LimeSDR::LimeSDR(std::shared_ptr spiLMS, std::shared_ptr spiFPGA, std::shared_ptr streamPort, diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp index 99ad7d1f9..bb2b643ad 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp @@ -135,6 +135,11 @@ static const std::vector> lms7002defaultsOverrides { 0x040C, 0x00FB } }; +/// @brief Constructs a new LimeSDR_Mini object +/// @param spiLMS The communications port to the LMS7002M chip. +/// @param spiFPGA The communications port to the device's FPGA. +/// @param streamPort The communications port to send and receive sample data. +/// @param commsPort The communications port for direct communications with the device. LimeSDR_Mini::LimeSDR_Mini(std::shared_ptr spiLMS, std::shared_ptr spiFPGA, std::shared_ptr streamPort, diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp index 048785126..d8c04539c 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp @@ -154,8 +154,15 @@ int LimeSDR_X3::LMS1_UpdateFPGAInterface(void* userData) return UpdateFPGAInterfaceFrequency(*soc, *pthis->mFPGA, chipIndex); } -// Do not perform any unnecessary configuring to device in constructor, so you -// could read back it's state for debugging purposes + +/// @brief Constructs a new LimeSDR_X3 object +/// +/// Do not perform any unnecessary configuring to device in constructor, so you +/// could read back it's state for debugging purposes +/// @param spiLMS7002M The communications port to the LMS7002M chips. +/// @param spiFPGA The communications port to the device's FPGA. +/// @param trxStreams The communications ports to send and receive sample data. +/// @param control The serial port of the device for retrieving device firmware information. LimeSDR_X3::LimeSDR_X3(std::shared_ptr spiLMS7002M, std::shared_ptr spiFPGA, std::vector> trxStreams, @@ -163,13 +170,12 @@ LimeSDR_X3::LimeSDR_X3(std::shared_ptr spiLMS7002M, : LMS7002M_SDRDevice() , mTRXStreamPorts(trxStreams) , mfpgaPort(spiFPGA) - , mSerialPort(control) , mConfigInProgress(false) { SDRDevice::Descriptor& desc = mDeviceDescriptor; LMS64CProtocol::FirmwareInfo fw; - LMS64CProtocol::GetFirmwareInfo(*mSerialPort, fw); + LMS64CProtocol::GetFirmwareInfo(*control, fw); LMS64CProtocol::FirmwareToDescriptor(fw, desc); desc.spiSlaveIds = { diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.h b/src/boards/LimeSDR_X3/LimeSDR_X3.h index 01c087a83..c7299f9fe 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.h +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.h @@ -82,7 +82,6 @@ class LimeSDR_X3 : public LMS7002M_SDRDevice std::array, 3> mLMS7002Mcomms; std::shared_ptr mfpgaPort; - std::shared_ptr mSerialPort; std::mutex mCommsMutex; bool mConfigInProgress; }; diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index ec17c8a7f..f25fc9273 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -101,8 +101,14 @@ int LimeSDR_XTRX::LMS1_UpdateFPGAInterface(void* userData) return UpdateFPGAInterfaceFrequency(*soc, *pthis->mFPGA, chipIndex); } -// Do not perform any unnecessary configuring to device in constructor, so you -// could read back it's state for debugging purposes +/// @brief Constructs a new LimeSDR_XTRX object +/// +/// Do not perform any unnecessary configuring to device in constructor, so you +/// could read back it's state for debugging purposes. +/// @param spiRFsoc The communications port to the LMS7002M chip. +/// @param spiFPGA The communications port to the device's FPGA. +/// @param sampleStream The communications port to send and receive sample data. +/// @param refClk The reference clock of the device. LimeSDR_XTRX::LimeSDR_XTRX( std::shared_ptr spiRFsoc, std::shared_ptr spiFPGA, std::shared_ptr sampleStream, double refClk) : LMS7002M_SDRDevice() diff --git a/src/boards/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index e2cab937b..2df729f03 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -21,12 +21,18 @@ namespace lime { static SDRDevice::CustomParameter cp_vctcxo_dac = { "VCTCXO DAC (volatile)", 0, 0, 65535, false }; static double X8ReferenceClock = 30.72e6; -// Do not perform any unnecessary configuring to device in constructor, so you -// could read back it's state for debugging purposes +/// @brief Constructs the LimeSDR_MMX8 object. +/// +/// Do not perform any unnecessary configuring to device in constructor, so you +/// could read back it's state for debugging purposes +/// @param spiLMS7002M The communications ports to the LMS7002M chips. +/// @param spiFPGA The communications ports to the device's FPGA chips. +/// @param trxStreams The communications ports to send and receive sample data. +/// @param adfComms The communications port to the device's ADF4002 chip. LimeSDR_MMX8::LimeSDR_MMX8(std::vector>& spiLMS7002M, std::vector>& spiFPGA, std::vector> trxStreams, - ISPI* adfComms) + std::shared_ptr adfComms) : mTRXStreamPorts(trxStreams) { mMainFPGAcomms = spiFPGA[8]; diff --git a/src/boards/MMX8/MM_X8.h b/src/boards/MMX8/MM_X8.h index 1fa32be08..b31f75117 100644 --- a/src/boards/MMX8/MM_X8.h +++ b/src/boards/MMX8/MM_X8.h @@ -26,7 +26,7 @@ class LimeSDR_MMX8 : public SDRDevice LimeSDR_MMX8(std::vector>& spiLMS7002M, std::vector>& spiFPGA, std::vector> trxStreams, - ISPI* adfComms); + std::shared_ptr adfComms); virtual ~LimeSDR_MMX8(); virtual void Configure(const SDRConfig& config, uint8_t socIndex) override; diff --git a/src/boards/MMX8/MM_X8Entry.cpp b/src/boards/MMX8/MM_X8Entry.cpp index adb14a6d0..c9819e903 100644 --- a/src/boards/MMX8/MM_X8Entry.cpp +++ b/src/boards/MMX8/MM_X8Entry.cpp @@ -84,7 +84,7 @@ SDRDevice* LimeSDR_MMX8Entry::make(const DeviceHandle& handle) std::vector> trxStreams(8); std::vector> controls(8); std::vector> fpga(8); - ISPI* adfComms = new LMS64C_ADF_Over_PCIe_MMX8(control, 0); + auto adfComms = std::make_shared(control, 0); for (size_t i = 0; i < controls.size(); ++i) { controls[i] = std::make_shared(control, i + 1); From 4e345157e11a83a97a08b607c37e794ac5640a41 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Fri, 22 Dec 2023 16:18:04 +0200 Subject: [PATCH 17/46] Fix PacketsFIFO documentation, document MemoryPool and WriteRegistersBatch --- src/FPGA_common/FPGA_common.cpp | 9 +++++++ src/memory/MemoryPool.cpp | 14 +++++++++- src/memory/MemoryPool.h | 5 +++- src/protocols/PacketsFIFO.h | 47 +++++++++++++++++---------------- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 4d440113f..a219e7f76 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -30,9 +30,14 @@ namespace lime { class WriteRegistersBatch { public: + /// @brief Constructor for the batch. + /// @param fpga The FPGA this batch belongs to. WriteRegistersBatch(FPGA* fpga) : owner(fpga){}; ~WriteRegistersBatch() { ASSERT_WARNING(addrs.size() == 0, "FPGA WriteRegistersBatch not flushed"); } + + /// @brief Writes the modified values into the FPGA. + /// @return The operation status (0 on success). int Flush() { int status = owner->WriteRegisters(addrs.data(), values.data(), addrs.size()); @@ -40,6 +45,10 @@ class WriteRegistersBatch values.clear(); return status; } + + /// @brief Sets an address value pair to write into the FPGA on flushing. + /// @param addr The address to write to. + /// @param value The value to write. void WriteRegister(uint16_t addr, uint16_t value) { addrs.push_back(addr); diff --git a/src/memory/MemoryPool.cpp b/src/memory/MemoryPool.cpp index 209d19739..c324f132b 100644 --- a/src/memory/MemoryPool.cpp +++ b/src/memory/MemoryPool.cpp @@ -3,6 +3,12 @@ #include namespace lime { + +/// @brief Constructs the Memory Pool and allocates the memory of the pool. +/// @param blockCount The amount of memory blocks to allocate. +/// @param blockSize The memory size of a single block. +/// @param alignment The alignment of the memory. +/// @param name The name of the memory pool. MemoryPool::MemoryPool(int blockCount, int blockSize, int alignment, const std::string& name) : name(name) , allocCnt(0) @@ -11,7 +17,7 @@ MemoryPool::MemoryPool(int blockCount, int blockSize, int alignment, const std:: { for (int i = 0; i < blockCount; ++i) { - void* ptr = aligned_alloc(alignment, blockSize); + void* ptr = std::aligned_alloc(alignment, blockSize); if (!ptr) { throw std::runtime_error("Failed to allocate memory"); @@ -22,6 +28,7 @@ MemoryPool::MemoryPool(int blockCount, int blockSize, int alignment, const std:: ownedAddresses.insert(ptr); } } + MemoryPool::~MemoryPool() { // if(mFreeBlocks.size() != ownedAddresses.size()) @@ -37,6 +44,9 @@ MemoryPool::~MemoryPool() free(ptr); } +/// @brief Gives a block of memory of a given size. +/// @param size The size of the memory to give. Must not be more than the maximum size. +/// @return The pointer to the allocated memory. void* MemoryPool::Allocate(int size) { if (size > mBlockSize) @@ -58,6 +68,8 @@ void* MemoryPool::Allocate(int size) return ptr; } +/// @brief Frees the given memory location. +/// @param ptr The pointer of the memory to free. Must belong to this memory pool. void MemoryPool::Free(void* ptr) { std::lock_guard lock(mLock); diff --git a/src/memory/MemoryPool.h b/src/memory/MemoryPool.h index 34470f9d9..4869b06ab 100644 --- a/src/memory/MemoryPool.h +++ b/src/memory/MemoryPool.h @@ -20,7 +20,10 @@ class MemoryPool void* Allocate(int size); void Free(void* ptr); - int32_t MaxAllocSize() const { return mBlockSize; }; + + /// @brief Gets the maximum possible allocation size of this memory pool. + /// @return The maximum amount of memory (in bytes) this pool can allocate. + constexpr int32_t MaxAllocSize() const { return mBlockSize; }; private: std::string name; diff --git a/src/protocols/PacketsFIFO.h b/src/protocols/PacketsFIFO.h index 93b693bb5..615e1d48f 100644 --- a/src/protocols/PacketsFIFO.h +++ b/src/protocols/PacketsFIFO.h @@ -35,13 +35,9 @@ namespace lime { template class PacketsFIFO { public: - std::condition_variable canRead; - std::condition_variable canWrite; - std::mutex mwr; - std::mutex mrd; - ///--------------------------------------------------------------------------- - /// @brief Constructor. Asserts when the underlying type is not lock free + /// @brief Constructor. Asserts when the underlying type is not lock free. + /// @param fixedSize The maximum size of the queue. PacketsFIFO(std::size_t fixedSize) : RingBufferSize(fixedSize + 1) { @@ -59,8 +55,8 @@ template class PacketsFIFO } ///--------------------------------------------------------------------------- - /// @brief Returns whether the queue is empty - /// @return True when empty + /// @brief Returns whether the queue is empty. + /// @return True when empty. bool empty() const noexcept { bool isEmpty = false; @@ -76,11 +72,11 @@ template class PacketsFIFO } ///--------------------------------------------------------------------------- - /// @brief Pushes an element to the queue - /// @param element The element to add - /// @param wait Whether to wait or now - /// @param timeout The timeout (in ms) to wait for - /// @return True when the element was added, false when the queue is full + /// @brief Pushes an element to the queue. + /// @param element The element to add. + /// @param wait Whether to wait or now. + /// @param timeout The timeout (in ms) to wait for. + /// @return True when the element was added, false when the queue is full. bool push(const T element, bool wait = false, int timeout = 250) { std::unique_lock lk(mwr); @@ -113,11 +109,11 @@ template class PacketsFIFO } ///--------------------------------------------------------------------------- - /// @brief Pops an element from the queue - /// @param element The returned element - /// @param wait Whether to wait or now - /// @param timeout The timeout (in ms) to wait for - /// @return True when succeeded, false when the queue is empty + /// @brief Pops an element from the queue. + /// @param element The returned element. + /// @param wait Whether to wait or now. + /// @param timeout The timeout (in ms) to wait for. + /// @return True when succeeded, false when the queue is empty. bool pop(T* element, bool wait = false, int timeout = 250) { std::unique_lock lk(mwr); @@ -148,7 +144,7 @@ template class PacketsFIFO } ///--------------------------------------------------------------------------- - /// @brief Clears the content from the queue + /// @brief Clears the content from the queue. void clear() noexcept { const std::size_t readPosition = m_readPosition.load(); @@ -161,16 +157,16 @@ template class PacketsFIFO } ///--------------------------------------------------------------------------- - /// @brief Returns the maximum size of the queue - /// @return The maximum number of elements the queue can hold + /// @brief Returns the maximum size of the queue. + /// @return The maximum number of elements the queue can hold. constexpr std::size_t max_size() const noexcept { return RingBufferSize - 1; } ///--------------------------------------------------------------------------- - /// @brief Returns the actual number of elements in the queue - /// @return The actual size or 0 when empty + /// @brief Returns the actual number of elements in the queue. + /// @return The actual size or 0 when empty. std::size_t size() const noexcept { const std::size_t readPosition = m_readPosition.load(); @@ -201,6 +197,11 @@ template class PacketsFIFO std::atomic m_readPosition = { 0 }; std::atomic m_writePosition = { 0 }; + std::condition_variable canRead; + std::condition_variable canWrite; + std::mutex mwr; + std::mutex mrd; + constexpr std::size_t getPositionAfter(std::size_t pos) const noexcept { return ((pos + 1 == RingBufferSize) ? 0 : pos + 1); From 0b09e53f9b334a1bec9d4dd9b8e630294e04ca8c Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 27 Dec 2023 09:11:33 +0200 Subject: [PATCH 18/46] Make StreamRx/Tx return type be uint32_t everywhere. --- src/StreamComposite.cpp | 29 +++++++++++++++---------- src/boards/LMS7002M_SDRDevice.cpp | 10 +++++---- src/boards/LMS7002M_SDRDevice.h | 10 +++++---- src/boards/MMX8/MM_X8.cpp | 10 +++++---- src/boards/MMX8/MM_X8.h | 8 +++---- src/cli/limeTRX.cpp | 10 ++++----- src/examples/basicRX.cpp | 6 ++--- src/examples/basicTX.cpp | 6 ++--- src/examples/dualRXTX.cpp | 8 +++---- src/include/limesuite/SDRDevice.h | 14 +++++++----- src/include/limesuite/StreamComposite.h | 4 ++-- src/protocols/TRXLooper.cpp | 16 +++++++------- src/protocols/TRXLooper.h | 12 +++++----- src/utilities/rfTest.cpp | 12 +++++----- 14 files changed, 84 insertions(+), 71 deletions(-) diff --git a/src/StreamComposite.cpp b/src/StreamComposite.cpp index 8811a84d3..37bbd37dd 100644 --- a/src/StreamComposite.cpp +++ b/src/StreamComposite.cpp @@ -67,41 +67,46 @@ void StreamComposite::StreamStop() a.device->StreamStop(a.streamIndex); } -template int StreamComposite::StreamRx(T** samples, uint32_t count, SDRDevice::StreamMeta* meta) +template uint32_t StreamComposite::StreamRx(T** samples, uint32_t count, SDRDevice::StreamMeta* meta) { T** dest = samples; for (auto& a : mActiveAggregates) { - int ret = a.device->StreamRx(a.streamIndex, dest, count, meta); - if (ret != static_cast(count)) + uint32_t ret = a.device->StreamRx(a.streamIndex, dest, count, meta); + if (ret != count) + { return ret; + } dest += a.channels.size(); } - return static_cast(count); + return count; } -template int StreamComposite::StreamTx(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) +template uint32_t StreamComposite::StreamTx(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { const T* const* src = samples; for (auto& a : mActiveAggregates) { - int ret = a.device->StreamTx(a.streamIndex, src, count, meta); - if (ret != static_cast(count)) + uint32_t ret = a.device->StreamTx(a.streamIndex, src, count, meta); + if (ret != count) + { return ret; + } src += a.channels.size(); } - return static_cast(count); + return count; } // force instantiate functions with these types -template int StreamComposite::StreamRx(lime::complex16_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); -template int StreamComposite::StreamRx( +template uint32_t StreamComposite::StreamRx( + lime::complex16_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); +template uint32_t StreamComposite::StreamRx( lime::complex32f_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); -template int StreamComposite::StreamTx( +template uint32_t StreamComposite::StreamTx( const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); -template int StreamComposite::StreamTx( +template uint32_t StreamComposite::StreamTx( const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); } // namespace lime diff --git a/src/boards/LMS7002M_SDRDevice.cpp b/src/boards/LMS7002M_SDRDevice.cpp index bf0f719bd..d5df6cb51 100644 --- a/src/boards/LMS7002M_SDRDevice.cpp +++ b/src/boards/LMS7002M_SDRDevice.cpp @@ -179,22 +179,24 @@ void LMS7002M_SDRDevice::StreamStop(uint8_t moduleIndex) mStreamers[moduleIndex] = nullptr; } -int LMS7002M_SDRDevice::StreamRx(uint8_t moduleIndex, complex32f_t** dest, uint32_t count, StreamMeta* meta) +uint32_t LMS7002M_SDRDevice::StreamRx(uint8_t moduleIndex, complex32f_t** dest, uint32_t count, StreamMeta* meta) { return mStreamers[moduleIndex]->StreamRx(dest, count, meta); } -int LMS7002M_SDRDevice::StreamRx(uint8_t moduleIndex, complex16_t** dest, uint32_t count, StreamMeta* meta) +uint32_t LMS7002M_SDRDevice::StreamRx(uint8_t moduleIndex, complex16_t** dest, uint32_t count, StreamMeta* meta) { return mStreamers[moduleIndex]->StreamRx(dest, count, meta); } -int LMS7002M_SDRDevice::StreamTx(uint8_t moduleIndex, const complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) +uint32_t LMS7002M_SDRDevice::StreamTx( + uint8_t moduleIndex, const complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) { return mStreamers[moduleIndex]->StreamTx(samples, count, meta); } -int LMS7002M_SDRDevice::StreamTx(uint8_t moduleIndex, const complex16_t* const* samples, uint32_t count, const StreamMeta* meta) +uint32_t LMS7002M_SDRDevice::StreamTx( + uint8_t moduleIndex, const complex16_t* const* samples, uint32_t count, const StreamMeta* meta) { return mStreamers[moduleIndex]->StreamTx(samples, count, meta); } diff --git a/src/boards/LMS7002M_SDRDevice.h b/src/boards/LMS7002M_SDRDevice.h index 72a2c1b3e..5fc7aa0cc 100644 --- a/src/boards/LMS7002M_SDRDevice.h +++ b/src/boards/LMS7002M_SDRDevice.h @@ -41,10 +41,12 @@ class LIME_API LMS7002M_SDRDevice : public SDRDevice virtual void StreamStart(uint8_t moduleIndex) override; virtual void StreamStop(uint8_t moduleIndex) override; - virtual int StreamRx(uint8_t moduleIndex, complex32f_t** samples, uint32_t count, StreamMeta* meta) override; - virtual int StreamRx(uint8_t moduleIndex, complex16_t** samples, uint32_t count, StreamMeta* meta) override; - virtual int StreamTx(uint8_t moduleIndex, const complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) override; - virtual int StreamTx(uint8_t moduleIndex, const complex16_t* const* samples, uint32_t count, const StreamMeta* meta) override; + virtual uint32_t StreamRx(uint8_t moduleIndex, complex32f_t** samples, uint32_t count, StreamMeta* meta) override; + virtual uint32_t StreamRx(uint8_t moduleIndex, complex16_t** samples, uint32_t count, StreamMeta* meta) override; + virtual uint32_t StreamTx( + uint8_t moduleIndex, const complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) override; + virtual uint32_t StreamTx( + uint8_t moduleIndex, const complex16_t* const* samples, uint32_t count, const StreamMeta* meta) override; virtual void StreamStatus(uint8_t moduleIndex, SDRDevice::StreamStats* rx, SDRDevice::StreamStats* tx) override; virtual int SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; diff --git a/src/boards/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index 2df729f03..aed8613e7 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -204,22 +204,24 @@ void LimeSDR_MMX8::StreamStop(uint8_t moduleIndex) tempFPGA.StopStreaming(); } -int LimeSDR_MMX8::StreamRx(uint8_t moduleIndex, lime::complex32f_t** dest, uint32_t count, StreamMeta* meta) +uint32_t LimeSDR_MMX8::StreamRx(uint8_t moduleIndex, lime::complex32f_t** dest, uint32_t count, StreamMeta* meta) { return mSubDevices[moduleIndex]->StreamRx(0, dest, count, meta); } -int LimeSDR_MMX8::StreamRx(uint8_t moduleIndex, lime::complex16_t** dest, uint32_t count, StreamMeta* meta) +uint32_t LimeSDR_MMX8::StreamRx(uint8_t moduleIndex, lime::complex16_t** dest, uint32_t count, StreamMeta* meta) { return mSubDevices[moduleIndex]->StreamRx(0, dest, count, meta); } -int LimeSDR_MMX8::StreamTx(uint8_t moduleIndex, const lime::complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) +uint32_t LimeSDR_MMX8::StreamTx( + uint8_t moduleIndex, const lime::complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) { return mSubDevices[moduleIndex]->StreamTx(0, samples, count, meta); } -int LimeSDR_MMX8::StreamTx(uint8_t moduleIndex, const lime::complex16_t* const* samples, uint32_t count, const StreamMeta* meta) +uint32_t LimeSDR_MMX8::StreamTx( + uint8_t moduleIndex, const lime::complex16_t* const* samples, uint32_t count, const StreamMeta* meta) { return mSubDevices[moduleIndex]->StreamTx(0, samples, count, meta); } diff --git a/src/boards/MMX8/MM_X8.h b/src/boards/MMX8/MM_X8.h index b31f75117..fc6cf68e4 100644 --- a/src/boards/MMX8/MM_X8.h +++ b/src/boards/MMX8/MM_X8.h @@ -48,11 +48,11 @@ class LimeSDR_MMX8 : public SDRDevice virtual void StreamStart(uint8_t moduleIndex) override; virtual void StreamStop(uint8_t moduleIndex) override; - virtual int StreamRx(uint8_t moduleIndex, lime::complex32f_t** samples, uint32_t count, StreamMeta* meta) override; - virtual int StreamRx(uint8_t moduleIndex, lime::complex16_t** samples, uint32_t count, StreamMeta* meta) override; - virtual int StreamTx( + virtual uint32_t StreamRx(uint8_t moduleIndex, lime::complex32f_t** samples, uint32_t count, StreamMeta* meta) override; + virtual uint32_t StreamRx(uint8_t moduleIndex, lime::complex16_t** samples, uint32_t count, StreamMeta* meta) override; + virtual uint32_t StreamTx( uint8_t moduleIndex, const lime::complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) override; - virtual int StreamTx( + virtual uint32_t StreamTx( uint8_t moduleIndex, const lime::complex16_t* const* samples, uint32_t count, const StreamMeta* meta) override; virtual void StreamStatus(uint8_t moduleIndex, SDRDevice::StreamStats* rx, SDRDevice::StreamStats* tx) override; diff --git a/src/cli/limeTRX.cpp b/src/cli/limeTRX.cpp index 9ca5f330a..707311f6c 100644 --- a/src/cli/limeTRX.cpp +++ b/src/cli/limeTRX.cpp @@ -632,8 +632,8 @@ int main(int argc, char** argv) const complex16_t* txSamples[16]; for (int i = 0; i < 16; ++i) txSamples[i] = &txData[txSent]; - int samplesSent = useComposite ? composite->StreamTx(txSamples, toSend, &txMeta) - : device->StreamTx(chipIndex, txSamples, toSend, &txMeta); + uint32_t samplesSent = useComposite ? composite->StreamTx(txSamples, toSend, &txMeta) + : device->StreamTx(chipIndex, txSamples, toSend, &txMeta); if (samplesSent > 0) { txSent += samplesSent; @@ -645,9 +645,9 @@ int main(int argc, char** argv) complex16_t* rxSamples[16]; for (int i = 0; i < 16; ++i) rxSamples[i] = rxData[i].data(); - int samplesRead = useComposite ? composite->StreamRx(rxSamples, fftSize, &rxMeta) - : device->StreamRx(chipIndex, rxSamples, fftSize, &rxMeta); - if (samplesRead <= 0) + uint32_t samplesRead = useComposite ? composite->StreamRx(rxSamples, fftSize, &rxMeta) + : device->StreamRx(chipIndex, rxSamples, fftSize, &rxMeta); + if (samplesRead == 0) continue; if (tx && repeater) diff --git a/src/examples/basicRX.cpp b/src/examples/basicRX.cpp index 5bf315f15..c0ab4be15 100644 --- a/src/examples/basicRX.cpp +++ b/src/examples/basicRX.cpp @@ -134,8 +134,8 @@ int main(int argc, char** argv) SDRDevice::StreamMeta rxMeta; while (std::chrono::high_resolution_clock::now() - startTime < std::chrono::seconds(10) && !stopProgram) { - int samplesRead = device->StreamRx(chipIndex, rxSamples, fftSize, &rxMeta); - if (samplesRead <= 0) + uint32_t samplesRead = device->StreamRx(chipIndex, rxSamples, fftSize, &rxMeta); + if (samplesRead == 0) continue; // process samples @@ -169,7 +169,7 @@ int main(int argc, char** argv) (frequencyLO + peakFrequency) / 1e6); #ifdef USE_GNU_PLOT gp.write("plot '-' with points\n"); - for (int j = 0; j < samplesRead; ++j) + for (uint32_t j = 0; j < samplesRead; ++j) gp.writef("%f %f\n", rxSamples[0][j].i, rxSamples[0][j].q); gp.write("e\n"); gp.flush(); diff --git a/src/examples/basicTX.cpp b/src/examples/basicTX.cpp index 20ca67be5..b75b6e1b5 100644 --- a/src/examples/basicTX.cpp +++ b/src/examples/basicTX.cpp @@ -131,12 +131,12 @@ int main(int argc, char** argv) txMeta.waitForTimestamp = true; txMeta.flushPartialPacket = true; - int totalSamplesSent = 0; + uint32_t totalSamplesSent = 0; while (std::chrono::high_resolution_clock::now() - startTime < std::chrono::seconds(10) && !stopProgram) //run for 10 seconds { - int samplesToSend = samplesInPkt * txPacketCount; - int samplesSent = device->StreamTx(chipIndex, src, samplesToSend, &txMeta); + uint32_t samplesToSend = samplesInPkt * txPacketCount; + uint32_t samplesSent = device->StreamTx(chipIndex, src, samplesToSend, &txMeta); if (samplesSent < 0) { printf("Failure to send\n"); diff --git a/src/examples/dualRXTX.cpp b/src/examples/dualRXTX.cpp index 68e42b96b..ecd4664c5 100644 --- a/src/examples/dualRXTX.cpp +++ b/src/examples/dualRXTX.cpp @@ -127,17 +127,17 @@ int main(int argc, char** argv) auto t2 = t1; int totalSamplesReceived = 0; - int totalSamplesSent = 0; + uint32_t totalSamplesSent = 0; float maxSignalAmplitude = 0; SDRDevice::StreamMeta rxMeta; while (std::chrono::high_resolution_clock::now() - startTime < std::chrono::seconds(10) && !stopProgram) { - int samplesRead = device->StreamRx(chipIndex, rxSamples, samplesInBuffer, &rxMeta); + uint32_t samplesRead = device->StreamRx(chipIndex, rxSamples, samplesInBuffer, &rxMeta); totalSamplesReceived += samplesRead; // process samples - for (int n = 0; n < samplesRead; ++n) + for (uint32_t n = 0; n < samplesRead; ++n) { float amplitude = pow(rxSamples[0][n].i, 2) + pow(rxSamples[0][n].q, 2); if (amplitude > maxSignalAmplitude) @@ -148,7 +148,7 @@ int main(int argc, char** argv) txMeta.timestamp = rxMeta.timestamp + samplesInBuffer * 64; txMeta.waitForTimestamp = true; txMeta.flushPartialPacket = false; - int samplesSent = device->StreamTx(chipIndex, rxSamples, samplesInBuffer, &txMeta); + uint32_t samplesSent = device->StreamTx(chipIndex, rxSamples, samplesInBuffer, &txMeta); if (samplesSent < 0) { printf("Failure to send\n"); diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index cc9123374..77a1b686d 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -20,7 +20,7 @@ namespace lime { struct DeviceNode; /// @brief Class for holding information about an SDR (Software Defined Radio) device. -/// SDRDevice can have multiple modules (RF chips), that can operate independently. +/// SDRDevice can have multiple modules (RF chips), that can operate independently. class LIME_API SDRDevice { public: @@ -329,9 +329,9 @@ class LIME_API SDRDevice /// @param count The amount of samples to reveive. /// @param meta The metadata of the packets of the stream. /// @return The amount of samples received. - virtual int StreamRx(uint8_t moduleIndex, lime::complex32f_t** samples, uint32_t count, StreamMeta* meta) = 0; + virtual uint32_t StreamRx(uint8_t moduleIndex, lime::complex32f_t** samples, uint32_t count, StreamMeta* meta) = 0; /// @copydoc SDRDevice::StreamRx() - virtual int StreamRx(uint8_t moduleIndex, lime::complex16_t** samples, uint32_t count, StreamMeta* meta) = 0; + virtual uint32_t StreamRx(uint8_t moduleIndex, lime::complex16_t** samples, uint32_t count, StreamMeta* meta) = 0; /// @brief Transmits packets from all the active streams in the device. /// @param moduleIndex The index of the device to transmit the samples with. @@ -339,9 +339,11 @@ class LIME_API SDRDevice /// @param count The amount of samples to transmit. /// @param meta The metadata of the packets of the stream. /// @return The amount of samples transmitted. - virtual int StreamTx(uint8_t moduleIndex, const lime::complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) = 0; + virtual uint32_t StreamTx( + uint8_t moduleIndex, const lime::complex32f_t* const* samples, uint32_t count, const StreamMeta* meta) = 0; /// @copydoc SDRDevice::StreamTx() - virtual int StreamTx(uint8_t moduleIndex, const lime::complex16_t* const* samples, uint32_t count, const StreamMeta* meta) = 0; + virtual uint32_t StreamTx( + uint8_t moduleIndex, const lime::complex16_t* const* samples, uint32_t count, const StreamMeta* meta) = 0; /// @brief Retrieves the current stream statistics. /// @param moduleIndex The index of the device to retrieve the status from. @@ -417,7 +419,7 @@ class LIME_API SDRDevice /// @brief The definition of a function to call whenever memory is being uploaded. typedef bool (*UploadMemoryCallback)(size_t bsent, size_t btotal, const char* statusMessage); - + /// @brief Uploads the given memory into the specified device. /// @param device The memory device to upload the memory to. /// @param moduleIndex The index of the main device to upload the memory to. diff --git a/src/include/limesuite/StreamComposite.h b/src/include/limesuite/StreamComposite.h index 47136c0f2..76f5bd949 100644 --- a/src/include/limesuite/StreamComposite.h +++ b/src/include/limesuite/StreamComposite.h @@ -25,8 +25,8 @@ class LIME_API StreamComposite void StreamStart(); void StreamStop(); - template int StreamRx(T** samples, uint32_t count, SDRDevice::StreamMeta* meta); - template int StreamTx(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); + template uint32_t StreamRx(T** samples, uint32_t count, SDRDevice::StreamMeta* meta); + template uint32_t StreamTx(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); private: std::vector SplitAggregateStreamSetup(const SDRDevice::StreamConfig& cfg); diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index 728129111..3865bfcda 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -612,7 +612,7 @@ bool TRXLooper::IsStreamRunning() return mStreamEnabled; } -template int TRXLooper::StreamRxTemplate(T** dest, uint32_t count, SDRDevice::StreamMeta* meta) +template uint32_t TRXLooper::StreamRxTemplate(T** dest, uint32_t count, SDRDevice::StreamMeta* meta) { bool timestampSet = false; uint32_t samplesProduced = 0; @@ -663,24 +663,24 @@ template int TRXLooper::StreamRxTemplate(T** dest, uint32_t count, SDRD return samplesProduced; } -int TRXLooper::StreamRx(complex32f_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) +uint32_t TRXLooper::StreamRx(complex32f_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) { return StreamRxTemplate(dest, count, meta); } -int TRXLooper::StreamRx(complex16_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) +uint32_t TRXLooper::StreamRx(complex16_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) { return StreamRxTemplate(dest, count, meta); } -template int TRXLooper::StreamTxTemplate(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) +template uint32_t TRXLooper::StreamTxTemplate(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { const bool useChannelB = mConfig.txCount > 1; const bool useTimestamp = meta ? meta->waitForTimestamp : false; const bool flush = meta && meta->flushPartialPacket; int64_t ts = meta ? meta->timestamp : 0; - int samplesRemaining = count; + uint32_t samplesRemaining = count; const int samplesInPkt = mTx.samplesInPkt; const int packetsToBatch = mTx.packetsToBatch; @@ -697,7 +697,7 @@ template int TRXLooper::StreamTxTemplate(const T* const* samples, uint3 } const T* src[2] = { samples[0], useChannelB ? samples[1] : nullptr }; - while (samplesRemaining) + while (samplesRemaining > 0) { if (!mTx.stagingPacket) { @@ -743,12 +743,12 @@ template int TRXLooper::StreamTxTemplate(const T* const* samples, uint3 return count - samplesRemaining; } -int TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) +uint32_t TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { return StreamTxTemplate(samples, count, meta); } -int TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) +uint32_t TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { return StreamTxTemplate(samples, count, meta); } diff --git a/src/protocols/TRXLooper.h b/src/protocols/TRXLooper.h index e3628fb6d..991adda66 100644 --- a/src/protocols/TRXLooper.h +++ b/src/protocols/TRXLooper.h @@ -31,10 +31,10 @@ class TRXLooper inline const lime::SDRDevice::StreamConfig& GetConfig() const { return mConfig; } - virtual int StreamRx(lime::complex32f_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); - virtual int StreamRx(lime::complex16_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); - virtual int StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); - virtual int StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); + virtual uint32_t StreamRx(lime::complex32f_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); + virtual uint32_t StreamRx(lime::complex16_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); + virtual uint32_t StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); + virtual uint32_t StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); void SetMessageLogCallback(SDRDevice::LogCallbackType callback) { mCallback_logMessage = callback; } @@ -97,8 +97,8 @@ class TRXLooper Stream mTx; private: - template int StreamRxTemplate(T** dest, uint32_t count, SDRDevice::StreamMeta* meta); - template int StreamTxTemplate(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); + template uint32_t StreamRxTemplate(T** dest, uint32_t count, SDRDevice::StreamMeta* meta); + template uint32_t StreamTxTemplate(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); }; } // namespace lime diff --git a/src/utilities/rfTest.cpp b/src/utilities/rfTest.cpp index 0a8ba8917..955788dc4 100644 --- a/src/utilities/rfTest.cpp +++ b/src/utilities/rfTest.cpp @@ -222,7 +222,7 @@ bool FullStreamTxRx(SDRDevice& dev, bool MIMO) SDRDevice::StreamMeta rxMeta; rxMeta.timestamp = 0; auto tt1 = std::chrono::high_resolution_clock::now(); - int samplesRead = dev.StreamRx(testStreamIndex, dest, samplesInPkt * txPacketCount, &rxMeta); + uint32_t samplesRead = dev.StreamRx(testStreamIndex, dest, samplesInPkt * txPacketCount, &rxMeta); auto tt2 = std::chrono::high_resolution_clock::now(); int duration = std::chrono::duration_cast(tt2 - tt1).count(); if (show) @@ -259,9 +259,9 @@ bool FullStreamTxRx(SDRDevice& dev, bool MIMO) txMeta.flushPartialPacket = false; // not really matters because of continuous trasmitting auto tt1 = std::chrono::high_resolution_clock::now(); - int samplesSent = dev.StreamTx(testStreamIndex, src, samplesInPkt * txPacketCount, &txMeta); + uint32_t samplesSent = dev.StreamTx(testStreamIndex, src, samplesInPkt * txPacketCount, &txMeta); bsent += txPacketCount; - //int samplesSent2 = dev.StreamTx(0, (const void **)src, samplesInPkt*txPacketCount/4, &txMeta); + //uint32_t samplesSent2 = dev.StreamTx(0, (const void **)src, samplesInPkt*txPacketCount/4, &txMeta); auto tt2 = std::chrono::high_resolution_clock::now(); int duration = std::chrono::duration_cast(tt2 - tt1).count(); if (show) @@ -395,7 +395,7 @@ bool TxTiming(SDRDevice& dev, bool MIMO, float tsDelay_ms) { //Receive samples SDRDevice::StreamMeta rxMeta; - int samplesRead = dev.StreamRx(chipIndex, dest, samplesInPkt * txPacketCount, &rxMeta); + uint32_t samplesRead = dev.StreamRx(chipIndex, dest, samplesInPkt * txPacketCount, &rxMeta); if (samplesRead < 0) { printf("Failed to StreamRx\n"); @@ -414,7 +414,7 @@ bool TxTiming(SDRDevice& dev, bool MIMO, float tsDelay_ms) txMeta.timestamp = rxNow + txDeltaTS; txMeta.waitForTimestamp = true; txMeta.flushPartialPacket = true; - int samplesSent = dev.StreamTx(chipIndex, src, samplesInPkt, &txMeta); + uint32_t samplesSent = dev.StreamTx(chipIndex, src, samplesInPkt, &txMeta); if (samplesSent <= 0) { if (samplesSent < 0) @@ -443,7 +443,7 @@ bool TxTiming(SDRDevice& dev, bool MIMO, float tsDelay_ms) } else // wait and check for tx packet reception { - for (int j = 0; j < samplesRead; ++j) + for (uint32_t j = 0; j < samplesRead; ++j) { float i = dest[0][j].i; float q = dest[0][j].q; From dd6871fccebd6cce5e096f5d385313d55667b003 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 27 Dec 2023 10:55:17 +0200 Subject: [PATCH 19/46] Document TRXLooper --- src/comms/PCIe/TRXLooper_PCIE.cpp | 33 ++- src/comms/PCIe/TRXLooper_PCIE.h | 6 +- src/comms/PCIe/TxBufferManager.h | 32 ++- src/comms/USB/TRXLooper_USB.cpp | 6 + src/protocols/TRXLooper.cpp | 458 ++++-------------------------- src/protocols/TRXLooper.h | 22 +- 6 files changed, 119 insertions(+), 438 deletions(-) diff --git a/src/comms/PCIe/TRXLooper_PCIE.cpp b/src/comms/PCIe/TRXLooper_PCIE.cpp index d898ef4db..6be8e2208 100644 --- a/src/comms/PCIe/TRXLooper_PCIE.cpp +++ b/src/comms/PCIe/TRXLooper_PCIE.cpp @@ -32,20 +32,20 @@ using namespace std::chrono; namespace lime { -static inline int64_t ts_to_us(int64_t fs, int64_t ts) +static constexpr int64_t ts_to_us(int64_t fs, int64_t ts) { - int n, r; - n = (ts / fs); - r = (ts % fs); - return (int64_t)n * 1000000 + (((int64_t)r * 1000000) / fs); -} + int64_t n = (ts / fs); + int64_t r = (ts % fs); -template inline static T clamp(T value, T low, T high) -{ - assert(low <= high); - return value < low ? low : (value > high ? high : value); + return n * 1000000 + ((r * 1000000) / fs); } +/// @brief Constructs a new TRXLooper_PCIE object. +/// @param rxPort The PCIe stream receive port to use. +/// @param txPort The PCIe stream transmit port to use. +/// @param f The FPGA to use in this stream. +/// @param chip The LMS7002M chip to use in this stream. +/// @param moduleIndex The ID of the chip to use. TRXLooper_PCIE::TRXLooper_PCIE( std::shared_ptr rxPort, std::shared_ptr txPort, FPGA* f, LMS7002M* chip, uint8_t moduleIndex) : TRXLooper(f, chip, moduleIndex) @@ -74,7 +74,7 @@ void TRXLooper_PCIE::Setup(const SDRDevice::StreamConfig& config) if (combinedSampleRate != 0) { batchSize = combinedSampleRate / 61.44e6; - batchSize = clamp(batchSize, 1, 4); + batchSize = std::clamp(batchSize, 1, 4); } if (config.hintSampleRate) @@ -130,7 +130,7 @@ int TRXLooper_PCIE::TxSetup() if (mConfig.extraConfig && mConfig.extraConfig->tx.packetsInBatch != 0) mTx.packetsToBatch = mConfig.extraConfig->tx.packetsInBatch; - mTx.packetsToBatch = clamp((int)mTx.packetsToBatch, 1, (int)(dma.bufferSize / packetSize)); + mTx.packetsToBatch = std::clamp((int)mTx.packetsToBatch, 1, (int)(dma.bufferSize / packetSize)); std::vector dmaBuffers(dma.bufferCount); for (uint32_t i = 0; i < dmaBuffers.size(); ++i) @@ -478,7 +478,7 @@ int TRXLooper_PCIE::RxSetup() if (mConfig.extraConfig && mConfig.extraConfig->rx.samplesInPacket != 0) requestSamplesInPkt = mConfig.extraConfig->rx.samplesInPacket; - int samplesInPkt = clamp(requestSamplesInPkt, 64, maxSamplesInPkt); + int samplesInPkt = std::clamp(requestSamplesInPkt, 64, maxSamplesInPkt); int payloadSize = requestSamplesInPkt * sampleSize * chCount; // iqSamplesCount must be N*16, or N*8 depending on device BUS width @@ -499,7 +499,7 @@ int TRXLooper_PCIE::RxSetup() if (mConfig.extraConfig && mConfig.extraConfig->rx.packetsInBatch != 0) mRx.packetsToBatch = mConfig.extraConfig->rx.packetsInBatch; - mRx.packetsToBatch = clamp((int)mRx.packetsToBatch, 1, (int)(dma.bufferSize / packetSize)); + mRx.packetsToBatch = std::clamp((int)mRx.packetsToBatch, 1, (int)(dma.bufferSize / packetSize)); int irqPeriod = 16; float bufferTimeDuration = 0; @@ -508,7 +508,7 @@ int TRXLooper_PCIE::RxSetup() bufferTimeDuration = float(samplesInPkt * mRx.packetsToBatch) / mConfig.hintSampleRate; irqPeriod = 80e-6 / bufferTimeDuration; } - irqPeriod = clamp(irqPeriod, 1, 16); + irqPeriod = std::clamp(irqPeriod, 1, 16); irqPeriod = 4; if (mCallback_logMessage) @@ -758,6 +758,9 @@ void TRXLooper_PCIE::RxTeardown() mRxArgs.port->RxDMAEnable(false, mRxArgs.bufferSize, 1); } +/// @copydoc SDRDevice::UploadTxWaveform() +/// @param fpga The FPGA device to use. +/// @param port The PCIe communications port to use. int TRXLooper_PCIE::UploadTxWaveform(FPGA* fpga, std::shared_ptr port, const lime::SDRDevice::StreamConfig& config, diff --git a/src/comms/PCIe/TRXLooper_PCIE.h b/src/comms/PCIe/TRXLooper_PCIE.h index 77f618385..9cc3d3577 100644 --- a/src/comms/PCIe/TRXLooper_PCIE.h +++ b/src/comms/PCIe/TRXLooper_PCIE.h @@ -18,8 +18,8 @@ class TRXLooper_PCIE : public TRXLooper TRXLooper_PCIE( std::shared_ptr rxPort, std::shared_ptr txPort, FPGA* f, LMS7002M* chip, uint8_t moduleIndex); virtual ~TRXLooper_PCIE(); - virtual void Setup(const SDRDevice::StreamConfig& config); - virtual void Start(); + virtual void Setup(const SDRDevice::StreamConfig& config) override; + virtual void Start() override; static int UploadTxWaveform(FPGA* fpga, std::shared_ptr port, @@ -28,8 +28,6 @@ class TRXLooper_PCIE : public TRXLooper const void** samples, uint32_t count); - typedef SamplesPacket<2> SamplesPacketType; - /** @brief The transfer arguments for the PCIe transfer. */ struct TransferArgs { std::shared_ptr port; diff --git a/src/comms/PCIe/TxBufferManager.h b/src/comms/PCIe/TxBufferManager.h index ae45ddf79..77d47ca35 100644 --- a/src/comms/PCIe/TxBufferManager.h +++ b/src/comms/PCIe/TxBufferManager.h @@ -17,6 +17,12 @@ namespace lime { template class TxBufferManager { public: + /// @brief Constructs a new TxBufferManager object. + /// @param mimo Whether the stream is a Multiple In Multiple Out (MIMO) stream. + /// @param compressed Whether the stream is in 12-bit or in 16-bit format (true for 12-bit). + /// @param maxSamplesInPkt The maximum amount of samples allowed in a single packet. + /// @param maxPacketsInBatch The maximum amount of packets allowed in a single transfer batch. + /// @param inputFormat The input format of the samples for the device. TxBufferManager(bool mimo, bool compressed, uint32_t maxSamplesInPkt, @@ -39,6 +45,9 @@ template class TxBufferManager maxPayloadSize = std::min(4080u, bytesForFrame * maxSamplesInPkt); } + /// @brief Resets the buffer to point to an empty buffer. + /// @param memPtr The pointer of memory to set. + /// @param capacity The total capacity of the buffer. void Reset(uint8_t* memPtr, uint32_t capacity) { packetsCreated = 0; @@ -52,14 +61,19 @@ template class TxBufferManager payloadPtr = reinterpret_cast(header) + sizeof(StreamHeader); } - inline bool hasSpace() const + /// @brief Checks if the buffer still has space in it. + /// @return Whether there still is space or not. + constexpr bool hasSpace() const { const bool packetNotFull = payloadSize < maxPayloadSize; const bool spaceAvailable = mCapacity - bytesUsed > sizeof(StreamHeader); return packetNotFull && spaceAvailable; } - inline bool consume(T* src) + /// @brief Adds samples from the given source packet into the transfer. + /// @param src The source packet to add to the transfer. + /// @return The sendability of the transfer (true to send it now). + bool consume(T* src) { bool sendBuffer = false; while (!src->empty()) @@ -126,9 +140,17 @@ template class TxBufferManager return src->metadata.flushPartialPacket || sendBuffer; } - inline int size() const { return bytesUsed; }; - inline uint8_t* data() const { return mData; }; - inline int packetCount() const { return packetsCreated; }; + /// @brief Gets the current size of the transfer. + /// @return The amount of bytes this transfer is currently using. + constexpr uint32_t size() const { return bytesUsed; }; + + /// @brief Gets the pointer to the buffer of the transfer. + /// @return The pointer to the buffer of the transfer. + constexpr uint8_t* data() const { return mData; }; + + /// @brief Gets the amount of packets in this transfer. + /// @return The amount of packets in this transfer. + constexpr uint16_t packetCount() const { return packetsCreated; }; private: DataConversion conversion; diff --git a/src/comms/USB/TRXLooper_USB.cpp b/src/comms/USB/TRXLooper_USB.cpp index f0e932e11..02e8630e9 100644 --- a/src/comms/USB/TRXLooper_USB.cpp +++ b/src/comms/USB/TRXLooper_USB.cpp @@ -10,6 +10,12 @@ namespace lime { +/// @brief Constructs a TRXLooper_USB object. +/// @param comms The USB communications interface to use. +/// @param f The FPGA to use. +/// @param chip The LMS7002M chip to use. +/// @param rxEndPt The endpoint for receiving the stream data from the USB communications. +/// @param txEndPt The endpoint for transmitting the stream data to the USB communications. TRXLooper_USB::TRXLooper_USB(std::shared_ptr comms, FPGA* f, LMS7002M* chip, uint8_t rxEndPt, uint8_t txEndPt) : TRXLooper(f, chip, 0) , comms(comms) diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index 3865bfcda..4c834cf2e 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -17,6 +17,10 @@ using namespace std::chrono; static constexpr uint16_t defaultSamplesInPkt = 256; +/// @brief Constructs a new TRXLooper object. +/// @param f The FPGA device to use for streaming. +/// @param chip The LMS7002M device to use for streaming. +/// @param id The ID of the chip to use. TRXLooper::TRXLooper(FPGA* f, LMS7002M* chip, int id) : mCallback_logMessage(nullptr) , mStreamEnabled(false) @@ -40,407 +44,24 @@ TRXLooper::TRXLooper(FPGA* f, LMS7002M* chip, int id) TRXLooper::~TRXLooper() { Stop(); - mRx.terminate.store(true, std::memory_order_relaxed); - mTx.terminate.store(true, std::memory_order_relaxed); - if (mTx.thread.joinable()) - mTx.thread.join(); - if (mRx.thread.joinable()) - mRx.thread.join(); } -uint64_t TRXLooper::GetHardwareTimestamp(void) +/// @brief Gets the current timestamp of the hardware. +/// @return The current timestamp of the hardware. +uint64_t TRXLooper::GetHardwareTimestamp() const { return mRx.lastTimestamp.load(std::memory_order_relaxed) + mTimestampOffset; } +/// @brief Sets the hardware timestamp. +/// @param now The current timestamp to set. void TRXLooper::SetHardwareTimestamp(const uint64_t now) { mTimestampOffset = now - mRx.lastTimestamp.load(std::memory_order_relaxed); } -/* -void TRXLooper::RstRxIQGen() -{ - uint32_t data[16]; - uint32_t reg20; - uint32_t reg11C; - uint32_t reg10C; - data[0] = (uint32_t(0x0020) << 16); - dataPort->ReadLMS7002MSPI(data, ®20, 1, chipId); - data[0] = (uint32_t(0x010C) << 16); - dataPort->ReadLMS7002MSPI(data, ®10C, 1, chipId); - data[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; - dataPort->WriteLMS7002MSPI(data, 1, chipId); - data[0] = (uint32_t(0x011C) << 16); - dataPort->ReadLMS7002MSPI(data, ®11C, 1, chipId); - data[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //SXR - data[1] = (1 << 31) | (uint32_t(0x011C) << 16) | (reg11C | 0x10); //PD_FDIV - data[2] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFF; // mac 3 - both channels - data[3] = (1 << 31) | (uint32_t(0x0124) << 16) | 0x001F; //direct control of powerdowns - data[4] = (1 << 31) | (uint32_t(0x010C) << 16) | (reg10C | 0x8); // PD_QGEN_RFE - data[5] = (1 << 31) | (uint32_t(0x010C) << 16) | reg10C; //restore value - data[6] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //SXR - data[7] = (1 << 31) | (uint32_t(0x011C) << 16) | reg11C; //restore value - data[8] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //restore value - dataPort->WriteLMS7002MSPI(data, 9, chipId); -} - -void TRXLooper::AlignRxTSP() -{ - uint32_t reg20; - uint32_t regsA[2]; - uint32_t regsB[2]; - //backup values - { - const std::vector bakAddr = { (uint32_t(0x0400) << 16), (uint32_t(0x040C) << 16) }; - uint32_t data = (uint32_t(0x0020) << 16); - dataPort->ReadLMS7002MSPI(&data, ®20, 1, chipId); - data = (uint32_t(0x0020) << 16) | 0xFFFD; - dataPort->WriteLMS7002MSPI(&data, 1, chipId); - dataPort->ReadLMS7002MSPI(bakAddr.data(), regsA, bakAddr.size(), chipId); - data = (uint32_t(0x0020) << 16) | 0xFFFE; - dataPort->WriteLMS7002MSPI(&data, 1, chipId); - dataPort->ReadLMS7002MSPI(bakAddr.data(), regsB, bakAddr.size(), chipId); - } - - //alignment search - { - uint32_t dataWr[4]; - dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFF; - dataWr[1] = (1 << 31) | (uint32_t(0x0400) << 16) | 0x8085; - dataWr[2] = (1 << 31) | (uint32_t(0x040C) << 16) | 0x01FF; - dataPort->WriteLMS7002MSPI(dataWr, 3, chipId); - uint32_t* buf = new uint32_t[sizeof(FPGA_DataPacket) / sizeof(uint32_t)]; - - fpga->StopStreaming(); - fpga->WriteRegister(0xFFFF, 1 << chipId); - fpga->WriteRegister(0x0008, 0x0100); - fpga->WriteRegister(0x0007, 3); - - dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0x55FE; - dataWr[1] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; - - for (int i = 0; i < 100; i++) - { - dataPort->WriteLMS7002MSPI(&dataWr[0], 2, chipId); - dataPort->ResetStreamBuffers(); - fpga->StartStreaming(); - if (dataPort->ReceiveData((char*)buf, sizeof(FPGA_DataPacket), chipId, 50) != sizeof(FPGA_DataPacket)) - { - lime::warning("Channel alignment failed"); - break; - } - fpga->StopStreaming(); - dataPort->AbortReading(chipId); - if (buf[4] == buf[5]) - break; - } - delete[] buf; - } - - //restore values - { - uint32_t dataWr[7]; - dataWr[0] = (uint32_t(0x0020) << 16) | 0xFFFD; - dataWr[1] = (uint32_t(0x0400) << 16) | regsA[0]; - dataWr[2] = (uint32_t(0x040C) << 16) | regsA[1]; - dataWr[3] = (uint32_t(0x0020) << 16) | 0xFFFE; - dataWr[4] = (uint32_t(0x0400) << 16) | regsB[0]; - dataWr[5] = (uint32_t(0x040C) << 16) | regsB[1]; - dataWr[6] = (uint32_t(0x0020) << 16) | reg20; - dataPort->WriteLMS7002MSPI(dataWr, 7, chipId); - } -} - -double TRXLooper::GetPhaseOffset(int bin) -{ - int16_t* buf = new int16_t[sizeof(FPGA_DataPacket)/sizeof(int16_t)]; - - dataPort->ResetStreamBuffers(); - fpga->StartStreaming(); - if (dataPort->ReceiveData((char*)buf, sizeof(FPGA_DataPacket), chipId, 50)!=sizeof(FPGA_DataPacket)) - { - lime::warning("Channel alignment failed"); - delete [] buf; - return -1000; - } - fpga->StopStreaming(); - dataPort->AbortReading(chipId); - //calculate DFT bin of interest and check channel phase difference - const std::complex iunit(0, 1); - const double pi = std::acos(-1); - const int N = 512; - std::complex xA(0,0); - std::complex xB(0, 0); - for (int n = 0; n < N; n++) - { - const std::complex xAn(buf[8+4*n], buf[9+4*n]); - const std::complex xBn(buf[10+4*n],buf[11+4*n]); - const std::complex mult = std::exp(-2.0*iunit*pi* double(bin)* double(n)/double(N)); - xA += xAn * mult; - xB += xBn * mult; - } - double phaseA = std::arg(xA) * 180.0 / pi; - double phaseB = std::arg(xB) * 180.0 / pi; - double phasediff = phaseB - phaseA; - if (phasediff < -180.0) phasediff +=360.0; - if (phasediff > 180.0) phasediff -=360.0; - delete [] buf; - return phasediff; -} - -void TRXLooper::AlignRxRF(bool restoreValues) -{ - uint32_t reg20 = lms->SPI_read(0x20); - auto regBackup = lms->BackupRegisterMap(); - lms->SPI_write(0x20, 0xFFFF); - lms->SetDefaults(LMS7002M::RFE); - lms->SetDefaults(LMS7002M::RBB); - lms->SetDefaults(LMS7002M::TBB); - lms->SetDefaults(LMS7002M::TRF); - lms->SPI_write(0x10C, 0x88C5); - lms->SPI_write(0x10D, 0x0117); - lms->SPI_write(0x113, 0x024A); - lms->SPI_write(0x118, 0x418C); - lms->SPI_write(0x100, 0x4039); - lms->SPI_write(0x101, 0x7801); - lms->SPI_write(0x103, 0x0612); - lms->SPI_write(0x108, 0x318C); - lms->SPI_write(0x082, 0x8001); - lms->SPI_write(0x200, 0x008D); - lms->SPI_write(0x208, 0x01FB); - lms->SPI_write(0x400, 0x8081); - lms->SPI_write(0x40C, 0x01FF); - lms->SPI_write(0x404, 0x0006); - lms->LoadDC_REG_IQ(true, 0x3FFF, 0x3FFF); - double srate = lms->GetSampleRate(false, LMS7002M::ChA); - lms->SetFrequencySX(false,450e6); - int dec = lms->Get_SPI_Reg_bits(LMS7_HBD_OVR_RXTSP); - if (dec > 4) dec = 0; - - double offsets[] = {1.15/60.0, 1.1/40.0, 0.55/20.0, 0.2/10.0, 0.18/5.0}; - double tolerance[] = {0.9, 0.45, 0.25, 0.14, 0.06}; - double offset = offsets[dec]*srate/1e6; - std::vector dataWr; - dataWr.resize(16); - - fpga->WriteRegister(0xFFFF, 1 << chipId); - fpga->StopStreaming(); - fpga->WriteRegister(0x0008, 0x0100); - fpga->WriteRegister(0x0007, 3); - bool found = false; - for (int i = 0; i < 200; i++){ - lms->Modify_SPI_Reg_bits(LMS7_PD_FDIV_O_CGEN, 1); - lms->Modify_SPI_Reg_bits(LMS7_PD_FDIV_O_CGEN, 0); - AlignRxTSP(); - - lms->SetFrequencySX(true, 450e6+srate/16.0); - double offset1 = GetPhaseOffset(32); - if (offset1 < -360) - break; - lms->SetFrequencySX(true, 450e6+srate/8.0); - double offset2 = GetPhaseOffset(64); - if (offset2 < -360) - break; - double diff = offset1-offset2; - if (abs(diff-offset) < tolerance[dec]) - { - found = true; - break; - } - } - if (restoreValues) - lms->RestoreRegisterMap(regBackup); - if (found) - AlignQuadrature(restoreValues); - else - lime::warning("Channel alignment failed"); - lms->SPI_write(0x20, reg20); -} - -void TRXLooper::AlignQuadrature(bool restoreValues) -{ - auto regBackup = lms->BackupRegisterMap(); - - lms->SPI_write(0x20, 0xFFFF); - lms->SetDefaults(LMS7002M::RBB); - lms->SetDefaults(LMS7002M::TBB); - lms->SetDefaults(LMS7002M::TRF); - lms->SPI_write(0x113, 0x0046); - lms->SPI_write(0x118, 0x418C); - lms->SPI_write(0x100, 0x4039); - lms->SPI_write(0x101, 0x7801); - lms->SPI_write(0x108, 0x318C); - lms->SPI_write(0x082, 0x8001); - lms->SPI_write(0x200, 0x008D); - lms->SPI_write(0x208, 0x01FB); - lms->SPI_write(0x400, 0x8081); - lms->SPI_write(0x40C, 0x01FF); - lms->SPI_write(0x404, 0x0006); - lms->LoadDC_REG_IQ(true, 0x3FFF, 0x3FFF); - lms->SPI_write(0x20, 0xFFFE); - lms->SPI_write(0x105, 0x0006); - lms->SPI_write(0x100, 0x4038); - lms->SPI_write(0x113, 0x007F); - lms->SPI_write(0x119, 0x529B); - auto val = lms->Get_SPI_Reg_bits(LMS7_SEL_PATH_RFE, true); - lms->SPI_write(0x10D, val==3 ? 0x18F : val==2 ? 0x117 : 0x08F); - lms->SPI_write(0x10C, val==2 ? 0x88C5 : 0x88A5); - lms->SPI_write(0x20, 0xFFFD); - lms->SPI_write(0x103, val==2 ? 0x612 : 0xA12); - val = lms->Get_SPI_Reg_bits(LMS7_SEL_PATH_RFE, true); - lms->SPI_write(0x10D, val==3 ? 0x18F : val==2 ? 0x117 : 0x08F); - lms->SPI_write(0x10C, val==2 ? 0x88C5 : 0x88A5); - lms->SPI_write(0x119, 0x5293); - double srate = lms->GetSampleRate(false, LMS7002M::ChA); - double freq = lms->GetFrequencySX(false); - - fpga->WriteRegister(0xFFFF, 1 << chipId); - fpga->StopStreaming(); - fpga->WriteRegister(0x0008, 0x0100); - fpga->WriteRegister(0x0007, 3); - lms->SetFrequencySX(true, freq+srate/16.0); - bool found = false; - for (int i = 0; i < 100; i++){ - - double offset = GetPhaseOffset(32); - if (offset < -360) - break; - if (fabs(offset) <= 90.0) - { - found = true; - break; - } - RstRxIQGen(); - } - - if (restoreValues) - lms->RestoreRegisterMap(regBackup); - if (!found) - lime::warning("Channel alignment failed"); -} -*/ -/* -int TRXLooper::UpdateThreads(bool stopAll) -{ - bool needTx = false; - bool needRx = false; - - //check which threads are needed - if (!stopAll) - { - for(auto &i : mRxStreams) - if(i.used && i.IsActive()) - { - needRx = true; - break; - } - for(auto &i : mTxStreams) - if(i.used && i.IsActive()) - { - needTx = true; - break; - } - } - - //stop threads if not needed - if((!needTx) && mTx.thread.joinable()) - { - mTx.terminate.store(true, std::memory_order_relaxed); - mTx.thread.join(); - } - if((!needRx) && mRx.thread.joinable()) - { - mRx.terminate.store(true, std::memory_order_relaxed); - mRx.thread.join(); - } - - //configure FPGA on first start, or disable FPGA when not streaming - if((needTx || needRx) && (!mTx.thread.joinable()) && (!mRx.thread.joinable())) - { - ResizeChannelBuffers(); - fpga->WriteRegister(0xFFFF, 1 << chipId); - bool align = (mRxStreams[0].used && mRxStreams[1].used && (mRxStreams[0].config.align | mRxStreams[1].config.align)); - if (align) - AlignRxRF(true); - //enable FPGA streaming - fpga->StopStreaming(); - fpga->ResetTimestamp(); - mRx.lastTimestamp.store(0, std::memory_order_relaxed); - //Clear device stream buffers - dataPort->ResetStreamBuffers(); - - //enable MIMO mode, 12 bit compressed values - dataLinkFormat = StreamConfig::FMT_INT12; - //by default use 12 bit compressed, adjust link format for stream - - for(auto &i : mRxStreams) - if(i.used && i.config.linkFormat != StreamConfig::FMT_INT12) - { - dataLinkFormat = StreamConfig::FMT_INT16; - break; - } - - for(auto &i : mTxStreams) - if(i.used && i.config.linkFormat != StreamConfig::FMT_INT12) - { - dataLinkFormat = StreamConfig::FMT_INT16; - break; - } - - const uint16_t smpl_width = dataLinkFormat == StreamConfig::FMT_INT12 ? 2 : 0; - uint16_t mode = 0x0100; - - if (lms->Get_SPI_Reg_bits(LMS7param(LML1_SISODDR))) - mode = 0x0040; - else if (lms->Get_SPI_Reg_bits(LMS7param(LML1_TRXIQPULSE))) - mode = 0x0180; - - fpga->WriteRegister(0x0008, mode | smpl_width); - - const uint16_t channelEnables = (mRxStreams[0].used||mTxStreams[0].used) + 2 * (mRxStreams[1].used||mTxStreams[1].used); - fpga->WriteRegister(0x0007, channelEnables); - - uint32_t reg9 = fpga->ReadRegister(0x0009); - const uint32_t addr[] = {0x0009, 0x0009}; - const uint32_t data[] = {reg9 | (5 << 1), reg9 & ~(5 << 1)}; - fpga->StartStreaming(); - fpga->WriteRegisters(addr, data, 2); - if (!align) - lms->ResetLogicregisters(); - } - else if(not needTx and not needRx) - { - //disable FPGA streaming - fpga->WriteRegister(0xFFFF, 1 << chipId); - fpga->StopStreaming(); - } - - //FPGA should be configured and activated, start needed threads - if(needRx && (!mRx.thread.joinable())) - { - mRx.terminate.store(false, std::memory_order_relaxed); - auto RxLoopFunction = std::bind(&TRXLooper::ReceivePacketsLoop, this); - mRx.thread = std::thread(RxLoopFunction); - SetOSThreadPriority(ThreadPriority::NORMAL, ThreadPolicy::REALTIME, &mRx.thread); - } - if(needTx && (!mTx.thread.joinable())) - { - fpga->WriteRegister(0xFFFF, 1 << chipId); - fpga->WriteRegister(0xD, 0); //stop WFM - mTx.terminate.store(false, std::memory_order_relaxed); - auto TxLoopFunction = std::bind(&TRXLooper::TransmitPacketsLoop, this); - mTx.thread = std::thread(TxLoopFunction); - SetOSThreadPriority(ThreadPriority::NORMAL, ThreadPolicy::REALTIME, &mTx.thread); - } - return 0; -} -*/ - -// const lime::SDRDevice::StreamConfig& TRXLooper::GetConfig() const -// { -// return mConfig; -// } +/// @brief Sets up the stream of this looper. +/// @param cfg The configuration settings to set up the stream with. void TRXLooper::Setup(const SDRDevice::StreamConfig& cfg) { if (mRx.thread.joinable() || mTx.thread.joinable()) @@ -552,6 +173,7 @@ void TRXLooper::Setup(const SDRDevice::StreamConfig& cfg) //enable FPGA streaming } +/// @brief Starts the stream of this looper. void TRXLooper::Start() { mRx.fifo->clear(); @@ -572,6 +194,7 @@ void TRXLooper::Start() // lms->ResetLogicregisters(); } +/// @brief Stops the stream and cleans up all the memory. void TRXLooper::Stop() { if (!mStreamEnabled) @@ -596,20 +219,32 @@ void TRXLooper::Stop() RxTeardown(); TxTeardown(); - // clear memory pools - mRx.stagingPacket = nullptr; - mTx.stagingPacket = nullptr; - - delete mRx.memPool; - mRx.memPool = nullptr; - delete mTx.memPool; - mTx.memPool = nullptr; - mStreamEnabled = false; -} -bool TRXLooper::IsStreamRunning() -{ - return mStreamEnabled; + if (mRx.stagingPacket != nullptr) + { + mRx.memPool->Free(mRx.stagingPacket); + mRx.stagingPacket = nullptr; + } + + if (mTx.stagingPacket != nullptr) + { + mTx.memPool->Free(mTx.stagingPacket); + mTx.stagingPacket = nullptr; + } + + if (mRx.memPool != nullptr) + { + delete mRx.memPool; + mRx.memPool = nullptr; + } + + if (mTx.memPool != nullptr) + { + delete mTx.memPool; + mTx.memPool = nullptr; + } + + mStreamEnabled = false; } template uint32_t TRXLooper::StreamRxTemplate(T** dest, uint32_t count, SDRDevice::StreamMeta* meta) @@ -663,11 +298,17 @@ template uint32_t TRXLooper::StreamRxTemplate(T** dest, uint32_t count, return samplesProduced; } +/// @brief Reveives samples from this specific stream. +/// @param samples The buffer to put the received samples in. +/// @param count The amount of samples to reveive. +/// @param meta The metadata of the packets of the stream. +/// @return The amount of samples received. uint32_t TRXLooper::StreamRx(complex32f_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) { return StreamRxTemplate(dest, count, meta); } +/// @copydoc TRXLooper::StreamRx() uint32_t TRXLooper::StreamRx(complex16_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) { return StreamRxTemplate(dest, count, meta); @@ -743,17 +384,26 @@ template uint32_t TRXLooper::StreamTxTemplate(const T* const* samples, return count - samplesRemaining; } +/// @brief Transmits packets from from this specific stream. +/// @param samples The buffer of the samples to transmit. +/// @param count The amount of samples to transmit. +/// @param meta The metadata of the packets of the stream. +/// @return The amount of samples transmitted. uint32_t TRXLooper::StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { return StreamTxTemplate(samples, count, meta); } +/// @copydoc TRXLooper::StreamTx() uint32_t TRXLooper::StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) { return StreamTxTemplate(samples, count, meta); } -SDRDevice::StreamStats TRXLooper::GetStats(TRXDir dir) +/// @brief Gets statistics from a specified transfer direction. +/// @param dir The direction of which to get the statistics. +/// @return The statistics of the transfers. +SDRDevice::StreamStats TRXLooper::GetStats(TRXDir dir) const { SDRDevice::StreamStats stats; diff --git a/src/protocols/TRXLooper.h b/src/protocols/TRXLooper.h index 991adda66..ed0b7de40 100644 --- a/src/protocols/TRXLooper.h +++ b/src/protocols/TRXLooper.h @@ -21,25 +21,32 @@ class TRXLooper TRXLooper(FPGA* f, LMS7002M* chip, int id); virtual ~TRXLooper(); - uint64_t GetHardwareTimestamp(void); + uint64_t GetHardwareTimestamp() const; void SetHardwareTimestamp(const uint64_t now); - virtual void Setup(const lime::SDRDevice::StreamConfig& config); + virtual void Setup(const lime::SDRDevice::StreamConfig& cfg); virtual void Start(); virtual void Stop(); - virtual bool IsStreamRunning(); + /// @brief Gets whether the stream is currently running or not. + /// @return The current status of the stream (true if running). + constexpr bool IsStreamRunning() const { return mStreamEnabled; } - inline const lime::SDRDevice::StreamConfig& GetConfig() const { return mConfig; } + /// @brief Gets the current configuration of the stream. + /// @return The current configuration of the stream. + constexpr const lime::SDRDevice::StreamConfig& GetConfig() const { return mConfig; } virtual uint32_t StreamRx(lime::complex32f_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); virtual uint32_t StreamRx(lime::complex16_t** samples, uint32_t count, SDRDevice::StreamMeta* meta); virtual uint32_t StreamTx(const lime::complex32f_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); virtual uint32_t StreamTx(const lime::complex16_t* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); + /// @brief Sets the callback to use for message logging. + /// @param callback The new callback to use. void SetMessageLogCallback(SDRDevice::LogCallbackType callback) { mCallback_logMessage = callback; } - SDRDevice::StreamStats GetStats(TRXDir tx); + SDRDevice::StreamStats GetStats(TRXDir tx) const; + /// @brief The type of a sample packet. typedef SamplesPacket<2> SamplesPacketType; protected: @@ -54,11 +61,6 @@ class TRXLooper uint64_t mTimestampOffset; lime::SDRDevice::StreamConfig mConfig; - // void AlignRxTSP(); - // void AlignRxRF(bool restoreValues); - // void AlignQuadrature(bool restoreValues); - // void RstRxIQGen(); - // double GetPhaseOffset(int bin); FPGA* fpga; LMS7002M* lms; int chipId; From 8460857ecee7f7da055275498d71beca01062ddc Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 27 Dec 2023 11:10:30 +0200 Subject: [PATCH 20/46] Document StreamComposite --- src/include/limesuite/StreamComposite.h | 15 +++++++++++++++ src/protocols/TRXLooper.cpp | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/include/limesuite/StreamComposite.h b/src/include/limesuite/StreamComposite.h index 76f5bd949..93bede494 100644 --- a/src/include/limesuite/StreamComposite.h +++ b/src/include/limesuite/StreamComposite.h @@ -19,13 +19,28 @@ class LIME_API StreamComposite { public: StreamComposite() = delete; + + /// @brief Constructs the StreamComposite object. + /// @param aggregate The list of streams to aggregate into one stream. StreamComposite(const std::vector& aggregate); + /// @brief Sets up the streams with the given configuration. + /// @param config The configuration to set up the streams with. + /// @return The status of the operation (0 on success). int StreamSetup(const SDRDevice::StreamConfig& config); + + /// @brief Starts all of the aggregated streams. void StreamStart(); + + /// @brief Ends all of the aggregated streams. void StreamStop(); + /// @copydoc TRXLooper::StreamRx() + /// @tparam T The type of streams to send. template uint32_t StreamRx(T** samples, uint32_t count, SDRDevice::StreamMeta* meta); + + /// @copydoc TRXLooper::StreamTx() + /// @tparam T The type of streams to receive. template uint32_t StreamTx(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta); private: diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index 4c834cf2e..2de8efef7 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -303,15 +303,15 @@ template uint32_t TRXLooper::StreamRxTemplate(T** dest, uint32_t count, /// @param count The amount of samples to reveive. /// @param meta The metadata of the packets of the stream. /// @return The amount of samples received. -uint32_t TRXLooper::StreamRx(complex32f_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) +uint32_t TRXLooper::StreamRx(complex32f_t** samples, uint32_t count, SDRDevice::StreamMeta* meta) { - return StreamRxTemplate(dest, count, meta); + return StreamRxTemplate(samples, count, meta); } /// @copydoc TRXLooper::StreamRx() -uint32_t TRXLooper::StreamRx(complex16_t** dest, uint32_t count, SDRDevice::StreamMeta* meta) +uint32_t TRXLooper::StreamRx(complex16_t** samples, uint32_t count, SDRDevice::StreamMeta* meta) { - return StreamRxTemplate(dest, count, meta); + return StreamRxTemplate(samples, count, meta); } template uint32_t TRXLooper::StreamTxTemplate(const T* const* samples, uint32_t count, const SDRDevice::StreamMeta* meta) From 5c530a4d57a385ae33e35933233be5822b52f750 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 27 Dec 2023 13:56:47 +0200 Subject: [PATCH 21/46] Separate WriteRegistersBatch into their own files --- src/CMakeLists.txt | 1 + src/FPGA_common/FPGA_common.cpp | 75 +++++++------------------ src/FPGA_common/FPGA_common.h | 9 +-- src/FPGA_common/WriteRegistersBatch.cpp | 40 +++++++++++++ src/FPGA_common/WriteRegistersBatch.h | 29 ++++++++++ 5 files changed, 95 insertions(+), 59 deletions(-) create mode 100644 src/FPGA_common/WriteRegistersBatch.cpp create mode 100644 src/FPGA_common/WriteRegistersBatch.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1af982642..b37d9dc7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,6 +46,7 @@ set(LIME_SUITE_SOURCES Si5351C/Si5351C.cpp ${PROJECT_SOURCE_DIR}/external/kissFFT/kiss_fft.c FPGA_common/FPGA_common.cpp + FPGA_common/WriteRegistersBatch.cpp windowFunction.cpp threadHelper/threadHelper.cpp CDCM6208/CDCM6208_Dev.cpp diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index a219e7f76..3b44e6ce5 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -1,14 +1,14 @@ #include "FPGA_common.h" #include "limesuite/IComms.h" -#include -#include -#include +#include "LMSBoards.h" #include "Logger.h" +#include "WriteRegistersBatch.h" + #include -#include -#include -#include "LMSBoards.h" -using namespace std; +#include +#include +#include +#include #ifndef NDEBUG #define ASSERT_WARNING(cond, message) \ @@ -26,41 +26,6 @@ using namespace std; namespace lime { -/** @brief A class for writing a batch of registers into the FPGA. */ -class WriteRegistersBatch -{ - public: - /// @brief Constructor for the batch. - /// @param fpga The FPGA this batch belongs to. - WriteRegistersBatch(FPGA* fpga) - : owner(fpga){}; - ~WriteRegistersBatch() { ASSERT_WARNING(addrs.size() == 0, "FPGA WriteRegistersBatch not flushed"); } - - /// @brief Writes the modified values into the FPGA. - /// @return The operation status (0 on success). - int Flush() - { - int status = owner->WriteRegisters(addrs.data(), values.data(), addrs.size()); - addrs.clear(); - values.clear(); - return status; - } - - /// @brief Sets an address value pair to write into the FPGA on flushing. - /// @param addr The address to write to. - /// @param value The value to write. - void WriteRegister(uint16_t addr, uint16_t value) - { - addrs.push_back(addr); - values.push_back(value); - } - - private: - FPGA* owner; - std::vector addrs; - std::vector values; -}; - // 0x000A const int RX_EN = 1; //controls both receiver and transmitter const int TX_EN = 1 << 1; //used for wfm playback from fpga @@ -82,8 +47,8 @@ const uint16_t PHCFG_MODE = 1 << 14; const uint16_t busyAddr = 0x0021; static const std::chrono::milliseconds busyPollPeriod(10); // time between checking "done" bit -// does the fpga has "done" bit to indicate PLLCFG_START,PHCFG_START,PLLRST_START completion -static bool HasWaitForDone(uint8_t targetDevice) +// Does the FPGA have the "done" bit to indicate PLLCFG_START, PHCFG_START, PLLRST_START completion? +static constexpr bool HasWaitForDone(uint8_t targetDevice) { // TODO: list devices that don't have it, as it's most likely that future devices will support this switch (static_cast(targetDevice)) @@ -97,7 +62,7 @@ static bool HasWaitForDone(uint8_t targetDevice) } } -static bool HasFPGAClockPhaseSearch(uint8_t targetDevice, uint8_t version, uint8_t revision) +static constexpr bool HasFPGAClockPhaseSearch(uint8_t targetDevice, uint8_t version, uint8_t revision) { const uint16_t ver_rev = version << 8 | revision; switch (static_cast(targetDevice)) @@ -366,8 +331,8 @@ int FPGA::ResetTimestamp() int FPGA::WaitTillDone(uint16_t pollAddr, uint16_t doneMask, uint16_t errorMask, const std::string& title) { - const auto timeout = chrono::seconds(3); - auto t1 = chrono::high_resolution_clock::now(); + const auto timeout = std::chrono::seconds(3); + auto t1 = std::chrono::high_resolution_clock::now(); bool done = false; uint16_t error = 0; if (!title.empty()) @@ -387,7 +352,7 @@ int FPGA::WaitTillDone(uint16_t pollAddr, uint16_t doneMask, uint16_t errorMask, if (!done) { - if ((chrono::high_resolution_clock::now() - t1) > timeout) + if ((std::chrono::high_resolution_clock::now() - t1) > timeout) { lime::warning("%s timeout", title.c_str()); return ETIME; @@ -463,7 +428,7 @@ int FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_P { verbose_printf("FPGA SetPllFrequency: PLL[%i] input:%.3f MHz clockCount:%i\n", pllIndex, inputFreq / 1e6, clockCount); WriteRegistersBatch batch(this); - const auto timeout = chrono::seconds(3); + const auto timeout = std::chrono::seconds(3); if (not fpgaPort) return ReportError(ENODEV, "ConfigureFPGA_PLL: connection port is NULL"); @@ -525,7 +490,7 @@ int FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_P const double vcoLimits_Hz[2] = { 600e6, 1280e6 }; // Collect all desired VCO frequencies - map desiredVCO; // + std::map desiredVCO; // for (int i = 0; i < clockCount; ++i) { if (clocks[i].outFrequency == 0 || clocks[i].bypass) @@ -539,7 +504,7 @@ int FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_P if (it != desiredVCO.end()) it->second++; // increase demand else // add new frequency demand - desiredVCO.insert(pair(freq, 1)); + desiredVCO.insert(std::pair(freq, 1)); freq += clocks[i].outFrequency; } } @@ -548,7 +513,7 @@ int FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_P // Find VCO that satisfies most outputs with integer dividers uint64_t bestFreqVCO = std::max_element( - desiredVCO.begin(), desiredVCO.end(), [](const pair& p1, const pair& p2) { + desiredVCO.begin(), desiredVCO.end(), [](const std::pair& p1, const std::pair& p2) { if (p1.second == p2.second) return p1.first < p2.first; // sort by VCO frequency return p1.second < p2.second; @@ -1276,9 +1241,9 @@ FPGA::GatewareInfo FPGA::GetGatewareInfo() void FPGA::GatewareToDescriptor(const FPGA::GatewareInfo& gw, SDRDevice::Descriptor& desc) { desc.gatewareTargetBoard = GetDeviceName(eLMS_DEV(gw.boardID)); - desc.gatewareVersion = std::to_string(int(gw.version)); - desc.gatewareRevision = std::to_string(int(gw.revision)); - desc.hardwareVersion = std::to_string(int(gw.hardwareVersion)); + desc.gatewareVersion = std::to_string(gw.version); + desc.gatewareRevision = std::to_string(gw.revision); + desc.hardwareVersion = std::to_string(gw.hardwareVersion); } } //namespace lime diff --git a/src/FPGA_common/FPGA_common.h b/src/FPGA_common/FPGA_common.h index 584fde966..e5487c62a 100644 --- a/src/FPGA_common/FPGA_common.h +++ b/src/FPGA_common/FPGA_common.h @@ -4,9 +4,10 @@ @brief Common functions used to work with FPGA */ -#ifndef FPGA_COMMON_H -#define FPGA_COMMON_H -#include +#ifndef LIME_FPGA_H +#define LIME_FPGA_H + +#include #include #include @@ -93,4 +94,4 @@ class FPGA }; } // namespace lime -#endif // FPGA_COMMON_H +#endif // LIME_FPGA_H diff --git a/src/FPGA_common/WriteRegistersBatch.cpp b/src/FPGA_common/WriteRegistersBatch.cpp new file mode 100644 index 000000000..89cdac459 --- /dev/null +++ b/src/FPGA_common/WriteRegistersBatch.cpp @@ -0,0 +1,40 @@ +#include "WriteRegistersBatch.h" + +#ifndef NDEBUG + #define ASSERT_WARNING(cond, message) \ + if (!cond) \ + printf("W: %s (%s)\n", message, #cond) +#else + #define ASSERT_WARNING(cond, message) +#endif + +using namespace lime; + +/// @brief Constructor for the batch. +/// @param fpga The FPGA this batch belongs to. +WriteRegistersBatch::WriteRegistersBatch(FPGA* fpga) + : owner(fpga){}; + +WriteRegistersBatch::~WriteRegistersBatch() +{ + ASSERT_WARNING(addrs.size() == 0, "FPGA WriteRegistersBatch not flushed"); +} + +/// @brief Writes the modified values into the FPGA. +/// @return The operation status (0 on success). +int WriteRegistersBatch::Flush() +{ + int status = owner->WriteRegisters(addrs.data(), values.data(), addrs.size()); + addrs.clear(); + values.clear(); + return status; +} + +/// @brief Sets an address value pair to write into the FPGA on flushing. +/// @param addr The address to write to. +/// @param value The value to write. +void WriteRegistersBatch::WriteRegister(uint16_t addr, uint16_t value) +{ + addrs.push_back(addr); + values.push_back(value); +} diff --git a/src/FPGA_common/WriteRegistersBatch.h b/src/FPGA_common/WriteRegistersBatch.h new file mode 100644 index 000000000..67b140984 --- /dev/null +++ b/src/FPGA_common/WriteRegistersBatch.h @@ -0,0 +1,29 @@ +#ifndef LIME_WRITEREGISTERSBATCH_H +#define LIME_WRITEREGISTERSBATCH_H + +#include +#include + +#include "FPGA_common.h" + +namespace lime { + +/** @brief A class for writing a batch of registers into the FPGA. */ +class WriteRegistersBatch +{ + public: + WriteRegistersBatch(FPGA* fpga); + ~WriteRegistersBatch(); + + int Flush(); + void WriteRegister(uint16_t addr, uint16_t value); + + private: + FPGA* owner; + std::vector addrs; + std::vector values; +}; + +} // namespace lime + +#endif // LIME_WRITEREGISTERSBATCH_H \ No newline at end of file From aea60ae2932b39e32ee0eadf2ec9ff613bd0bb2b Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 27 Dec 2023 15:09:58 +0200 Subject: [PATCH 22/46] Clean up SetInterfaceFreq defintions --- src/FPGA_common/FPGA_common.cpp | 155 +++++++------------------- src/FPGA_common/FPGA_common.h | 4 +- src/boards/LimeSDR_Mini/FPGA_Mini.cpp | 19 ++-- src/boards/LimeSDR_Mini/FPGA_Mini.h | 2 +- src/boards/LimeSDR_X3/FPGA_X3.cpp | 2 +- src/boards/LimeSDR_X3/FPGA_X3.h | 4 +- src/boards/LimeSDR_XTRX/FPGA_XTRX.cpp | 2 +- src/boards/LimeSDR_XTRX/FPGA_XTRX.h | 4 +- 8 files changed, 60 insertions(+), 132 deletions(-) diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 3b44e6ce5..393191567 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -84,6 +84,9 @@ static constexpr bool HasFPGAClockPhaseSearch(uint8_t targetDevice, uint8_t vers } } +/// @brief Constructs the FPGA object. +/// @param fpgaSPI The FPGA communications interface. +/// @param lms7002mSPI The LMS7002M chip communications interface. FPGA::FPGA(std::shared_ptr fpgaSPI, std::shared_ptr lms7002mSPI) : fpgaPort(fpgaSPI) , lms7002mPort(lms7002mSPI) @@ -91,6 +94,8 @@ FPGA::FPGA(std::shared_ptr fpgaSPI, std::shared_ptr lms7002mSPI) { } +/// @brief Enables caching of registers on the hosts' end. +/// @param enabled Whether to enable or disable the caching. void FPGA::EnableValuesCache(bool enabled) { verbose_printf("Enable FPGA registers cache: %s\n", enabled ? "true" : "false"); @@ -117,6 +122,11 @@ int FPGA::ReadRegister(uint32_t address) return ReadRegisters(&address, &val, 1) != 0 ? -1 : val; } +/// @brief Writes the given registers into the FPGA's memory. +/// @param addrs The addresses to write to. +/// @param data The values to write into the memory. +/// @param cnt The amount of values to write. +/// @return The success status of the operation (0 on success). int FPGA::WriteRegisters(const uint32_t* addrs, const uint32_t* data, unsigned cnt) { std::vector spiBuffer; @@ -288,6 +298,8 @@ int FPGA::ReadRegisters(const uint32_t* addrs, uint32_t* data, unsigned cnt) return 0; } +/// @brief Tells the FPGA to start streaming sample data. +/// @return The operation status (0 on success). int FPGA::StartStreaming() { verbose_printf("%s\n", __func__); @@ -298,6 +310,8 @@ int FPGA::StartStreaming() return WriteRegister(0x000A, interface_ctrl_000A | RX_EN); } +/// @brief Tells the FPGA to stop streaming sample data. +/// @return The operation status (0 on success). int FPGA::StopStreaming() { verbose_printf("%s\n", __func__); @@ -308,6 +322,8 @@ int FPGA::StopStreaming() return WriteRegister(0x000A, interface_ctrl_000A & flags); } +/// @brief Resets the timestamp of the FPGA. +/// @return The operation status (0 on success). int FPGA::ResetTimestamp() { verbose_printf("%s\n", __func__); @@ -417,12 +433,12 @@ int FPGA::SetPllClock(uint clockIndex, int nSteps, bool waitLock, bool doPhaseSe return 0; } -/** @brief Configures board FPGA clocks - @param pllIndex index of FPGA pll - @param inputFreq input frequency - @param clocks list of clocks to configure - @param clockCount number of clocks to configure - @return 0-success, other-failure +/** @brief Configures board FPGA clocks. + @param pllIndex Index of FPGA PLL. + @param inputFreq Input frequency. + @param clocks List of clocks to configure. + @param clockCount Number of clocks to configure. + @return 0 on success, other on failure. */ int FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_PLL_clock* clocks, const uint8_t clockCount) { @@ -813,7 +829,7 @@ int FPGA::Samples2FPGAPacketPayload( if (mimo) { - complex16_t* ptr = (complex16_t*)buffer; + complex16_t* ptr = reinterpret_cast(buffer); for (int src = 0; src < samplesCount; ++src) { *ptr++ = samples[0][src]; @@ -821,117 +837,24 @@ int FPGA::Samples2FPGAPacketPayload( } return samplesCount * 2 * sizeof(complex16_t); } - memcpy(buffer, samples[0], samplesCount * sizeof(complex16_t)); + std::memcpy(buffer, samples[0], samplesCount * sizeof(complex16_t)); return samplesCount * sizeof(complex16_t); } -/* -int FPGA::UploadWFM(const void* const* samples, uint8_t chCount, size_t sample_count, StreamConfig::StreamDataFormat format, int epIndex) -{ - bool comp = (epIndex==2 && format!=StreamConfig::FMT_INT12) ? false : true; - - const int samplesInPkt = comp ? samples12InPkt : samples16InPkt; - WriteRegister(0xFFFF, 1 << epIndex); - WriteRegister(0x000C, chCount == 2 ? 0x3 : 0x1); //channels 0,1 - WriteRegister(0x000E, comp ? 0x2 : 0x0); //16bit samples - - uint16_t regValue = ReadRegister(0x000D); - regValue |= 0x4; - WriteRegister(0x000D, regValue); - - lime::FPGA_DataPacket pkt; - size_t samplesUsed = 0; - int cnt = sample_count; - - const complex16_t* const* src = (const complex16_t* const*)samples; - const lime::complex16_t** batch = new const lime::complex16_t*[chCount]; - lime::complex16_t** samplesShort = new lime::complex16_t*[chCount]; - for(unsigned i=0; i> 4; - samplesShort[ch][i].q = src[ch][i].q >> 4; - } - src = samplesShort; - } - else if(format == StreamConfig::FMT_FLOAT32) - { - const float mult = comp ? 2047.0f : 32767.0f; - for(unsigned i=0; i 0) - { - pkt.counter = 0; - pkt.reserved[0] = 0; - int samplesToSend = cnt > samplesInPkt/chCount ? samplesInPkt/chCount : cnt; - - for(unsigned i=0; i> 8) & 0xFF; //WFM loading - pkt.reserved[1] = payloadSize & 0xFF; //WFM loading - pkt.reserved[0] = 0x1 << 5; //WFM loading - - long bToSend = 16+payloadSize; - if (connection->SendData((const char*)&pkt,bToSend,epIndex,500)!=bToSend) - break; - cnt -= samplesToSend; - } - delete[] batch; - for(unsigned i=0; iAbortSending(epIndex); - if(cnt == 0) - return 0; - else - return ReportError(-1, "Failed to upload waveform"); -} -*/ - -/** @brief Configures FPGA PLLs to LimeLight interface frequency -*/ -int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase, int channel) +/// @brief Configures FPGA PLLs to LimeLight interface frequency. +/// @return 0 on success; other on failure. +int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase) { - verbose_printf("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz txPhase:%g rxPhase:%g ch:%i\n", + verbose_printf("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz txPhase:%g rxPhase:%g\n", txRate_Hz / 1e6, rxRate_Hz / 1e6, txPhase, - rxPhase, - channel); + rxPhase); lime::FPGA::FPGA_PLL_clock clocks[2]; int status = 0; const uint32_t addr = 0x002A; - uint32_t val; - val = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write + uint32_t val = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; // msbit 1=SPI write WriteLMS7002MSPI(&val, 1); ReadLMS7002MSPI(&addr, &val, 1); bool bypassTx = (val & 0xF0) == 0x00; @@ -965,11 +888,11 @@ int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, d /** @brief Configures FPGA PLLs to LimeLight interface frequency */ -int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int chipIndex) +int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int channel) { - verbose_printf("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz chipIndex:%i\n", txRate_Hz / 1e6, rxRate_Hz / 1e6, chipIndex); + verbose_printf("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz channel:%i\n", txRate_Hz / 1e6, rxRate_Hz / 1e6, channel); //PrintStackTrace(); - const int pll_ind = (chipIndex == 1) ? 2 : 0; + const int pll_ind = (channel == 1) ? 2 : 0; int status = 0; uint32_t reg20; bool bypassTx = false; @@ -996,7 +919,7 @@ int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int chipIndex) } if (!phaseSearch) - return SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz, chipIndex); + return SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz); std::vector dataRdA; std::vector dataRdB; @@ -1081,7 +1004,7 @@ int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int chipIndex) SetPllFrequency(pll_ind + 1, rxRate_Hz, clocks, 2); } - WriteRegister(0xFFFF, 1 << chipIndex); + WriteRegister(0xFFFF, 1 << channel); uint16_t reg_000A = ReadRegister(0x000A); WriteRegister(0x000A, reg_000A & ~(RX_EN | TX_EN | TX_PTRN_EN | RX_PTRN_EN)); // clear test patterns { @@ -1219,12 +1142,15 @@ double FPGA::DetectRefClk(double fx3Clk) return clkTbl[i - 1]; } +/// @brief Gets the information about the gateware of the device from the FPGA. +/// @return The gateware information of the FPGA. FPGA::GatewareInfo FPGA::GetGatewareInfo() { GatewareInfo info; info.boardID = 0; info.version = 0; info.revision = 0; + info.hardwareVersion = 0; const uint32_t addrs[4] = { 0x0000, 0x0001, 0x0002, 0x0003 }; uint32_t data[4]; @@ -1232,12 +1158,15 @@ FPGA::GatewareInfo FPGA::GetGatewareInfo() return info; info.boardID = data[0]; - info.version = (int16_t)data[1]; + info.version = data[1]; info.revision = data[2]; info.hardwareVersion = data[3] & 0x7F; return info; } +/// @brief Converts the Gateware information descriptor into an SDR Device descriptor. +/// @param gw The gateware information to convert. +/// @param[out] desc The descriptor to output the information to. void FPGA::GatewareToDescriptor(const FPGA::GatewareInfo& gw, SDRDevice::Descriptor& desc) { desc.gatewareTargetBoard = GetDeviceName(eLMS_DEV(gw.boardID)); diff --git a/src/FPGA_common/FPGA_common.h b/src/FPGA_common/FPGA_common.h index e5487c62a..92f6ed5ec 100644 --- a/src/FPGA_common/FPGA_common.h +++ b/src/FPGA_common/FPGA_common.h @@ -49,8 +49,8 @@ class FPGA double rd_actualFrequency; }; - virtual int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, double txPhase, double rxPhase, int ch = 0); - virtual int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, int ch = 0); + virtual int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, double txPhase, double rxPhase); + virtual int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, int channel); double DetectRefClk(double fx3Clk = 100e6); static int FPGAPacketPayload2Samples( diff --git a/src/boards/LimeSDR_Mini/FPGA_Mini.cpp b/src/boards/LimeSDR_Mini/FPGA_Mini.cpp index 739b91bbe..db91975ae 100644 --- a/src/boards/LimeSDR_Mini/FPGA_Mini.cpp +++ b/src/boards/LimeSDR_Mini/FPGA_Mini.cpp @@ -15,7 +15,7 @@ FPGA_Mini::FPGA_Mini(std::shared_ptr fpgaSPI, std::shared_ptr lms700 { } -int FPGA_Mini::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase, int channel) +int FPGA_Mini::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase) { int status = 0; @@ -44,17 +44,16 @@ int FPGA_Mini::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPha clocks[3].phaseShift_deg = rxPhase; status = SetPllFrequency(0, rxRate_Hz, clocks, 4); + return status; } - else - { - status = SetDirectClocking(0); - if (status == 0) - { - status = SetDirectClocking(1); - } + status = SetDirectClocking(0); + if (status != 0) + { + return status; } + status = SetDirectClocking(1); return status; } @@ -79,7 +78,7 @@ int FPGA_Mini::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int channel) if (!phaseSearch) { - return SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz, 0); + return SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz); } std::vector dataRd; @@ -184,7 +183,7 @@ int FPGA_Mini::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int channel) if (!rxPhaseSearchSuccess || !txPhaseSearchSuccess) { - SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz, 0); + SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz); return -1; } return 0; diff --git a/src/boards/LimeSDR_Mini/FPGA_Mini.h b/src/boards/LimeSDR_Mini/FPGA_Mini.h index e1c9f33aa..bdc303cb4 100644 --- a/src/boards/LimeSDR_Mini/FPGA_Mini.h +++ b/src/boards/LimeSDR_Mini/FPGA_Mini.h @@ -13,7 +13,7 @@ class FPGA_Mini : public FPGA public: FPGA_Mini(std::shared_ptr fpgaSPI, std::shared_ptr lms7002mSPI); virtual ~FPGA_Mini(){}; - virtual int SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase, int channel) override; + virtual int SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase) override; virtual int SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int channel) override; }; diff --git a/src/boards/LimeSDR_X3/FPGA_X3.cpp b/src/boards/LimeSDR_X3/FPGA_X3.cpp index a93d3c6b4..1aa828e19 100644 --- a/src/boards/LimeSDR_X3/FPGA_X3.cpp +++ b/src/boards/LimeSDR_X3/FPGA_X3.cpp @@ -15,7 +15,7 @@ FPGA_X3::FPGA_X3(std::shared_ptr fpgaSPI, std::shared_ptr lms7002mSP { } -int FPGA_X3::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase, int channel) +int FPGA_X3::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase) { FPGA::FPGA_PLL_clock clocks[2]; diff --git a/src/boards/LimeSDR_X3/FPGA_X3.h b/src/boards/LimeSDR_X3/FPGA_X3.h index 6561b220e..49df8f5b5 100644 --- a/src/boards/LimeSDR_X3/FPGA_X3.h +++ b/src/boards/LimeSDR_X3/FPGA_X3.h @@ -13,8 +13,8 @@ class FPGA_X3 : public FPGA public: FPGA_X3(std::shared_ptr fpgaSPI, std::shared_ptr lms7002mSPI); virtual ~FPGA_X3(){}; - int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, double txPhase, double rxPhase, int ch = 0) override; - int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, int ch = 0) override; + int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, double txPhase, double rxPhase) override; + int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, int channel) override; int SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_PLL_clock* clocks, const uint8_t clockCount); }; diff --git a/src/boards/LimeSDR_XTRX/FPGA_XTRX.cpp b/src/boards/LimeSDR_XTRX/FPGA_XTRX.cpp index 3b6d90a4c..f8fd7c04e 100644 --- a/src/boards/LimeSDR_XTRX/FPGA_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/FPGA_XTRX.cpp @@ -15,7 +15,7 @@ FPGA_XTRX::FPGA_XTRX(std::shared_ptr fpgaSPI, std::shared_ptr lms700 { } -int FPGA_XTRX::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase, int channel) +int FPGA_XTRX::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase) { lime::FPGA::FPGA_PLL_clock clocks[2]; diff --git a/src/boards/LimeSDR_XTRX/FPGA_XTRX.h b/src/boards/LimeSDR_XTRX/FPGA_XTRX.h index b66566d6a..c97674e0c 100644 --- a/src/boards/LimeSDR_XTRX/FPGA_XTRX.h +++ b/src/boards/LimeSDR_XTRX/FPGA_XTRX.h @@ -13,8 +13,8 @@ class FPGA_XTRX : public FPGA public: FPGA_XTRX(std::shared_ptr fpgaSPI, std::shared_ptr lms7002mSPI); virtual ~FPGA_XTRX(){}; - int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, double txPhase, double rxPhase, int ch = 0) override; - int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, int ch = 0) override; + int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, double txPhase, double rxPhase) override; + int SetInterfaceFreq(double f_Tx_Hz, double f_Rx_Hz, int channel) override; int SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_PLL_clock* clocks, const uint8_t clockCount); }; From fd94f1cf7c9e023e452cabf7d18997cbabb8772f Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 27 Dec 2023 15:34:54 +0200 Subject: [PATCH 23/46] Document a few more FPGA functions --- src/FPGA_common/FPGA_common.cpp | 20 ++++++++++++++++---- src/lms7002m/MCU_BD.h | 6 +++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 393191567..4330e6df3 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -201,22 +201,34 @@ int FPGA::WriteRegisters(const uint32_t* addrs, const uint32_t* data, unsigned c return 0; } +/// @brief Writes the given data blocks into LMS7002M chip. +/// @param data The data to write. +/// @param length The length of the data to write. +/// @return Whether the operation succeedded or not. int FPGA::WriteLMS7002MSPI(const uint32_t* data, uint32_t length) { #ifndef NDEBUG for (uint32_t i = 0; i < length; ++i) assert(data[i] & (1 << 31)); #endif - lms7002mPort->SPI(data, nullptr, length); - return 0; + return lms7002mPort->SPI(data, nullptr, length); } +/// @brief Reads the given addresses from the LMS7002M's memory. +/// @param writeData The addresses to read from. +/// @param readData The storage to store the read data. +/// @param length The length of the data to read. +/// @return Whether the operation succeedded or not. int FPGA::ReadLMS7002MSPI(const uint32_t* writeData, uint32_t* readData, uint32_t length) { - lms7002mPort->SPI(writeData, readData, length); - return 0; + return lms7002mPort->SPI(writeData, readData, length); } +/// @brief Reads the given registers from the FPGA's memory. +/// @param addrs The addresses to read. +/// @param data The data array to write the read values to. +/// @param cnt The amount of registers to read. +/// @return The operation status (0 on success). int FPGA::ReadRegisters(const uint32_t* addrs, uint32_t* data, unsigned cnt) { std::vector spiBuffer; diff --git a/src/lms7002m/MCU_BD.h b/src/lms7002m/MCU_BD.h index 768c1e26e..d7710dd02 100644 --- a/src/lms7002m/MCU_BD.h +++ b/src/lms7002m/MCU_BD.h @@ -101,11 +101,11 @@ class MCU_BD OperationStatus writeIRAM(const uint8_t* addr, const uint8_t* values, const uint8_t count); void Wait_CLK_Cycles(int data); - // The IRAM content + /// The IRAM content unsigned char m_IRAM[256]; - // The SFR content + /// The SFR content unsigned char m_SFR[256]; - // The program memory code + /// The program memory code unsigned char byte_array[cMaxFWSize]; void mSPI_write(unsigned short addr_reg, unsigned short data_reg); From c8667abc569e337e9dc6a54296ea06accd4139d1 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 2 Jan 2024 09:04:45 +0200 Subject: [PATCH 24/46] Clean up a small mistake in LMS7002M::GetGFIRCoefficients docs --- src/lms7002m/LMS7002M.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lms7002m/LMS7002M.cpp b/src/lms7002m/LMS7002M.cpp index 662897fcf..82461ff69 100644 --- a/src/lms7002m/LMS7002M.cpp +++ b/src/lms7002m/LMS7002M.cpp @@ -2185,12 +2185,12 @@ int LMS7002M::WriteGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, const float_t return SPI_write_batch(addrs, (const uint16_t*)words, actualCoefCount, true); } -/** @brief Returns currently loaded FIR coefficients - @param dir Transmitter or receiver selection - @param GFIR_index GIR index from 0 to 2 - @param coef array of returned coefficients - @param coefCount number of coefficients to read - @return 0-success, other-failure +/** @brief Returns currently loaded FIR coefficients. + @param dir Transmitter or receiver selection. + @param GFIR_index FIR index from 0 to 2. + @param coef Array of returned coefficients. + @param coefCount Number of coefficients to read. + @return 0-success, other-failure. */ int LMS7002M::GetGFIRCoefficients(TRXDir dir, uint8_t GFIR_index, int16_t* coef, uint8_t coefCount) { From 1771fe1a3694732a5bf3534bba40754bf71f005a Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 6 Feb 2024 15:28:16 +0200 Subject: [PATCH 25/46] Clean up misdocumented parameters warnings --- src/include/limesuite/LMS7002M.h | 23 +++++++++++++++-------- src/include/limesuite/SDRDevice.h | 4 ---- src/lms7002m/LMS7002M.cpp | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/include/limesuite/LMS7002M.h b/src/include/limesuite/LMS7002M.h index cae2f938f..9fbeeac9a 100644 --- a/src/include/limesuite/LMS7002M.h +++ b/src/include/limesuite/LMS7002M.h @@ -40,7 +40,7 @@ struct RSSI_measurements { typedef double float_type; /** @brief Class for communicating with the LMS7002M chip. - * + * * More information: https://limemicro.com/technology/lms7002m/ */ class LIME_API LMS7002M @@ -168,7 +168,8 @@ class LIME_API LMS7002M /*! * Set the RX PGA gain in dB - * @param gain in dB range -12.0, 19.0 dB + * @param gain In dB range -12.0, 19.0 dB + * @param channel The channel to set it for * @return 0 for success, else error */ int SetRBBPGA_dB(const float_type gain, const Channel channel); @@ -177,7 +178,8 @@ class LIME_API LMS7002M /*! * Set the RX LNA gain in dB - * @param gain in dB range 0.0, 30.0 dB + * @param gain In dB range 0.0, 30.0 dB + * @param channel The channel to set it for * @return 0 for success, else error */ int SetRFELNA_dB(const float_type gain, const Channel channel); @@ -186,7 +188,8 @@ class LIME_API LMS7002M /*! * Set the RX loopback LNA gain in dB - * @param gain in dB range 0.0, 40.0 dB + * @param gain In dB range 0.0, 40.0 dB + * @param channel The channel to set it for * @return 0 for success, else error */ int SetRFELoopbackLNA_dB(const float_type gain, const Channel channel); @@ -196,7 +199,8 @@ class LIME_API LMS7002M /*! * Set the RX TIA gain in dB - * @param gain in dB range 0.0, 12.0 dB + * @param gain In dB range 0.0, 12.0 dB + * @param channel The channel to set it for * @return 0 for success, else error */ int SetRFETIA_dB(const float_type gain, const Channel channel); @@ -205,7 +209,8 @@ class LIME_API LMS7002M /*! * Set the TX PAD gain in dB - * @param gain in dB range -52.0, 0.0 dB + * @param gain In dB range -52.0, 0.0 dB + * @param channel The channel to set it for * @return 0 for success, else error */ int SetTRFPAD_dB(const float_type gain, const Channel channel); @@ -215,7 +220,8 @@ class LIME_API LMS7002M /*! * Set the TBB frontend gain in dB - * @param gain in dB relative to optimal gain (0 - optimal gain, >0 may cause saturation) + * @param gain In dB relative to optimal gain (0 - optimal gain, >0 may cause saturation) + * @param channel The channel to set it for * @return 0 for success, else error */ int SetTBBIAMP_dB(const float_type gain, const Channel channel); @@ -225,7 +231,8 @@ class LIME_API LMS7002M /*! * Set the TX loopback PAD gain in dB - * @param gain in dB range -4.3, 0.0 dB + * @param gain In dB range -4.3, 0.0 dB + * @param channel The channel to set it for * @return 0 for success, else error */ int SetTRFLoopbackPAD_dB(const float_type gain, const Channel channel); diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index 3a4645c98..96cc41510 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -353,10 +353,6 @@ class LIME_API SDRDevice /// @param status The pointer to which to output the GPS status. virtual void GetGPSLock(GPS_Lock* status) = 0; - /// @brief Gets the current sample rate of the device. - /// @param moduleIndex The device index to get the sample rate of. - /// @param trx The direction of the sample rate to get. - /// @return The sample rate of the specified device and direction. virtual void EnableChannel(uint8_t moduleIndex, TRXDir trx, uint8_t channel, bool enable) = 0; /// @brief Gets the frequency of a specified clock. diff --git a/src/lms7002m/LMS7002M.cpp b/src/lms7002m/LMS7002M.cpp index 220e90283..6a235ae56 100644 --- a/src/lms7002m/LMS7002M.cpp +++ b/src/lms7002m/LMS7002M.cpp @@ -2215,7 +2215,7 @@ int LMS7002M::SetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, const float_typ /** @brief Returns currently loaded FIR coefficients. @param dir Transmitter or receiver selection. - @param GFIR_index GFIR index from 0 to 2. + @param gfirIndex GFIR index from 0 to 2. @param coef Array of returned coefficients (normalized from -1 to 1) @param coefCount Number of coefficients to read. @return 0-success, other-failure. From fa7f6fda324eb467801861e1ab9a4bfc5d9b73f3 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Wed, 7 Feb 2024 12:35:10 +0200 Subject: [PATCH 26/46] Add full documentation coverage of SDRDevice --- src/include/limesuite/SDRDevice.h | 280 +++++++++++++++++++++++++++--- src/lms7002m/LMS7002M.cpp | 4 +- 2 files changed, 261 insertions(+), 23 deletions(-) diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index 96cc41510..6ab336d62 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -32,26 +32,27 @@ class LIME_API SDRDevice /// @brief Enumerator to define the log level of a log message. enum class LogLevel : uint8_t { CRITICAL, ERROR, WARNING, INFO, VERBOSE, DEBUG }; + /// @brief Information about possible gain values. struct GainValue { - uint16_t hardwareRegisterValue; - float actualGainValue; + uint16_t hardwareRegisterValue; ///< The value that is written to the hardware + float actualGainValue; ///< The actual meaning of the value (in dB) }; /// @brief General information about the Radio-Frequency System-on-Chip (RFSoC). struct RFSOCDescriptor { - std::string name; - uint8_t channelCount; - std::unordered_map> pathNames; + std::string name; ///< The name of the system + uint8_t channelCount; ///< The available channel count of the system + std::unordered_map> pathNames; ///< The available antenna names Range frequencyRange; ///< Deliverable frequency capabilities of the device Range samplingRateRange; ///< Sampling rate capabilities of the device std::unordered_map> antennaRange; ///< Antenna recommended bandwidths - std::unordered_map lowPassFilterRange; + std::unordered_map lowPassFilterRange; ///< The ranges of the low pass filter - std::unordered_map> gains; - std::unordered_map> gainRange; - std::unordered_map>> gainValues; + std::unordered_map> gains; ///< The types of gains available + std::unordered_map> gainRange; ///< The available ranges of each gain + std::unordered_map>> gainValues; ///< The possible gain values }; /// @brief Structure for the information of a custom parameter. @@ -183,7 +184,7 @@ class LIME_API SDRDevice StreamConfig(); - std::unordered_map> channels; + std::unordered_map> channels; ///< The channels to set up for the stream. DataFormat format; ///< Samples format used for Read/Write functions DataFormat linkFormat; ///< Samples format used in transport layer Host<->FPGA @@ -192,7 +193,7 @@ class LIME_API SDRDevice /// Default: 0 - allow to decide internally. uint32_t bufferSize; - /// Optional: expected sampling rate for data transfer optimizations. + /// Optional: expected sampling rate for data transfer optimizations (in Hz). /// Default: 0 - decide internally. float hintSampleRate; bool alignPhase; ///< Attempt to do phases alignment between paired channels @@ -253,25 +254,33 @@ class LIME_API SDRDevice /// @brief Configuration of a general finite impulse response (FIR) filter. struct GFIRFilter { bool enabled; ///< Whether the filter is enabled or not. - double bandwidth; ///< The bandwidth of the filter. + double bandwidth; ///< The bandwidth of the filter (in Hz). }; + /// @brief The structure holding the status of the test signal the device can produce. struct TestSignal { + /// @brief The enumeration describing the divide mode of the test signal. enum class Divide : uint8_t { Div8 = 1U, Div4 = 2U, }; + /// @brief The enumeration describing the scale of the test signal. enum class Scale : uint8_t { Half = 0U, Full = 1U, }; - bool enabled; - bool dcMode; - Divide divide; - Scale scale; + bool enabled; ///< Denotes whether test mode is enabled or not. + bool dcMode; ///< The DC mode of the test mode. + Divide divide; ///< The current divide of the test signal. + Scale scale; ///< The current scale of the test signal. + /// @brief Constructs the TestSignal struct + /// @param enabled Denotes whether test mode is enabled or not (default false) + /// @param dcMode The DC mode of the test mode (default false) + /// @param divide The current divide of the test signal (default Div8) + /// @param scale The current scale of the test signal (default Half) TestSignal(bool enabled = false, bool dcMode = false, Divide divide = Divide::Div8, Scale scale = Scale::Half) : enabled(enabled) , dcMode(dcMode) @@ -281,11 +290,11 @@ class LIME_API SDRDevice } }; - double centerFrequency; ///< The center frequency of the direction of this channel. - double NCOoffset; ///< The offset from the channel's numerically controlled oscillator (NCO). - double sampleRate; ///< The sample rate of this direction of a channel. + double centerFrequency; ///< The center frequency of the direction of this channel (in Hz). + double NCOoffset; ///< The offset from the channel's numerically controlled oscillator (NCO) (in Hz). + double sampleRate; ///< The sample rate of this direction of a channel (in Hz). std::unordered_map gain; ///< The gains and their current values for this direction. - double lpf; ///< The bandwidth of the Low Pass Filter (LPF). + double lpf; ///< The bandwidth of the Low Pass Filter (LPF) (in Hz). uint8_t path; ///< The antenna being used for this direction. uint8_t oversample; ///< The oversample ratio of this direction. GFIRFilter gfir; ///< The general finite impulse response (FIR) filter settings of this direction. @@ -294,6 +303,9 @@ class LIME_API SDRDevice TestSignal testSignal; ///< Denotes whether the signal being sent is a test signal or not. }; + /// @brief Gets the reference to the direction settings. + /// @param direction The direction to get it for. + /// @return The reference to the direction. Direction& GetDirection(TRXDir direction) { switch (direction) @@ -305,6 +317,9 @@ class LIME_API SDRDevice } } + /// @brief Gets the const reference to the direction settings. + /// @param direction The direction to get it for. + /// @return The const reference to the direction. const Direction& GetDirection(TRXDir direction) const { switch (direction) @@ -353,6 +368,11 @@ class LIME_API SDRDevice /// @param status The pointer to which to output the GPS status. virtual void GetGPSLock(GPS_Lock* status) = 0; + /// @brief Enables or disables the specified channel. + /// @param moduleIndex The device index to configure. + /// @param trx The direction of the channel to configure. + /// @param channel The channel to configure. + /// @param enable Whether to enable the channel or not. virtual void EnableChannel(uint8_t moduleIndex, TRXDir trx, uint8_t channel, bool enable) = 0; /// @brief Gets the frequency of a specified clock. @@ -367,28 +387,120 @@ class LIME_API SDRDevice /// @param channel The channel to set the frequency of. virtual void SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) = 0; + /// @brief Gets the current frequency of the given channel. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return The current radio frequency of the channel (in Hz). virtual double GetFrequency(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + + /// @brief Sets the radio frequency of the given channel. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param frequency The frequency to set the channel to (in Hz). virtual void SetFrequency(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double frequency) = 0; + /// @brief Gets the current frequency of the NCO. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @param index The index of the NCO to read from. + /// @return The current frequency of the NCO (in Hz) virtual double GetNCOFrequency(uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t index) = 0; + + /// @brief Sets the frequency and the phase angle of the NCO. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param index The index of the NCO to use. + /// @param frequency The frequency of the NCO to set (in Hz). + /// @param phaseOffset Phase offset angle (in degrees) virtual void SetNCOFrequency( uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t index, double frequency, double phaseOffset = -1.0) = 0; + /// @brief Gets the current offset of the NCO compared to the main frequency. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return The delta between the current device frequency and the current device NCO frequency (in Hz). virtual double GetNCOOffset(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + /// @brief Gets the current sample rate of the device. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return The currend device sample rate (in Hz) virtual double GetSampleRate(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + + /// @brief Sets the sample rate of the device. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param sampleRate The target sample rate (in Hz) + /// @param oversample The RF oversampling ratio. virtual void SetSampleRate(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double sampleRate, uint8_t oversample) = 0; - virtual int SetGain(uint8_t moduleIndex, TRXDir direction, uint8_t channel, eGainTypes gain, double value) = 0; + /// @brief Gets the current value of the specified gain. + /// @param moduleIndex The device index to read from. + /// @param direction The direction to read from. + /// @param channel The channel to read from. + /// @param gain The type of gain to get the data of. + /// @param value The value of the gain (in dB). + /// @return The status code of the operation. virtual int GetGain(uint8_t moduleIndex, TRXDir direction, uint8_t channel, eGainTypes gain, double& value) = 0; + /// @brief Sets the gain level of a specified gain. + /// @param moduleIndex The device index to configure. + /// @param direction The direction to configure. + /// @param channel The channel to configure. + /// @param gain The type of gain to set. + /// @param value The amount of gain to set (in dB). + /// @return The status code of the operation. + virtual int SetGain(uint8_t moduleIndex, TRXDir direction, uint8_t channel, eGainTypes gain, double value) = 0; + + /// @brief Gets the current frequency of the Low Pass Filter. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return The current frequency of the Low Pass Filter (in Hz). virtual double GetLowPassFilter(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + + /// @brief Sets the Low Pass Filter to a specified frequency. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param lpf The bandwidth of the Low Pass Filter to set it to (in Hz). virtual void SetLowPassFilter(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double lpf) = 0; + /// @brief Gets the currently set antenna of the device. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return The ID of the currently set antenna. virtual uint8_t GetAntenna(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + + /// @brief Sets the current antenna of the device. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param path The ID of the antenna to set the device to use. virtual void SetAntenna(uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t path) = 0; + /// @brief Gets the current status of the test signal mode. + /// @param moduleIndex The device index to read from. + /// @param direction The direction to read from. + /// @param channel The channel to read from. + /// @return The current status of the test signal mode. virtual ChannelConfig::Direction::TestSignal GetTestSignal(uint8_t moduleIndex, TRXDir direction, uint8_t channel) = 0; + + /// @brief Sets the test signal mode. + /// @param moduleIndex The device index to configure. + /// @param direction The direction to configure. + /// @param channel The channel to configure. + /// @param signalConfiguration The configuration of the test mode to set. + /// @param dc_i The I value of the test mode to send (0 for defaults) + /// @param dc_q The Q value of the test mode to send (0 for defaults) virtual void SetTestSignal(uint8_t moduleIndex, TRXDir direction, uint8_t channel, @@ -396,38 +508,157 @@ class LIME_API SDRDevice int16_t dc_i = 0, int16_t dc_q = 0) = 0; + /// @brief Gets if the DC corrector bypass is enabled or not. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return Whether the DC corrector bypassis enabled or not (false = bypass the corrector, true = use the corrector) virtual bool GetDCOffsetMode(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + + /// @brief Enables or disables the DC corrector bypass. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param isAutomatic Whether to use the DC corrector bypass or not (false = bypass the corrector, true = use the corrector) virtual void SetDCOffsetMode(uint8_t moduleIndex, TRXDir trx, uint8_t channel, bool isAutomatic) = 0; + /// @brief Gets the DC I and Q corrector values. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return The current DC I and Q corrector values. virtual complex64f_t GetDCOffset(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + + /// @brief Sets the DC I and Q corrector values. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param offset The offsets of the I and Q channels. virtual void SetDCOffset(uint8_t moduleIndex, TRXDir trx, uint8_t channel, const complex64f_t& offset) = 0; + /// @brief Gets the current I and Q gain corrector values. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @param channel The channel to read from. + /// @return The current I and Q gain corrector values. virtual complex64f_t GetIQBalance(uint8_t moduleIndex, TRXDir trx, uint8_t channel) = 0; + + /// @brief Sets the I and Q gain corrector values. + /// @param moduleIndex The device index to configure. + /// @param trx The direction to configure. + /// @param channel The channel to configure. + /// @param balance The I and Q corrector values to set. virtual void SetIQBalance(uint8_t moduleIndex, TRXDir trx, uint8_t channel, const complex64f_t& balance) = 0; + /// @brief Gets whether the VCO comparators of the clock generator are locked or not. + /// @param moduleIndex The device index to read from. + /// @return A value indicating whether the VCO comparators of the clock generator are locked or not. virtual bool GetCGENLocked(uint8_t moduleIndex) = 0; + + /// @brief Gets the temperature of the device. + /// @param moduleIndex The device index to get the temperature of. + /// @return The temperature of the device (in degrees Celsius) virtual double GetTemperature(uint8_t moduleIndex) = 0; + /// @brief Gets whether the VCO comparators of the LO synthesizer are locked or not. + /// @param moduleIndex The device index to read from. + /// @param trx The direction to read from. + /// @return A value indicating whether the VCO comparators of the clock generator are locked or not. virtual bool GetSXLocked(uint8_t moduleIndex, TRXDir trx) = 0; + /// @brief Reads the value of the given register. + /// @param moduleIndex The device index to read from. + /// @param address The memory address to read from. + /// @param useFPGA Whether to read memory from the FPGA or not. + /// @return The value read from the register. virtual unsigned int ReadRegister(uint8_t moduleIndex, unsigned int address, bool useFPGA = false) = 0; + + /// @brief Writes the given register value to the given address. + /// @param moduleIndex The device index to configure. + /// @param address The address of the memory to write to. + /// @param value The value to write to the device's memory. + /// @param useFPGA Whether to write to the FPGA or not (default false) virtual void WriteRegister(uint8_t moduleIndex, unsigned int address, unsigned int value, bool useFPGA = false) = 0; + /// @brief Loads the configuration of a device from a given file. + /// @param moduleIndex The device index to write the configuration into. + /// @param filename The file to read the data from. virtual void LoadConfig(uint8_t moduleIndex, const std::string& filename) = 0; + + /// @brief Saves the current configuration of the device into a given file. + /// @param moduleIndex The device index to save the data from. + /// @param filename The file to save the information to. virtual void SaveConfig(uint8_t moduleIndex, const std::string& filename) = 0; + /// @brief Gets the given parameter from the device. + /// @param moduleIndex The device index to configure. + /// @param channel The channel to configure. + /// @param parameterKey The key of the paremeter to read from. + /// @return The value read from the parameter. virtual uint16_t GetParameter(uint8_t moduleIndex, uint8_t channel, const std::string& parameterKey) = 0; + + /// @brief Sets the given parameter in the device. + /// @param moduleIndex The device index to configure. + /// @param channel The channel to configure. + /// @param parameterKey The key of the paremeter to write to. + /// @param value The value to write to the address. virtual void SetParameter(uint8_t moduleIndex, uint8_t channel, const std::string& parameterKey, uint16_t value) = 0; + /// @brief Gets the given parameter from the device. + /// @param moduleIndex The device index to get the data from. + /// @param channel The channel to get the data from. + /// @param address The memory address of the device to read. + /// @param msb The index of the most significant bit of the address to read. (16-bit register) + /// @param lsb The index of the least significant bit of the address to read. (16-bit register) + /// @return The value read from the parameter. virtual uint16_t GetParameter(uint8_t moduleIndex, uint8_t channel, uint16_t address, uint8_t msb, uint8_t lsb) = 0; + + /// @brief Sets the given parameter in the device. + /// @param moduleIndex The device index to configure. + /// @param channel The channel to configure. + /// @param address The memory address in the device to change. + /// @param msb The index of the most significant bit of the address to modify. (16-bit register) + /// @param lsb The index of the least significant bit of the address to modify. (16-bit register) + /// @param value The value to write to the address. virtual void SetParameter(uint8_t moduleIndex, uint8_t channel, uint16_t address, uint8_t msb, uint8_t lsb, uint16_t value) = 0; + /// @brief Calibrates the given channel for a given bandwidth. + /// @param moduleIndex The device index to configure. + /// @param trx The direction of the channel to configure. + /// @param channel The channel to configure. + /// @param bandwidth The bandwidth of the channel to calibrate for (in Hz). virtual void Calibrate(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double bandwidth) = 0; + + /// @brief Configures the GFIR with the settings. + /// @param moduleIndex The device index to configure. + /// @param trx The direction of the channel to configure. + /// @param channel The channel to configure. + /// @param settings The settings of the GFIR to set. virtual void ConfigureGFIR(uint8_t moduleIndex, TRXDir trx, uint8_t channel, ChannelConfig::Direction::GFIRFilter settings) = 0; + /// @brief Gets the current coefficients of a GFIR. + /// @param moduleIndex The device index to get the coefficients from. + /// @param trx The direction of the channel to get the data from. + /// @param channel The channel to get the data from. + /// @param gfirID The ID of the GFIR to get the coefficients from. + /// @return The current coefficients (normalized in the range [-1; 1]) of the GFIR. virtual std::vector GetGFIRCoefficients(uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t gfirID) = 0; + + /// @brief Sets the coefficients of a given GFIR + /// @param moduleIndex The device index to configure. + /// @param trx The direction of the channel to configure. + /// @param channel The channel to set the filter of. + /// @param gfirID The ID of the GFIR to set. + /// @param coefficients The coefficients (normalized in the range [-1; 1]) to set the GFIR to. virtual void SetGFIRCoefficients( uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t gfirID, std::vector coefficients) = 0; + + /// @brief Sets the GFIR to use. + /// @param moduleIndex The device index to configure. + /// @param trx The direction of the channel to configure. + /// @param channel The channel to set the filter of. + /// @param gfirID The ID of the GFIR to set. + /// @param enabled Whether the specifed GFIR should be enabled or disabled. virtual void SetGFIR(uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t gfirID, bool enabled) = 0; /// @brief Synchronizes the cached changed register values on the host with the real values on the device. @@ -438,7 +669,14 @@ class LIME_API SDRDevice /// @param enable Whether to enable or disable the register value caching (true = enabled). virtual void EnableCache(bool enable) = 0; + /// @brief Gets the hardware timestamp with the applied offset. + /// @param moduleIndex The device index to configure. + /// @return The current timestamp of the hardware. virtual uint64_t GetHardwareTimestamp(uint8_t moduleIndex) = 0; + + /// @brief Sets the hardware timestamp to the provided one by applying a constant offset. + /// @param moduleIndex The device index to configure. + /// @param now What the definition of the current time should be. virtual void SetHardwareTimestamp(uint8_t moduleIndex, const uint64_t now) = 0; /// @brief Sets up all the streams on a device. diff --git a/src/lms7002m/LMS7002M.cpp b/src/lms7002m/LMS7002M.cpp index 6a235ae56..392d49da0 100644 --- a/src/lms7002m/LMS7002M.cpp +++ b/src/lms7002m/LMS7002M.cpp @@ -1716,8 +1716,8 @@ int LMS7002M::Modify_SPI_Reg_bits(const LMS7Parameter& param, const uint16_t val /** @brief Change given parameter value @param address register address - @param msb Most significant byte - @param lsb Least significant byte + @param msb Most significant bit index + @param lsb Least significant bit index @param value new bits value, the value is shifted left by lsb bits @param fromChip read initial value directly from chip */ From ff23ae15a0ae32e33df437f2551c0546e769503b Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 8 Feb 2024 12:56:11 +0200 Subject: [PATCH 27/46] Document and slightly refactor LMS7002M's methods. --- src/boards/LMS7002M_SDRDevice.cpp | 6 +- src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp | 2 +- src/boards/LimeSDR_X3/LimeSDR_X3.cpp | 7 +- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 7 +- src/include/limesuite/LMS7002M.h | 584 ++++++++++++++++++-- src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp | 2 +- src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp | 2 +- src/lms7002m/LMS7002M.cpp | 542 ++++++------------ src/lms7002m/LMS7002M_RxTxCalibrations.cpp | 11 - src/lms7002m/LMS7002M_gainCalibrations.cpp | 18 +- src/protocols/TRXLooper.cpp | 2 +- 11 files changed, 739 insertions(+), 444 deletions(-) diff --git a/src/boards/LMS7002M_SDRDevice.cpp b/src/boards/LMS7002M_SDRDevice.cpp index 47bcf0ce5..a62ceef3b 100644 --- a/src/boards/LMS7002M_SDRDevice.cpp +++ b/src/boards/LMS7002M_SDRDevice.cpp @@ -461,7 +461,9 @@ void LMS7002M_SDRDevice::ConfigureGFIR( uint8_t moduleIndex, TRXDir trx, uint8_t channel, ChannelConfig::Direction::GFIRFilter settings) { LMS7002M* lms = mLMSChips.at(moduleIndex); - int returnValue = lms->SetGFIRFilter(trx, channel, settings.enabled, settings.bandwidth); + LMS7002M::Channel enumChannel = channel > 0 ? LMS7002M::Channel::ChB : LMS7002M::Channel::ChA; + + int returnValue = lms->SetGFIRFilter(trx, enumChannel, settings.enabled, settings.bandwidth); if (returnValue != 0) { throw std::runtime_error("Setting GFIR Filter failed"); @@ -1113,7 +1115,7 @@ int LMS7002M_SDRDevice::UpdateFPGAInterfaceFrequency(LMS7002M& soc, FPGA& fpga, if (fpga.SetInterfaceFreq(fpgaTxPLL, fpgaRxPLL, chipIndex) != 0) return -1; - soc.ResetLogicregisters(); + soc.ResetLogicRegisters(); return 0; } diff --git a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp index d4bcc4442..00ab5323f 100644 --- a/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp +++ b/src/boards/LimeSDR_Mini/LimeSDR_Mini.cpp @@ -315,7 +315,7 @@ int LimeSDR_Mini::Init() lms->Modify_SPI_Reg_bits(LMS7param(MAC), 1); - if (lms->CalibrateTxGain(0, nullptr) != 0) + if (lms->CalibrateTxGain() != 0) return -1; lms->EnableChannel(TRXDir::Tx, 0, false); diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp index c45b8db47..a1667d6ef 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp @@ -154,9 +154,8 @@ int LimeSDR_X3::LMS1_UpdateFPGAInterface(void* userData) return UpdateFPGAInterfaceFrequency(*soc, *pthis->mFPGA, chipIndex); } - /// @brief Constructs a new LimeSDR_X3 object -/// +/// /// Do not perform any unnecessary configuring to device in constructor, so you /// could read back it's state for debugging purposes /// @param spiLMS7002M The communications port to the LMS7002M chips. @@ -666,7 +665,9 @@ void LimeSDR_X3::ConfigureDirection(TRXDir dir, LMS7002M* chip, const SDRConfig& if (socIndex == 0) { - if (trx.enabled && chip->SetGFIRFilter(dir, ch, trx.gfir.enabled, trx.gfir.bandwidth) != 0) + if (trx.enabled && + chip->SetGFIRFilter( + dir, ch == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB, trx.gfir.enabled, trx.gfir.bandwidth) != 0) { throw std::logic_error(strFormat("%s ch%i GFIR config failed", dirName, ch)); } diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index f75aed5d4..2256602b5 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -303,14 +303,15 @@ void LimeSDR_XTRX::Configure(const SDRConfig& cfg, uint8_t socIndex) for (int i = 0; i < 2; ++i) { - chip->SetActiveChannel(i == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB); + LMS7002M::Channel enumChannel = i == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB; + chip->SetActiveChannel(enumChannel); const ChannelConfig& ch = cfg.channel[i]; if (socIndex == 0) { - if (ch.rx.enabled && chip->SetGFIRFilter(TRXDir::Rx, i, ch.rx.gfir.enabled, ch.rx.gfir.bandwidth) != 0) + if (ch.rx.enabled && chip->SetGFIRFilter(TRXDir::Rx, enumChannel, ch.rx.gfir.enabled, ch.rx.gfir.bandwidth) != 0) throw std::logic_error(strFormat("Rx ch%i GFIR config failed", i)); - if (ch.tx.enabled && chip->SetGFIRFilter(TRXDir::Tx, i, ch.tx.gfir.enabled, ch.tx.gfir.bandwidth) != 0) + if (ch.tx.enabled && chip->SetGFIRFilter(TRXDir::Tx, enumChannel, ch.tx.gfir.enabled, ch.tx.gfir.bandwidth) != 0) throw std::logic_error(strFormat("Tx ch%i GFIR config failed", i)); } diff --git a/src/include/limesuite/LMS7002M.h b/src/include/limesuite/LMS7002M.h index 9fbeeac9a..63d28afc1 100644 --- a/src/include/limesuite/LMS7002M.h +++ b/src/include/limesuite/LMS7002M.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -39,15 +40,17 @@ struct RSSI_measurements { typedef double float_type; -/** @brief Class for communicating with the LMS7002M chip. +/*! @brief Class for communicating with the LMS7002M chip. * * More information: https://limemicro.com/technology/lms7002m/ */ class LIME_API LMS7002M { public: + /// @brief The maximum frequency of the onboard clock generator. static constexpr double CGEN_MAX_FREQ = 640e6; + /// @brief The IDs of the clocks on the chip. enum class ClockID : uint8_t { CLK_REFERENCE = 0, ///< Reference clock CLK_SXR = 1, ///< RX LO clock @@ -82,14 +85,22 @@ class LIME_API LMS7002M bool success; }; + /*! + * The constructor for the LMS7002M chip. + * @param port The connection interface + */ LMS7002M(std::shared_ptr port); /*! * Set the connection for the LMS7002M driver. - * @param port the connection interface + * @param port The connection interface */ void SetConnection(std::shared_ptr port); + /*! + * @brief Get the current connection to the device. + * @return The connection to the device. + */ std::shared_ptr GetConnection(void) const { return controlPort; } virtual ~LMS7002M(); @@ -109,15 +120,24 @@ class LIME_API LMS7002M /*! * Set the selected channel (MAC). * The API calls will reflect this channel. + * + * @param ch The channel to set the chip to. */ void SetActiveChannel(const Channel ch); /*! * Get the selected channel (MAC). * The API calls will reflect this channel. + * @param fromChip Whether to read directly from the chip or use the cache (true = device, false = cache) + * @return The currently active channel. */ Channel GetActiveChannel(bool fromChip = true); + /*! + * Gets the index of the current selected channel (MAC) + * @param fromChip Whether to read directly from the chip or use the cache (true = device, false = cache) + * @return The index of the currently active channel (0 - Channel A, 1 - Channel B) + */ size_t GetActiveChannelIndex(bool fromChip = true); /*! @@ -127,43 +147,193 @@ class LIME_API LMS7002M * @param dir Rx or Tx * @param channel true for the transmit size, false for receive * @param enable true to enable, false to disable + * @return 0 - success, other - failure */ int EnableChannel(TRXDir dir, const uint8_t channel, const bool enable); + /*! + * @brief Writes all registers from host to chip + * @return 0-success, other-failure + */ int UploadAll(); + + /*! + * @brief Reads all registers from the chip to host + * @return 0-success, other-failure + */ int DownloadAll(); + + /*! + * @brief Reads all chip configuration and checks if it matches with local registers copy. + * @return Whether the cached value is synced with the device or not + */ bool IsSynced(); + + /** + * @brief Copies all the channel specific registers from one channel to another one. + * @param src The channel to copy from. + * @param dest The channel to copy to. + * @param copySX Whether to copy the SX registers or not. + * @return 0-success, other-failure + */ int CopyChannelRegisters(const Channel src, const Channel dest, bool copySX); + /*! + * @brief Sends reset signal to chip, after reset enables B channel controls + * @return 0-success, other-failure + */ int ResetChip(); /*! * Perform soft-reset sequence over SPI + * @return 0 - success, other - failure */ int SoftReset(); - int ResetLogicregisters(); + /*! + * @brief Resets the logic registers to their default state. + * @return 0 - success, other - failure + */ + int ResetLogicRegisters(); + + /*! + * @brief Reads configuration file and uploads registers to chip + * @param filename Configuration source file + * @param tuneDynamicValues Whether to tune the dynamic values or not + * @return 0 - success, other - failure + */ int LoadConfig(const std::string& filename, bool tuneDynamicValues = true); + + /*! + * @brief Reads all registers from chip and saves to file + * @param filename destination filename + * @return 0-success, other failure + */ int SaveConfig(const std::string& filename); + /*! + * @brief Returns given parameter value from chip register + * @param param LMS7002M control parameter + * @param fromChip read directly from chip + * @return parameter value + */ uint16_t Get_SPI_Reg_bits(const LMS7Parameter& param, bool fromChip = false); + + /*! + * @brief Returns given parameter value from chip register + * @param address register address + * @param msb most significant bit index + * @param lsb least significant bit index + * @param fromChip read directly from chip + * @return register bits from selected interval, shifted to right by lsb bits + */ uint16_t Get_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, bool fromChip = false); + + /*! + * @brief Change given parameter value + * @param param LMS7002M control parameter + * @param fromChip read initial value directly from chip + * @param value new parameter value + * @return 0 - success, other - failure + */ int Modify_SPI_Reg_bits(const LMS7Parameter& param, const uint16_t value, bool fromChip = false); + + /*! + * @brief Change given parameter value + * @param address register address + * @param msb Most significant bit index + * @param lsb Least significant bit index + * @param value new bits value, the value is shifted left by lsb bits + * @param fromChip read initial value directly from chip + * @return 0 - success, other - failure + */ int Modify_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, uint16_t value, bool fromChip = false); + + /*! + * @brief Write given data value to whole register + * @param address SPI address + * @param data new register value + * @param toChip whether we're writing to the chip or not + * @return 0-success, other-failure + */ int SPI_write(uint16_t address, uint16_t data, bool toChip = false); + + /*! + * @brief Reads whole register value from given address + * @param address SPI address + * @param status operation status(optional) + * @param fromChip read value directly from chip + * @return register value + */ uint16_t SPI_read(uint16_t address, bool fromChip = false, int* status = 0); + + /*! + * @brief Performs registers test by writing known data and confirming readback data + * @param fileName The name of the file to write the test output to. + * @return 0-registers test passed, other-failure + */ int RegistersTest(const std::string& fileName = "registersTest.txt"); + + /*! + * @brief Get parameter by name + * @param name The name of the parameter to get. + * @return A constant reference to the parameter + */ static const LMS7Parameter& GetParam(const std::string& name); - int CalibrateRx(float_type bandwidth, const bool useExtLoopback = false); - int CalibrateTx(float_type bandwidth, const bool useExtLoopback = false); + /*! + * @brief Calibrates Receiver. DC offset, IQ gains, IQ phase correction + * @param bandwidth_Hz The bandwidth to calibrate the device for (in Hz) + * @param useExtLoopback Whether to use external loopback or not. + * @return 0 - success, other - failure + */ + int CalibrateRx(float_type bandwidth_Hz, const bool useExtLoopback = false); + + /*! + * @brief Calibrates Transmitter. DC correction, IQ gains, IQ phase correction + * @param bandwidth_Hz The bandwidth to calibrate the device for (in Hz) + * @param useExtLoopback Whether to use external loopback or not. + * @return 0 - success, other - failure + */ + int CalibrateTx(float_type bandwidth_Hz, const bool useExtLoopback = false); + + /** + * @brief Tunes the Low Pass Filter for the TX direction. + * @param tx_lpf_freq_RF The frequency (in Hz) to tune the filter to. + * @return 0 - success, other - failure + */ + int TuneTxFilter(const float_type tx_lpf_freq_RF); - int TuneTxFilter(const float_type bandwidth); + /** + * @brief Tunes the Low Pass Filter for the RX direction. + * @param rx_lpf_freq_RF The frequency (in Hz) to tune the filter to. + * @return 0 - success, other - failure + */ int TuneRxFilter(const float_type rx_lpf_freq_RF); + /*! + * @brief Calibrates the internal Analog to Digital Converter on the chip. + * @param clkDiv The clock division ratio for measurement loop. + * @return 0 for success, else error + */ int CalibrateInternalADC(int clkDiv = 32); + + /*! + * @brief Calibrates the RP_BIAS of the chip. + * @return 0 for success, else error + */ int CalibrateRP_BIAS(); - int CalibrateTxGain(float maxGainOffset_dBFS, float* actualGain_dBFS); + + /*! + * @brief Calibrates the TX gain. + * @return 0 for success, else error + */ + int CalibrateTxGain(); + + /** + * @brief Calibrates the Analog RSSI + * @return 0 for success, else error + */ int CalibrateAnalogRSSI_DC_Offset(); /*! @@ -174,6 +344,11 @@ class LIME_API LMS7002M */ int SetRBBPGA_dB(const float_type gain, const Channel channel); + /*! + * Gets the RX PGA gain in dB + * @param channel The channel to get it from + * @return The RX PGA gain (in dB) + */ float_type GetRBBPGA_dB(const Channel channel); /*! @@ -184,6 +359,11 @@ class LIME_API LMS7002M */ int SetRFELNA_dB(const float_type gain, const Channel channel); + /*! + * Gets the RX LNA gain in dB + * @param channel The channel to get it from + * @return The RX LNA gain (in dB) + */ float_type GetRFELNA_dB(const Channel channel); /*! @@ -194,7 +374,11 @@ class LIME_API LMS7002M */ int SetRFELoopbackLNA_dB(const float_type gain, const Channel channel); - //! Get the actual RX loopback LNA gain in dB + /*! + * Get the actual RX loopback LNA gain in dB + * @param channel The channel to get it from + * @return The actual RX loopback LNA gain (in dB) + */ float_type GetRFELoopbackLNA_dB(const Channel channel); /*! @@ -205,6 +389,11 @@ class LIME_API LMS7002M */ int SetRFETIA_dB(const float_type gain, const Channel channel); + /*! + * Get the RX TIA gain in dB + * @param channel The channel to get it from + * @return The RX TIA gain in dB + */ float_type GetRFETIA_dB(const Channel channel); /*! @@ -215,7 +404,11 @@ class LIME_API LMS7002M */ int SetTRFPAD_dB(const float_type gain, const Channel channel); - //! Get the actual TX PAD gain in dB + /*! + * @brief Gets the actual TX PAD gain. + * @param channel The channel to get the gain from. + * @return The actual TX PAD gain (in dB). + */ float_type GetTRFPAD_dB(const Channel channel); /*! @@ -226,7 +419,11 @@ class LIME_API LMS7002M */ int SetTBBIAMP_dB(const float_type gain, const Channel channel); - //! Get the TBB frontend gain in dB + /*! + * @brief Gets the TBB frontend gain. + * @param channel The channel to get the gain from. + * @return The actual TBB frontend gain (in dB). + */ float_type GetTBBIAMP_dB(const Channel channel); /*! @@ -237,9 +434,14 @@ class LIME_API LMS7002M */ int SetTRFLoopbackPAD_dB(const float_type gain, const Channel channel); - //! Get the actual TX loopback PAD gain in dB + /*! + * @brief Gets the actual TX loopback PAD gain. + * @param channel The channel to get the gain from. + * @return The actual TX loopback PAD gain (in dB). + */ float_type GetTRFLoopbackPAD_dB(const Channel channel); + /// @brief The possible antennae on the chip. enum class PathRFE : uint8_t { NONE, LNAH, @@ -249,15 +451,23 @@ class LIME_API LMS7002M LB2, }; - //! Set the RFE input path. + /*! + * @brief Sets the RFE input path. + * @param path The enumeration value of the path to set it to + * @return 0-success, other-failure + */ int SetPathRFE(PathRFE path); - //! Get the currently set RFE path + /*! + * @brief Gets the currently set RFE path + * @return The enumerator value of the currently selected RFE path. + */ PathRFE GetPathRFE(void); /*! * Set the TRF Band selection. * @param band 1 or 2 + * @return 0 - success, other - failure */ int SetBandTRF(const int band); @@ -267,47 +477,253 @@ class LIME_API LMS7002M */ int GetBandTRF(void); + /*! + * @brief Sets the antenna to use on the device + * @param direction The direction to set the antenna for. + * @param channel The channel to set the antenna for. + * @param path The index of the antenna to use. + * @return 0-success, other-failure + */ int SetPath(TRXDir direction, uint8_t channel, uint8_t path); + /*! + * @brief Sets the reference clock of the SX + * @param dir Rx/Tx module selection + * @param freq_Hz The frequency to set the reference clock to (in Hz) + * @return 0-success, other-failure + */ int SetReferenceClk_SX(TRXDir dir, float_type freq_Hz); + + /*! + * @brief Returns reference clock in Hz used for SXT or SXR. + * @param dir transmitter or receiver selection. + * @return The reference clock speed (in Hz). + */ float_type GetReferenceClk_SX(TRXDir dir); + + /*! + * Returns the curernt frequency of the clock generator. + * @return Current CLKGEN frequency in Hz. + * Returned frequency depends on reference clock used for Receiver. + */ float_type GetFrequencyCGEN(); + + /*! + * @brief Sets CLKGEN frequency, calculations use receiver'r reference clock + * @param freq_Hz desired frequency in Hz + * @param retainNCOfrequencies recalculate NCO coefficients to keep currently set frequencies + * @param output if not null outputs calculated CGEN parameters + * @return 0-success, other-cannot deliver desired frequency + */ int SetFrequencyCGEN(float_type freq_Hz, const bool retainNCOfrequencies = false, CGEN_details* output = nullptr); + + /*! + * @brief Gets whether the VCO comparators of the clock generator are locked or not. + * @return A value indicating whether the VCO comparators of the clock generator are locked or not. + */ bool GetCGENLocked(void); + + /*! + * @brief Returns currently set SXR/SXT frequency + * @param dir Rx/Tx module selection + * @return SX frequency Hz + */ float_type GetFrequencySX(TRXDir dir); + + /*! + * @brief Sets SX frequency + * @param dir Rx/Tx module selection + * @param freq_Hz desired frequency in Hz + * @param output if not null outputs intermediate calculation values + * @return 0-success, other-cannot deliver requested frequency + */ int SetFrequencySX(TRXDir dir, float_type freq_Hz, SX_details* output = nullptr); + + /*! + * @brief Sets SX frequency with Reference clock spur cancelation + * @param dir Rx/Tx module selection + * @param freq_Hz desired frequency in Hz + * @param BW The bandwidth (in Hz) + * @return 0-success, other-cannot deliver requested frequency + */ int SetFrequencySXWithSpurCancelation(TRXDir dir, float_type freq_Hz, float_type BW); + + /*! + * @brief Gets whether the VCO comparators of the LO synthesizer are locked or not. + * @param dir The direction to read from. + * @return A value indicating whether the VCO comparators of the clock generator are locked or not. + */ bool GetSXLocked(TRXDir dir); ///VCO modules available for tuning enum class VCO_Module : uint8_t { VCO_CGEN, VCO_SXR, VCO_SXT }; + + /*! + * @brief Performs VCO tuning operations for CLKGEN + * @return 0-success, other-failure + */ int TuneCGENVCO(); + + /*! + * @brief Performs VCO tuning operations for CLKGEN, SXR, SXT modules + * @param module module selection for tuning 0-cgen, 1-SXR, 2-SXT + * @return 0-success, other-failure + */ int TuneVCO(VCO_Module module); + /*! + * @brief Loads given DC_REG values into registers + * @param dir TxTSP or RxTSP selection + * @param I DC_REG I value + * @param Q DC_REG Q value + * @return 0-success, other-failure + */ int LoadDC_REG_IQ(TRXDir dir, int16_t I, int16_t Q); + + /*! + * @brief Sets chosen NCO's frequency + * @param dir transmitter or receiver selection + * @param index NCO index from 0 to 15 + * @param freq_Hz desired NCO frequency + * @return 0-success, other-failure + */ int SetNCOFrequency(TRXDir dir, uint8_t index, float_type freq_Hz); + + /*! + * @brief Returns chosen NCO's frequency in Hz + * @param dir transmitter or receiver selection + * @param index NCO index from 0 to 15 + * @param fromChip read frequency directly from chip or local registers + * @return NCO frequency in Hz + */ float_type GetNCOFrequency(TRXDir dir, uint8_t index, bool fromChip = true); - int SetNCOPhaseOffsetForMode0(TRXDir dir, float_type angle_Deg); - int SetNCOPhaseOffset(TRXDir dir, uint8_t index, float_type angle_Deg); + + /*! + * @brief Sets chosen NCO phase offset angle when memory table MODE is 0 + * @param dir transmitter or receiver selection + * @param angle_deg phase offset angle in degrees + * @return 0-success, other-failure + */ + int SetNCOPhaseOffsetForMode0(TRXDir dir, float_type angle_deg); + + /*! + * @brief Sets chosen NCO's phase offset angle + * @param dir transmitter or receiver selection + * @param index PHO index from 0 to 15 + * @param angle_deg phase offset angle in degrees + * @return 0-success, other-failure + */ + int SetNCOPhaseOffset(TRXDir dir, uint8_t index, float_type angle_deg); + + /*! + * @brief Returns chosen NCO's phase offset angle in radians + * @param dir transmitter or receiver selection + * @param index PHO index from 0 to 15 + * @return phase offset angle in degrees + */ float_type GetNCOPhaseOffset_Deg(TRXDir dir, uint8_t index); + + /*! + * @brief Returns TSP reference frequency + * @param dir TxTSP or RxTSP selection + * @return TSP reference frequency in Hz + */ float_type GetReferenceClk_TSP(TRXDir dir); + /*! + * @brief Returns currently loaded FIR coefficients. + * @param dir Transmitter or receiver selection. + * @param gfirIndex GFIR index from 0 to 2. + * @param coef Array of returned coefficients (normalized from -1 to 1) + * @param coefCount Number of coefficients to read. + * @return 0-success, other-failure. + */ int GetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, float_type* coef, uint8_t coefCount); + + /*! + * @brief Uploads given FIR coefficients to chip + * @param dir Transmitter or receiver selection + * @param gfirIndex GIR index from 0 to 2 + * @param coef array of coefficients (normalized from -1 to 1) + * @param coefCount number of coefficients + * @return 0-success, other-failure + * + * This function does not change GFIR*_L or GFIR*_N parameters, they have to be set manually + */ int SetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, const float_type* coef, uint8_t coefCount); - int SetGFIRFilter(TRXDir dir, unsigned ch, bool enabled, double bandwidth); + /*! + * @brief Sets up the GFIR filter. + * @param dir The direction for which to set up the filter. + * @param ch The channel for which to set up the filter + * @param enabled Whether to enable or disable the GFIR filter + * @param bandwidth The bandwidth (in Hz) to set the filter for. + * @return 0-success, other-failure + */ + int SetGFIRFilter(TRXDir dir, Channel ch, bool enabled, double bandwidth); + + /*! + * @brief Sets the frequencies of the NCO. + * @param dir The direction for which to set the frequencies. + * @param freq_Hz The frequency array to set. + * @param count The amount of frequencies to set (max 16) + * @param phaseOffset The phase offset of the NCO to set. + * @return 0-success, other-failure + */ int SetNCOFrequencies(TRXDir dir, const float_type* freq_Hz, uint8_t count, float_type phaseOffset); + /*! + * @brief Gets the current frequencies of the NCO. + * @param dir The direction to receive the frequencies of. + * @param phaseOffset Returns the phase offset in here if it's not nullptr. + * @return The frequencies of the NCO (in Hz). + */ std::vector GetNCOFrequencies(TRXDir dir, float_type* phaseOffset = nullptr); + + /*! + * @brief Sets the phases of the NCO (up to 16 values) + * @param dir The direction to which to set the phases. + * @param angles_deg The angles of the NCO to set (in degrees). + * @param count The amount of angles to set (max 16) + * @param frequencyOffset The offset of the NCO (in Hz). + * @return 0-success, other-failure + */ int SetNCOPhases(TRXDir dir, const float_type* angles_deg, uint8_t count, float_type frequencyOffset); + /*! + * @brief Gets the current phases of the NCO (currently returns an empty vector) + * @param dir The direction from which to get the phases. + * @param frequencyOffset The offset of the NCO (in Hz). + * @return The phases of the NCO (in degrees) + */ std::vector GetNCOPhases(TRXDir dir, float_type* frequencyOffset = nullptr); + /*! + * @brief Configures interfaces for desired frequency + * Sets interpolation and decimation, changes MCLK sources and TSP clock dividers accordingly to selected interpolation and decimation + * @param cgen_freq_Hz The clock frequency to set (in Hz) + * @param interpolation The HBI interpolation ratio (actual ratio is pow(2, interpolation + 1), 7 for bypass) + * @param decimation The HBD decimation ratio (actual ratio is pow(2, decimation + 1), 7 for bypass) + * @return 0-success, other-failure + */ int SetInterfaceFrequency(float_type cgen_freq_Hz, const uint8_t interpolation, const uint8_t decimation); + /*! + * @brief Gets the current sample rate of the specified channel. + * @param dir The direction for which to get the sample rate. + * @param ch The channel from which to get the sample rate. + * @return The current sample rate (in Hz) + */ float_type GetSampleRate(TRXDir dir, Channel ch); + + /*! + * @brief Gets the current sample rate of the currently active channel. + * @param dir The direction for which to get the sample rate. + * @return The current sample rate (in Hz) + */ float_type GetSampleRate(TRXDir dir); + /// @brief The sample source for the LML. enum class LMLSampleSource : uint8_t { AI, AQ, @@ -316,26 +732,40 @@ class LIME_API LMS7002M }; /*! - * Set the LML sample positions in the RF to baseband direction. + * @brief Set the LML sample positions in the RF to baseband direction. + * @param s0 + * @param s1 + * @param s2 + * @param s3 */ void ConfigureLML_RF2BB(const LMLSampleSource s0, const LMLSampleSource s1, const LMLSampleSource s2, const LMLSampleSource s3); /*! - * Set the LML sample positions in the baseband to RF direction. + * @brief Set the LML sample positions in the baseband to RF direction. + * @param s0 + * @param s1 + * @param s2 + * @param s3 */ void ConfigureLML_BB2RF(const LMLSampleSource s0, const LMLSampleSource s1, const LMLSampleSource s2, const LMLSampleSource s3); + /*! + * @brief Enables or disables the DC corrector bypass + * @param enable Enables or disables the + * @return 0-success, other-failure + */ int SetRxDCRemoval(const bool enable); /*! * Get the RX DC removal filter enabled. + * @return Whether the DC corrector bypass is enabled or not. */ bool GetRxDCRemoval(void); /*! * Enables/disables TDD mode - * @param enable true - use same pll for Tx and Rx, false - us seperate PLLs - * @return 0 for success for error condition + * @param enable true - use same PLL for Tx and Rx, false - us seperate PLLs + * @return 0-success, other-failure */ int EnableSXTDD(bool enable); @@ -344,7 +774,7 @@ class LIME_API LMS7002M * @param dir true for tx, false for rx * @param I the real adjustment [+1.0, -1.0] * @param Q the imaginary adjustment [+1.0, -1.0] - * @return 0 for success for error condition + * @return 0-success, other-failure */ int SetDCOffset(TRXDir dir, const float_type I, const float_type Q); @@ -362,6 +792,7 @@ class LIME_API LMS7002M * @param phase the phase adjustment [+pi, -pi] * @param gainI the real gain adjustment [+1.0, 0.0] * @param gainQ the imaginary gain adjustment [+1.0, 0.0] + * @return 0 - success, other - failure */ int SetIQBalance(const TRXDir dir, const float_type phase, const float_type gainI, const float_type gainQ); @@ -374,11 +805,90 @@ class LIME_API LMS7002M */ void GetIQBalance(const TRXDir dir, float_type& phase, float_type& gainI, float_type& gainQ); + /*! + * @brief Gets the frequency of the selected clock. + * @param clk_id The enumerator value of the clock to get. + * @return The current frequency of that clock (in Hz). + */ double GetClockFreq(ClockID clk_id); + + /*! + * @brief Sets the frequency of the selected clock. + * @param clk_id The enumerator value of the clock to set. + * @param freq The frequency (in Hz) to set the clock to. + */ void SetClockFreq(ClockID clk_id, double freq); + /*! + * @brief Modifies the defaults of this instance's Register map. + * @param registerValues A vector of address value pairs to modify the defaults to. + */ + void ModifyRegistersDefaults(const std::vector>& registerValues); + + /*! + * @brief Sets whether a local registers cache is being used or not. + * @param enabled Whether to enable the cache or not. + */ + void EnableValuesCache(bool enabled = true); + + /*! + * @brief Returns whether register value caching on the host is enabled or not. + * @return True - cache is being used, false - device values only. + */ + bool IsValuesCacheEnabled() const; + + /*! + * @brief Gets the class to control the MCU on the chip. + * @return A pointer to the class responsible for controlling the MCU. + */ + MCU_BD* GetMCUControls() const; + + /*! + * @brief Gets the of the chip + * @return The current temperature of the chip (in degrees Celsius) + */ + float_type GetTemperature(); + + /// @brief The available log types on the LMS7002M + enum class LogType : uint8_t { LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DATA }; + /*! + * @brief Sets the function to call for any logs to be written to. + * @param callback The function to call on LMS7002M logs + */ + void SetLogCallback(std::function callback); + + /*! + * @brief Batches multiple register writes into least amount of transactions + * @param spiAddr spi register addresses to be written + * @param spiData registers data to be written + * @param cnt number of registers to write + * @param toChip force write to chip + * @return 0-success, other-failure + */ + int SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, uint16_t cnt, bool toChip = false); + + /*! + * @brief Batches multiple register reads into least amount of transactions + * @param spiAddr SPI addresses to read + * @param spiData array for read data + * @param cnt number of registers to read + * @return 0-success, other-failure + */ + int SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_t cnt); + + /// @brief The clock generator change callback type + typedef int (*CGENChangeCallbackType)(void* userData); + + /*! + * @brief Sets the function that gets executed when the CGEN changes. + * @param callback The function to call on CGEN change. + * @param userData The data to pass to the function being called. + */ + void SetOnCGENChangeCallback(CGENChangeCallbackType callback, void* userData = nullptr); + + private: ///enumeration to indicate module registers intervals - enum MemorySection { + enum class MemorySection : uint8_t { LimeLight = 0, EN_DIR, AFE, @@ -411,36 +921,20 @@ class LIME_API LMS7002M RSSI_DC_CALIBRATION, RSSI_PDET_TEMP_CONFIG, RSSI_DC_CONFIG, - MEMORY_SECTIONS_COUNT }; - virtual int SetDefaults(MemorySection module); - void ModifyRegistersDefaults(const std::vector>& registerValues); - - static float_type gVCO_frequency_table[3][2]; - static float_type gCGEN_VCO_frequencies[2]; - void EnableValuesCache(bool enabled = true); - bool IsValuesCacheEnabled(); - MCU_BD* GetMCUControls() const; - void EnableCalibrationByMCU(bool enabled); - float_type GetTemperature(); + /*! + * @brief Sets given module registers to default values + * @return 0-success, other-failure + */ + virtual int SetDefaults(MemorySection module); - enum class LogType : uint8_t { LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DATA }; - void SetLogCallback(std::function callback); LMS7002M_RegistersMap* BackupRegisterMap(void); void RestoreRegisterMap(LMS7002M_RegistersMap* backup); - int SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, uint16_t cnt, bool toChip = false); - int SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_t cnt); - - typedef int (*CGENChangeCallbackType)(void* userData); - void SetOnCGENChangeCallback(CGENChangeCallbackType callback, void* userData = nullptr); - - protected: CGENChangeCallbackType mCallback_onCGENChange; void* mCallback_onCGENChange_userData; - bool mCalibrationByMCU; MCU_BD* mcuControl; bool useCache; LMS7002M_RegistersMap* mRegistersMap; @@ -452,7 +946,9 @@ class LIME_API LMS7002M static const std::vector readOnlyRegisters; - std::array, MEMORY_SECTIONS_COUNT> MemorySectionAddresses; + static const std::map> MemorySectionAddresses; + static const std::array, 3> gVCO_frequency_table; + static const std::array gCGEN_VCO_frequencies; uint32_t GetRSSI(RSSI_measurements* measurements = nullptr); void SetRxDCOFF(int8_t offsetI, int8_t offsetQ); diff --git a/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp b/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp index 60d59b005..527ef1915 100644 --- a/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp +++ b/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp @@ -1847,7 +1847,7 @@ void lms7002_pnlRXTSP_view::OnbtnSetLPFClick(wxCommandEvent& event) { double bw; txtLPFBW->GetValue().ToDouble(&bw); - if (lmsControl->SetGFIRFilter(TRXDir::Rx, mChannel, true, bw * 1e6) != 0) + if (lmsControl->SetGFIRFilter(TRXDir::Rx, mChannel == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB, true, bw * 1e6) != 0) wxMessageBox(_("GFIR configuration failed"), _("Error")); UpdateGUI(); // API changes nco selection diff --git a/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp b/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp index ec65c25b2..fcaaf68dc 100644 --- a/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp +++ b/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp @@ -1649,7 +1649,7 @@ void lms7002_pnlTXTSP_view::OnbtnSetLPFClick(wxCommandEvent& event) double bw; txtLPFBW->GetValue().ToDouble(&bw); - if (lmsControl->SetGFIRFilter(TRXDir::Tx, mChannel, true, bw * 1e6) != 0) + if (lmsControl->SetGFIRFilter(TRXDir::Tx, mChannel == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB, true, bw * 1e6) != 0) wxMessageBox(_("GFIR configuration failed"), _("Error")); UpdateGUI(); // API changes nco selection } diff --git a/src/lms7002m/LMS7002M.cpp b/src/lms7002m/LMS7002M.cpp index 392d49da0..6cec6cdcd 100644 --- a/src/lms7002m/LMS7002M.cpp +++ b/src/lms7002m/LMS7002M.cpp @@ -28,8 +28,10 @@ using namespace lime; -float_type LMS7002M::gVCO_frequency_table[3][2] = { { 3800e6, 5222e6 }, { 4961e6, 6754e6 }, { 6306e6, 7714e6 } }; -float_type LMS7002M::gCGEN_VCO_frequencies[2] = { 1930e6, 2940e6 }; +constexpr std::array, 3> LMS7002M::gVCO_frequency_table{ + { { 3800e6, 5222e6 }, { 4961e6, 6754e6 }, { 6306e6, 7714e6 } } +}; +constexpr std::array LMS7002M::gCGEN_VCO_frequencies{ 1930e6, 2940e6 }; /// Define for parameter enumeration if prefix might be needed extern std::vector> LMS7parameterList; @@ -51,10 +53,57 @@ const std::vector LMS7002M::readOnlyRegisters{ { 0x040F, 0x0000 }, }; +const std::map> LMS7002M::MemorySectionAddresses{ + { LMS7002M::MemorySection::LimeLight, { 0x0020, 0x002F } }, + { LMS7002M::MemorySection::EN_DIR, { 0x0081, 0x0081 } }, + { LMS7002M::MemorySection::AFE, { 0x0082, 0x0082 } }, + { LMS7002M::MemorySection::BIAS, { 0x0084, 0x0084 } }, + { LMS7002M::MemorySection::XBUF, { 0x0085, 0x0085 } }, + { LMS7002M::MemorySection::CGEN, { 0x0086, 0x008C } }, + { LMS7002M::MemorySection::LDO, { 0x0092, 0x00A7 } }, + { LMS7002M::MemorySection::BIST, { 0x00A8, 0x00AC } }, + { LMS7002M::MemorySection::CDS, { 0x00AD, 0x00AE } }, + { LMS7002M::MemorySection::TRF, { 0x0100, 0x0104 } }, + { LMS7002M::MemorySection::TBB, { 0x0105, 0x010B } }, + { LMS7002M::MemorySection::RFE, { 0x010C, 0x0114 } }, + { LMS7002M::MemorySection::RBB, { 0x0115, 0x011A } }, + { LMS7002M::MemorySection::SX, { 0x011C, 0x0124 } }, + { LMS7002M::MemorySection::TRX_GAIN, { 0x0125, 0x0126 } }, + { LMS7002M::MemorySection::TxTSP, { 0x0200, 0x020C } }, + { LMS7002M::MemorySection::TxNCO, { 0x0240, 0x0261 } }, + { LMS7002M::MemorySection::TxGFIR1, { 0x0280, 0x02A7 } }, + { LMS7002M::MemorySection::TxGFIR2, { 0x02C0, 0x02E7 } }, + { LMS7002M::MemorySection::TxGFIR3a, { 0x0300, 0x0327 } }, + { LMS7002M::MemorySection::TxGFIR3b, { 0x0340, 0x0367 } }, + { LMS7002M::MemorySection::TxGFIR3c, { 0x0380, 0x03A7 } }, + { LMS7002M::MemorySection::RxTSP, { 0x0400, 0x040F } }, + { LMS7002M::MemorySection::RxNCO, { 0x0440, 0x0461 } }, + { LMS7002M::MemorySection::RxGFIR1, { 0x0480, 0x04A7 } }, + { LMS7002M::MemorySection::RxGFIR2, { 0x04C0, 0x04E7 } }, + { LMS7002M::MemorySection::RxGFIR3a, { 0x0500, 0x0527 } }, + { LMS7002M::MemorySection::RxGFIR3b, { 0x0540, 0x0567 } }, + { LMS7002M::MemorySection::RxGFIR3c, { 0x0580, 0x05A7 } }, + { LMS7002M::MemorySection::RSSI_DC_CALIBRATION, { 0x05C0, 0x05CC } }, + { LMS7002M::MemorySection::RSSI_PDET_TEMP_CONFIG, { 0x0600, 0x0606 } }, + { LMS7002M::MemorySection::RSSI_DC_CONFIG, { 0x0640, 0x0641 } }, +}; + /** @brief Switches LMS7002M SPI to requested channel and restores previous channel when going out of scope */ class ChannelScope { public: + /** + * @brief Saves the current channel and restores it at scope exit. + * @param chip The chip to use. + * @param useCache Whether to use caching or not. + */ + ChannelScope(LMS7002M* chip, bool useCache = false) + : mChip(chip) + , mStoredValue(chip->GetActiveChannel(!useCache)) + , mNeedsRestore(true) + { + } + /** @brief Convenient constructor when using explicit MAC value. @param chip The chip to use. @@ -63,13 +112,13 @@ class ChannelScope */ ChannelScope(LMS7002M* chip, LMS7002M::Channel mac, bool useCache = false) : mChip(chip) + , mStoredValue(chip->GetActiveChannel(!useCache)) , mNeedsRestore(false) { - mStoredValue = chip->GetActiveChannel(!useCache); if (mStoredValue == mac) return; - chip->SetActiveChannel(mac); + mChip->SetActiveChannel(mac); mNeedsRestore = true; } @@ -188,74 +237,8 @@ LMS7002M::LMS7002M(std::shared_ptr port) , controlPort(port) , _cachedRefClockRate(30.72e6) { - mCalibrationByMCU = true; opt_gain_tbb[0] = -1; opt_gain_tbb[1] = -1; - //memory intervals for registers tests and calibration algorithms - MemorySectionAddresses[LimeLight][0] = 0x0020; - MemorySectionAddresses[LimeLight][1] = 0x002F; - MemorySectionAddresses[EN_DIR][0] = 0x0081; - MemorySectionAddresses[EN_DIR][1] = 0x0081; - MemorySectionAddresses[AFE][0] = 0x0082; - MemorySectionAddresses[AFE][1] = 0x0082; - MemorySectionAddresses[BIAS][0] = 0x0084; - MemorySectionAddresses[BIAS][1] = 0x0084; - MemorySectionAddresses[XBUF][0] = 0x0085; - MemorySectionAddresses[XBUF][1] = 0x0085; - MemorySectionAddresses[CGEN][0] = 0x0086; - MemorySectionAddresses[CGEN][1] = 0x008C; - MemorySectionAddresses[LDO][0] = 0x0092; - MemorySectionAddresses[LDO][1] = 0x00A7; - MemorySectionAddresses[BIST][0] = 0x00A8; - MemorySectionAddresses[BIST][1] = 0x00AC; - MemorySectionAddresses[CDS][0] = 0x00AD; - MemorySectionAddresses[CDS][1] = 0x00AE; - MemorySectionAddresses[TRF][0] = 0x0100; - MemorySectionAddresses[TRF][1] = 0x0104; - MemorySectionAddresses[TBB][0] = 0x0105; - MemorySectionAddresses[TBB][1] = 0x010B; - MemorySectionAddresses[RFE][0] = 0x010C; - MemorySectionAddresses[RFE][1] = 0x0114; - MemorySectionAddresses[RBB][0] = 0x0115; - MemorySectionAddresses[RBB][1] = 0x011A; - MemorySectionAddresses[SX][0] = 0x011C; - MemorySectionAddresses[SX][1] = 0x0124; - MemorySectionAddresses[TRX_GAIN][0] = 0x0125; - MemorySectionAddresses[TRX_GAIN][1] = 0x0126; - MemorySectionAddresses[TxTSP][0] = 0x0200; - MemorySectionAddresses[TxTSP][1] = 0x020C; - MemorySectionAddresses[TxNCO][0] = 0x0240; - MemorySectionAddresses[TxNCO][1] = 0x0261; - MemorySectionAddresses[TxGFIR1][0] = 0x0280; - MemorySectionAddresses[TxGFIR1][1] = 0x02A7; - MemorySectionAddresses[TxGFIR2][0] = 0x02C0; - MemorySectionAddresses[TxGFIR2][1] = 0x02E7; - MemorySectionAddresses[TxGFIR3a][0] = 0x0300; - MemorySectionAddresses[TxGFIR3a][1] = 0x0327; - MemorySectionAddresses[TxGFIR3b][0] = 0x0340; - MemorySectionAddresses[TxGFIR3b][1] = 0x0367; - MemorySectionAddresses[TxGFIR3c][0] = 0x0380; - MemorySectionAddresses[TxGFIR3c][1] = 0x03A7; - MemorySectionAddresses[RxTSP][0] = 0x0400; - MemorySectionAddresses[RxTSP][1] = 0x040F; - MemorySectionAddresses[RxNCO][0] = 0x0440; - MemorySectionAddresses[RxNCO][1] = 0x0461; - MemorySectionAddresses[RxGFIR1][0] = 0x0480; - MemorySectionAddresses[RxGFIR1][1] = 0x04A7; - MemorySectionAddresses[RxGFIR2][0] = 0x04C0; - MemorySectionAddresses[RxGFIR2][1] = 0x04E7; - MemorySectionAddresses[RxGFIR3a][0] = 0x0500; - MemorySectionAddresses[RxGFIR3a][1] = 0x0527; - MemorySectionAddresses[RxGFIR3b][0] = 0x0540; - MemorySectionAddresses[RxGFIR3b][1] = 0x0567; - MemorySectionAddresses[RxGFIR3c][0] = 0x0580; - MemorySectionAddresses[RxGFIR3c][1] = 0x05A7; - MemorySectionAddresses[RSSI_DC_CALIBRATION][0] = 0x05C0; - MemorySectionAddresses[RSSI_DC_CALIBRATION][1] = 0x05CC; - MemorySectionAddresses[RSSI_PDET_TEMP_CONFIG][0] = 0x0600; - MemorySectionAddresses[RSSI_PDET_TEMP_CONFIG][1] = 0x0606; - MemorySectionAddresses[RSSI_DC_CONFIG][0] = 0x0640; - MemorySectionAddresses[RSSI_DC_CONFIG][1] = 0x0641; mRegistersMap->InitializeDefaultValues(LMS7parameterList); mcuControl = new MCU_BD(); @@ -288,10 +271,9 @@ size_t LMS7002M::GetActiveChannelIndex(bool fromChip) int LMS7002M::EnableChannel(TRXDir dir, const uint8_t channel, const bool enable) { - ChannelScope scope(this, channel); + ChannelScope scope(this, channel, false); - const Channel ch = this->GetActiveChannel(); - this->SetActiveChannel(channel > 0 ? Channel::ChB : Channel::ChA); + const Channel ch = channel > 0 ? Channel::ChB : Channel::ChA; const bool isTx = dir == TRXDir::Tx; //--- LML --- @@ -427,9 +409,6 @@ int LMS7002M::EnableChannel(TRXDir dir, const uint8_t channel, const bool enable return 0; } -/** @brief Sends reset signal to chip, after reset enables B channel controls - @return 0-success, other-failure -*/ int LMS7002M::ResetChip() { int status = 0; @@ -465,12 +444,12 @@ int LMS7002M::ResetChip() int LMS7002M::SoftReset() { - auto reg_0x0020 = this->SPI_read(0x0020, true); - auto reg_0x002E = this->SPI_read(0x002E, true); - this->SPI_write(0x0020, 0x0); - this->SPI_write(0x0020, reg_0x0020); - this->SPI_write(0x002E, reg_0x002E); //must write, enables/disabled MIMO channel B - return 0; + auto reg_0x0020 = SPI_read(0x0020, true); + auto reg_0x002E = SPI_read(0x002E, true); + int status = SPI_write(0x0020, 0x0); + status |= SPI_write(0x0020, reg_0x0020); + status |= SPI_write(0x002E, reg_0x002E); //must write, enables/disabled MIMO channel B + return status; } int LMS7002M::LoadConfigLegacyFile(const std::string& filename) @@ -485,7 +464,6 @@ int LMS7002M::LoadConfigLegacyFile(const std::string& filename) uint16_t addr = 0; uint16_t value = 0; - Channel ch = this->GetActiveChannel(); //remember used channel int status; typedef INI ini_t; ini_t parser(filename, true); @@ -507,6 +485,8 @@ int LMS7002M::LoadConfigLegacyFile(const std::string& filename) std::vector dataToWrite; if (fileVersion == 1) { + ChannelScope scope(this); + if (parser.select("Reference clocks")) { this->SetReferenceClk_SX(TRXDir::Rx, parser.get("SXR reference frequency MHz", 30.72) * 1e6); @@ -646,17 +626,11 @@ int LMS7002M::LoadConfigLegacyFile(const std::string& filename) } } } - this->SetActiveChannel(ch); return 0; } return ReportError(EINVAL, "LoadConfigLegacyFile(%s) - invalid format", filename.c_str()); } -/** @brief Reads configuration file and uploads registers to chip - @param filename Configuration source file - @param tuneDynamicValues Whether to tune the dynamic values or not - @return 0 - success, other - failure -*/ int LMS7002M::LoadConfig(const std::string& filename, bool tuneDynamicValues) { std::ifstream f(filename); @@ -669,7 +643,6 @@ int LMS7002M::LoadConfig(const std::string& filename, bool tuneDynamicValues) uint16_t addr = 0; uint16_t value = 0; - Channel ch = this->GetActiveChannel(); //remember used channel int status; typedef INI ini_t; @@ -697,6 +670,7 @@ int LMS7002M::LoadConfig(const std::string& filename, bool tuneDynamicValues) if (fileVersion == 1) { + ChannelScope scope(this); if (parser.select("lms7002_registers_a") == true) { ini_t::sectionsit_t section = parser.sections.find("lms7002_registers_a"); @@ -755,14 +729,13 @@ int LMS7002M::LoadConfig(const std::string& filename, bool tuneDynamicValues) if (status != 0 && controlPort != nullptr) return status; } - this->SetActiveChannel(ch); parser.select("reference_clocks"); this->SetReferenceClk_SX(TRXDir::Rx, parser.get("sxr_ref_clk_mhz", 30.72) * 1e6); this->SetReferenceClk_SX(TRXDir::Tx, parser.get("sxt_ref_clk_mhz", 30.72) * 1e6); } - ResetLogicregisters(); + ResetLogicRegisters(); if (tuneDynamicValues) { @@ -783,7 +756,7 @@ int LMS7002M::LoadConfig(const std::string& filename, bool tuneDynamicValues) return 0; } -int LMS7002M::ResetLogicregisters() +int LMS7002M::ResetLogicRegisters() { const uint16_t x0020_value = SPI_read(0x0020); //reset logic registers const uint16_t addr[] = { 0x0020, 0x0020 }; @@ -793,10 +766,6 @@ int LMS7002M::ResetLogicregisters() return SPI_write_batch(addr, values, 2); } -/** @brief Reads all registers from chip and saves to file - @param filename destination filename - @return 0-success, other failure -*/ int LMS7002M::SaveConfig(const std::string& filename) { std::ofstream fout; @@ -808,12 +777,13 @@ int LMS7002M::SaveConfig(const std::string& filename) char addr[80]; char value[80]; - Channel ch = this->GetActiveChannel(); + ChannelScope scope(this); std::vector addrToRead; - for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) + for (const auto& memorySectionPair : MemorySectionAddresses) + for (uint16_t addr = memorySectionPair.second[0]; addr <= memorySectionPair.second[1]; ++addr) addrToRead.push_back(addr); + std::vector dataReceived; dataReceived.resize(addrToRead.size(), 0); @@ -839,9 +809,9 @@ int LMS7002M::SaveConfig(const std::string& filename) fout << "[lms7002_registers_b]" << std::endl; addrToRead.clear(); //add only B channel addresses - for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - if (i != RSSI_DC_CALIBRATION) - for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) + for (const auto& memorySectionPair : MemorySectionAddresses) + if (memorySectionPair.first != MemorySection::RSSI_DC_CALIBRATION) + for (uint16_t addr = memorySectionPair.second[0]; addr <= memorySectionPair.second[1]; ++addr) if (addr >= 0x0100) addrToRead.push_back(addr); @@ -854,8 +824,6 @@ int LMS7002M::SaveConfig(const std::string& filename) fout << addr << "=" << value << std::endl; } - this->SetActiveChannel(ch); //retore previously used channel - fout << "[reference_clocks]" << std::endl; fout << "sxt_ref_clk_mhz=" << this->GetReferenceClk_SX(TRXDir::Tx) / 1e6 << std::endl; fout << "sxr_ref_clk_mhz=" << this->GetReferenceClk_SX(TRXDir::Rx) / 1e6 << std::endl; @@ -1176,7 +1144,7 @@ int LMS7002M::SetTBBIAMP_dB(const float_type gain, const Channel channel) int ind = this->GetActiveChannelIndex() % 2; if (opt_gain_tbb[ind] <= 0) { - if (CalibrateTxGain(0, nullptr) != 0) //set optimal BB gain + if (CalibrateTxGain() != 0) //set optimal BB gain return -1; if (std::fabs(gain) < 0.2) // optimal gain = ~0dB return 0; @@ -1197,7 +1165,7 @@ float_type LMS7002M::GetTBBIAMP_dB(const Channel channel) if (opt_gain_tbb[ind] <= 0) { - if (CalibrateTxGain(0, nullptr) != 0) + if (CalibrateTxGain() != 0) return 0.0; Modify_SPI_Reg_bits(LMS7param(CG_IAMP_TBB), g_current, true); //restore } @@ -1283,7 +1251,7 @@ int LMS7002M::GetBandTRF(void) int LMS7002M::SetPath(TRXDir direction, uint8_t channel, uint8_t path) { - ChannelScope scope(this, channel); + ChannelScope scope(this, channel, false); if (direction == TRXDir::Tx) { @@ -1299,9 +1267,6 @@ int LMS7002M::SetReferenceClk_SX(TRXDir dir, float_type freq_Hz) return 0; } -/** @brief Returns reference clock in Hz used for SXT or SXR - @param dir transmitter or receiver selection -*/ float_type LMS7002M::GetReferenceClk_SX(TRXDir dir) { return _cachedRefClockRate; @@ -1309,7 +1274,7 @@ float_type LMS7002M::GetReferenceClk_SX(TRXDir dir) int LMS7002M::SetNCOFrequencies(TRXDir dir, const float_type* freq_Hz, uint8_t count, float_type phaseOffset) { - for (unsigned i = 0; i < 16 && i < count; i++) + for (uint8_t i = 0; i < 16 && i < count; i++) { if (SetNCOFrequency(dir, i, freq_Hz[i])) return -1; @@ -1330,9 +1295,6 @@ std::vector LMS7002M::GetNCOFrequencies(TRXDir dir, float_type* phas return ncos; } -/** @return Current CLKGEN frequency in Hz - Returned frequency depends on reference clock used for Receiver -*/ float_type LMS7002M::GetFrequencyCGEN() { float_type dMul = @@ -1342,10 +1304,6 @@ float_type LMS7002M::GetFrequencyCGEN() return dMul * (((gINT >> 4) + 1 + gFRAC / 1048576.0)); } -/** @brief Returns TSP reference frequency - @param dir TxTSP or RxTSP selection - @return TSP reference frequency in Hz -*/ float_type LMS7002M::GetReferenceClk_TSP(TRXDir dir) { float_type cgenFreq = GetFrequencyCGEN(); @@ -1356,12 +1314,6 @@ float_type LMS7002M::GetReferenceClk_TSP(TRXDir dir) return dir == TRXDir::Tx ? cgenFreq : clklfreq / 4.0; } -/** @brief Sets CLKGEN frequency, calculations use receiver'r reference clock - @param freq_Hz desired frequency in Hz - @param retainNCOfrequencies recalculate NCO coefficients to keep currently set frequencies - @param output if not null outputs calculated CGEN parameters - @return 0-succes, other-cannot deliver desired frequency -*/ int LMS7002M::SetFrequencyCGEN(const float_type freq_Hz, const bool retainNCOfrequencies, CGEN_details* output) { if (freq_Hz > CGEN_MAX_FREQ) @@ -1460,9 +1412,6 @@ bool LMS7002M::GetSXLocked(TRXDir dir) return (Get_SPI_Reg_bits(LMS7param(VCO_CMPHO).address, 13, 12, true) & 0x3) == 2; } -/** @brief Performs VCO tuning operations for CLKGEN - @return 0-success, other-failure -*/ int LMS7002M::TuneCGENVCO() { #ifndef NDEBUG @@ -1507,10 +1456,6 @@ int LMS7002M::TuneCGENVCO() return -1; } -/** @brief Performs VCO tuning operations for CLKGEN, SXR, SXT modules - @param module module selection for tuning 0-cgen, 1-SXR, 2-SXT - @return 0-success, other-failure -*/ int LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT { if (module == VCO_Module::VCO_CGEN) @@ -1529,7 +1474,7 @@ int LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT uint8_t lsb; //SWC lsb index uint8_t msb; //SWC msb index - Channel ch = this->GetActiveChannel(); //remember used channel + ChannelScope scope(this); if (module != VCO_Module::VCO_CGEN) //set addresses to SX module { @@ -1563,7 +1508,6 @@ int LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); if (cmphl == 3) //VCO too high { - this->SetActiveChannel(ch); //restore previously used channel lime::debug("TuneVCO(%s) - attempted VCO too high", moduleName); return -1; } @@ -1572,7 +1516,6 @@ int LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); if (cmphl == 0) //VCO too low { - this->SetActiveChannel(ch); //restore previously used channel lime::debug("TuneVCO(%s) - attempted VCO too low", moduleName); return -1; } @@ -1672,7 +1615,6 @@ int LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT } std::this_thread::sleep_for(settlingTime); cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12, true); - this->SetActiveChannel(ch); //restore previously used channel if (cmphl == 2) { lime::debug("TuneVCO(%s) - confirmed lock with final csw=%i, cmphl=%i", moduleName, finalCSW, cmphl); @@ -1682,45 +1624,21 @@ int LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT return -1; } -/** @brief Returns given parameter value from chip register - @param param LMS7002M control parameter - @param fromChip read directly from chip - @return parameter value -*/ uint16_t LMS7002M::Get_SPI_Reg_bits(const LMS7Parameter& param, bool fromChip) { return Get_SPI_Reg_bits(param.address, param.msb, param.lsb, fromChip); } -/** @brief Returns given parameter value from chip register - @param address register address - @param msb most significant bit index - @param lsb least significant bit index - @param fromChip read directly from chip - @return register bits from selected interval, shifted to right by lsb bits -*/ uint16_t LMS7002M::Get_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, bool fromChip) { return (SPI_read(address, fromChip) & (~(~0u << (msb + 1)))) >> lsb; //shift bits to LSB } -/** @brief Change given parameter value - @param param LMS7002M control parameter - @param fromChip read initial value directly from chip - @param value new parameter value -*/ int LMS7002M::Modify_SPI_Reg_bits(const LMS7Parameter& param, const uint16_t value, bool fromChip) { return Modify_SPI_Reg_bits(param.address, param.msb, param.lsb, value, fromChip); } -/** @brief Change given parameter value - @param address register address - @param msb Most significant bit index - @param lsb Least significant bit index - @param value new bits value, the value is shifted left by lsb bits - @param fromChip read initial value directly from chip -*/ int LMS7002M::Modify_SPI_Reg_bits(const uint16_t address, const uint8_t msb, const uint8_t lsb, const uint16_t value, bool fromChip) { uint16_t spiDataReg = SPI_read(address, fromChip); //read current SPI reg data @@ -1757,9 +1675,6 @@ int LMS7002M::Modify_SPI_Reg_mask(const uint16_t* addr, const uint16_t* masks, c return status; } -/** @brief Get parameter by name - @param name parameter name -*/ const LMS7Parameter& LMS7002M::GetParam(const std::string& name) { for (const LMS7Parameter& parameter : LMS7parameterList) @@ -1773,12 +1688,6 @@ const LMS7Parameter& LMS7002M::GetParam(const std::string& name) throw std::logic_error("Parameter " + name + " not found"); } -/** @brief Sets SX frequency - @param dir Rx/Tx module selection - @param freq_Hz desired frequency in Hz - @param output if not null outputs intermediate calculation values - @return 0-success, other-cannot deliver requested frequency -*/ int LMS7002M::SetFrequencySX(TRXDir dir, float_type freq_Hz, SX_details* output) { static std::map tuning_cache_sel_vco; @@ -1822,7 +1731,7 @@ int LMS7002M::SetFrequencySX(TRXDir dir, float_type freq_Hz, SX_details* output) (uint32_t)(VCOfreq / (refClk_Hz * (1 + (VCOfreq > m_dThrF))))) * 1048576); - Channel ch = this->GetActiveChannel(); + ChannelScope scope(this); this->SetActiveChannel(dir == TRXDir::Tx ? Channel::ChSXT : Channel::ChSXR); Modify_SPI_Reg_bits(LMS7param(EN_INTONLY_SDM), 0); Modify_SPI_Reg_bits(LMS7param(INT_SDM), integerPart); //INT_SDM @@ -1868,7 +1777,6 @@ int LMS7002M::SetFrequencySX(TRXDir dir, float_type freq_Hz, SX_details* output) if (cmphl == 2) { lime::info("Fast Tune success; vco=%d value=%d", tuning_cache_sel_vco[freq_Hz], tuning_cache_csw_value[freq_Hz]); - this->SetActiveChannel(ch); //restore used channel if (output) { output->success = true; @@ -1941,19 +1849,11 @@ int LMS7002M::SetFrequencySX(TRXDir dir, float_type freq_Hz, SX_details* output) tuning_cache_csw_value[freq_Hz] = csw_value; } - this->SetActiveChannel(ch); //restore used channel - if (canDeliverFrequency == false) return ReportError("SetFrequencySX%s(%g MHz) - cannot deliver frequency", dir == TRXDir::Tx ? "T" : "R", freq_Hz / 1e6); return 0; } -/** @brief Sets SX frequency with Reference clock spur cancelation - @param dir Rx/Tx module selection - @param freq_Hz desired frequency in Hz - @param BW BW - @return 0-success, other-cannot deliver requested frequency -*/ int LMS7002M::SetFrequencySXWithSpurCancelation(TRXDir dir, float_type freq_Hz, float_type BW) { const float BWOffset = 2e6; @@ -2021,9 +1921,6 @@ int LMS7002M::SetFrequencySXWithSpurCancelation(TRXDir dir, float_type freq_Hz, return 0; } -/** @brief Returns currently set SXR/SXT frequency - @return SX frequency Hz -*/ float_type LMS7002M::GetFrequencySX(TRXDir dir) { ChannelScope(this, dir == TRXDir::Tx ? Channel::ChSXT : Channel::ChSXR); @@ -2039,12 +1936,6 @@ float_type LMS7002M::GetFrequencySX(TRXDir dir) return dMul; } -/** @brief Sets chosen NCO's frequency - @param dir transmitter or receiver selection - @param index NCO index from 0 to 15 - @param freq_Hz desired NCO frequency - @return 0-success, other-failure -*/ int LMS7002M::SetNCOFrequency(TRXDir dir, uint8_t index, float_type freq_Hz) { if (index > 15) @@ -2063,12 +1954,6 @@ int LMS7002M::SetNCOFrequency(TRXDir dir, uint8_t index, float_type freq_Hz) return 0; } -/** @brief Returns chosen NCO's frequency in Hz - @param dir transmitter or receiver selection - @param index NCO index from 0 to 15 - @param fromChip read frequency directly from chip or local registers - @return NCO frequency in Hz -*/ float_type LMS7002M::GetNCOFrequency(TRXDir dir, uint8_t index, bool fromChip) { if (index > 15) @@ -2081,11 +1966,6 @@ float_type LMS7002M::GetNCOFrequency(TRXDir dir, uint8_t index, bool fromChip) return refClk_Hz * (fcw / 4294967296.0); } -/** @brief Sets chosen NCO phase offset angle when memory table MODE is 0 -@param dir transmitter or receiver selection -@param angle_deg phase offset angle in degrees -@return 0-success, other-failure -*/ int LMS7002M::SetNCOPhaseOffsetForMode0(TRXDir dir, float_type angle_deg) { uint16_t addr = dir == TRXDir::Tx ? 0x0241 : 0x0441; @@ -2094,12 +1974,6 @@ int LMS7002M::SetNCOPhaseOffsetForMode0(TRXDir dir, float_type angle_deg) return 0; } -/** @brief Sets chosen NCO's phase offset angle - @param dir transmitter or receiver selection - @param index PHO index from 0 to 15 - @param angle_deg phase offset angle in degrees - @return 0-success, other-failure -*/ int LMS7002M::SetNCOPhaseOffset(TRXDir dir, uint8_t index, float_type angle_deg) { if (index > 15) @@ -2117,7 +1991,7 @@ int LMS7002M::SetNCOPhases(TRXDir dir, const float_type* angles_deg, uint8_t cou if (angles_deg != nullptr) { - for (unsigned i = 0; i < 16; i++) + for (uint8_t i = 0; i < 16 && i < count; i++) if (SetNCOPhaseOffset(dir, i, angles_deg[i]) != 0) return -1; if (Modify_SPI_Reg_bits(dir == TRXDir::Tx ? LMS7_SEL_TX : LMS7_SEL_RX, 0) != 0) @@ -2132,11 +2006,6 @@ std::vector LMS7002M::GetNCOPhases(TRXDir dir, float_type* frequency return angles_deg; } -/** @brief Returns chosen NCO's phase offset angle in radians - @param dir transmitter or receiver selection - @param index PHO index from 0 to 15 - @return phase offset angle in degrees -*/ float_type LMS7002M::GetNCOPhaseOffset_Deg(TRXDir dir, uint8_t index) { if (index > 15) @@ -2147,15 +2016,6 @@ float_type LMS7002M::GetNCOPhaseOffset_Deg(TRXDir dir, uint8_t index) return angle; } -/** @brief Uploads given FIR coefficients to chip - @param dir Transmitter or receiver selection - @param gfirIndex GIR index from 0 to 2 - @param coef array of coefficients (normalized from -1 to 1) - @param coefCount number of coefficients - @return 0-success, other-failure - - This function does not change GFIR*_L or GFIR*_N parameters, they have to be set manually -*/ int LMS7002M::SetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, const float_type* coef, uint8_t coefCount) { if (gfirIndex > 2) @@ -2213,13 +2073,6 @@ int LMS7002M::SetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, const float_typ return SPI_write_batch(addrs, (const uint16_t*)words, actualCoefCount, true); } -/** @brief Returns currently loaded FIR coefficients. - @param dir Transmitter or receiver selection. - @param gfirIndex GFIR index from 0 to 2. - @param coef Array of returned coefficients (normalized from -1 to 1) - @param coefCount Number of coefficients to read. - @return 0-success, other-failure. -*/ int LMS7002M::GetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, float_type* coef, uint8_t coefCount) { int status = -1; @@ -2268,12 +2121,6 @@ int LMS7002M::GetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, float_type* coe return status; } -/** @brief Write given data value to whole register - @param address SPI address - @param data new register value - @param toChip whether we're writing to the chip or not - @return 0-succes, other-failure -*/ int LMS7002M::SPI_write(uint16_t address, uint16_t data, bool toChip) { if (address == 0x0640 || address == 0x0641) @@ -2292,23 +2139,18 @@ int LMS7002M::SPI_write(uint16_t address, uint16_t data, bool toChip) return this->SPI_write_batch(&address, &data, 1, toChip); } -/** @brief Reads whole register value from given address - @param address SPI address - @param status operation status(optional) - @param fromChip read value directly from chip - @return register value -*/ uint16_t LMS7002M::SPI_read(uint16_t address, bool fromChip, int* status) { fromChip |= !useCache; //registers containing read only registers, which values can change - static const std::unordered_set volatileRegs = { 0, - 1, - 2, - 3, - 4, - 5, - 6, + static const std::unordered_set volatileRegs = { + 0x0000, + 0x0001, + 0x0002, + 0x0003, + 0x0004, + 0x0005, + 0x0006, 0x002F, 0x008C, 0x00A8, @@ -2329,7 +2171,8 @@ uint16_t LMS7002M::SPI_read(uint16_t address, bool fromChip, int* status) 0x05C7, 0x05C8, 0x05C9, - 0x05CA }; + 0x05CA, + }; if (volatileRegs.find(address) != volatileRegs.end()) fromChip = true; @@ -2368,13 +2211,6 @@ uint16_t LMS7002M::SPI_read(uint16_t address, bool fromChip, int* status) return 0; } -/** @brief Batches multiple register writes into least amount of transactions - @param spiAddr spi register addresses to be written - @param spiData registers data to be written - @param cnt number of registers to write - @param toChip force write to chip - @return 0-success, other-failure -*/ int LMS7002M::SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, uint16_t cnt, bool toChip) { toChip |= !useCache; @@ -2421,12 +2257,6 @@ int LMS7002M::SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, return 0; } -/** @brief Batches multiple register reads into least amount of transactions - @param spiAddr SPI addresses to read - @param spiData array for read data - @param cnt number of registers to read - @return 0-success, other-failure -*/ int LMS7002M::SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_t cnt) { if (!controlPort) @@ -2463,9 +2293,6 @@ int LMS7002M::SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_ return 0; } -/** @brief Performs registers test by writing known data and confirming readback data - @return 0-registers test passed, other-failure -*/ int LMS7002M::RegistersTest(const std::string& fileName) { char chex[16]; @@ -2476,12 +2303,12 @@ int LMS7002M::RegistersTest(const std::string& fileName) } int status; - Channel ch = this->GetActiveChannel(); + ChannelScope scope(this); //backup both channel data for restoration after test std::vector ch1Addresses; - for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) + for (const auto& memorySectionPair : MemorySectionAddresses) + for (uint16_t addr = memorySectionPair.second[0]; addr <= memorySectionPair.second[1]; ++addr) ch1Addresses.push_back(addr); std::vector ch1Data; ch1Data.resize(ch1Addresses.size(), 0); @@ -2493,8 +2320,8 @@ int LMS7002M::RegistersTest(const std::string& fileName) return status; std::vector ch2Addresses; - for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i) - for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr) + for (const auto& memorySectionPair : MemorySectionAddresses) + for (uint16_t addr = memorySectionPair.second[0]; addr <= memorySectionPair.second[1]; ++addr) if (addr >= 0x0100) ch2Addresses.push_back(addr); std::vector ch2Data; @@ -2515,34 +2342,37 @@ int LMS7002M::RegistersTest(const std::string& fileName) std::stringstream ss; //check single channel memory sections - std::vector modulesToCheck = { AFE, - BIAS, - XBUF, - CGEN, - BIST, - CDS, - TRF, - TBB, - RFE, - RBB, - SX, - TxTSP, - TxNCO, - TxGFIR1, - TxGFIR2, - TxGFIR3a, - TxGFIR3b, - TxGFIR3c, - RxTSP, - RxNCO, - RxGFIR1, - RxGFIR2, - RxGFIR3a, - RxGFIR3b, - RxGFIR3c, - LimeLight, - LDO }; - const std::string moduleNames[] = { "AFE", + std::vector modulesToCheck = { + MemorySection::AFE, + MemorySection::BIAS, + MemorySection::XBUF, + MemorySection::CGEN, + MemorySection::BIST, + MemorySection::CDS, + MemorySection::TRF, + MemorySection::TBB, + MemorySection::RFE, + MemorySection::RBB, + MemorySection::SX, + MemorySection::TxTSP, + MemorySection::TxNCO, + MemorySection::TxGFIR1, + MemorySection::TxGFIR2, + MemorySection::TxGFIR3a, + MemorySection::TxGFIR3b, + MemorySection::TxGFIR3c, + MemorySection::RxTSP, + MemorySection::RxNCO, + MemorySection::RxGFIR1, + MemorySection::RxGFIR2, + MemorySection::RxGFIR3a, + MemorySection::RxGFIR3b, + MemorySection::RxGFIR3c, + MemorySection::LimeLight, + MemorySection::LDO, + }; + const std::string moduleNames[] = { + "AFE", "BIAS", "XBUF", "CGEN", @@ -2568,7 +2398,8 @@ int LMS7002M::RegistersTest(const std::string& fileName) "RxGFIR3b", "RxGFIR3c", "LimeLight", - "LDO" }; + "LDO", + }; const uint16_t patterns[] = { 0xAAAA, 0x5555 }; const uint8_t patternsCount = 2; @@ -2578,8 +2409,8 @@ int LMS7002M::RegistersTest(const std::string& fileName) for (unsigned i = 0; i < modulesToCheck.size(); ++i) { bool moduleTestsSuccess = true; - uint16_t startAddr = MemorySectionAddresses[modulesToCheck[i]][0]; - uint16_t endAddr = MemorySectionAddresses[modulesToCheck[i]][1]; + uint16_t startAddr = MemorySectionAddresses.at(modulesToCheck[i]).at(0); + uint16_t endAddr = MemorySectionAddresses.at(modulesToCheck[i]).at(1); uint8_t channelCount = startAddr >= 0x0100 ? 2 : 1; for (int cc = 1; cc <= channelCount; ++cc) { @@ -2604,7 +2435,6 @@ int LMS7002M::RegistersTest(const std::string& fileName) SPI_write_batch(&ch1Addresses[0], &ch1Data[0], ch1Addresses.size(), true); this->SetActiveChannel(Channel::ChB); SPI_write_batch(&ch2Addresses[0], &ch2Data[0], ch2Addresses.size(), true); - this->SetActiveChannel(ch); if (!fileName.empty()) { @@ -2710,15 +2540,12 @@ void LMS7002M::SetRxDCOFF(int8_t offsetI, int8_t offsetQ) SPI_write(0x010E, valToSend); } -/** @brief Sets given module registers to default values - @return 0-success, other-failure -*/ int LMS7002M::SetDefaults(MemorySection module) { int status = 0; std::vector addrs; std::vector values; - for (uint32_t address = MemorySectionAddresses[module][0]; address <= MemorySectionAddresses[module][1]; ++address) + for (uint16_t address = MemorySectionAddresses.at(module).at(0); address <= MemorySectionAddresses.at(module).at(1); ++address) { addrs.push_back(address); values.push_back(mRegistersMap->GetDefaultValue(address)); @@ -2733,15 +2560,12 @@ void LMS7002M::ModifyRegistersDefaults(const std::vectorSetDefaultValue(addrValuePair.first, addrValuePair.second); } -/** @brief Reads all chip configuration and checks if it matches with local registers copy -*/ bool LMS7002M::IsSynced() { if (!controlPort) return false; - bool isSynced = true; - Channel ch = this->GetActiveChannel(); + ChannelScope scope(this); std::vector addrToRead = mRegistersMap->GetUsedAddresses(0); std::vector dataReceived; @@ -2778,8 +2602,7 @@ bool LMS7002M::IsSynced() if (dataReceived[i] != regValue) { lime::debug("Addr: 0x%04X gui: 0x%04X chip: 0x%04X", addrToRead[i], regValue, dataReceived[i]); - isSynced = false; - goto isSyncedEnding; + return false; } } @@ -2815,18 +2638,13 @@ bool LMS7002M::IsSynced() if (dataReceived[i] != regValue) { lime::debug("Addr: 0x%04X gui: 0x%04X chip: 0x%04X", addrToRead[i], regValue, dataReceived[i]); - isSynced = false; - goto isSyncedEnding; + return false; } } -isSyncedEnding: - this->SetActiveChannel(ch); //restore previously used channel - return isSynced; -} -/** @brief Writes all registers from host to chip + return true; +} -*/ int LMS7002M::UploadAll() { if (!controlPort) @@ -2835,7 +2653,7 @@ int LMS7002M::UploadAll() return -1; } - Channel ch = this->GetActiveChannel(); //remember used channel + ChannelScope scope(this); int status; @@ -2872,14 +2690,10 @@ int LMS7002M::UploadAll() status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size(), true); if (status != 0) return status; - this->SetActiveChannel(ch); //restore last used channel return 0; } -/** @brief Reads all registers from the chip to host - -*/ int LMS7002M::DownloadAll() { if (!controlPort) @@ -2888,7 +2702,7 @@ int LMS7002M::DownloadAll() return -1; } int status; - Channel ch = this->GetActiveChannel(false); + ChannelScope scope(this, true); std::vector addrToRead = mRegistersMap->GetUsedAddresses(0); std::vector dataReceived; @@ -2914,15 +2728,9 @@ int LMS7002M::DownloadAll() for (uint16_t i = 0; i < addrToRead.size(); ++i) mRegistersMap->SetValue(1, addrToRead[i], dataReceived[i]); - this->SetActiveChannel(ch); //retore previously used channel - return 0; } -/** @brief Configures interfaces for desired frequency - @return 0-success, other-failure - Sets interpolation and decimation, changes MCLK sources and TSP clock dividers accordingly to selected interpolation and decimation -*/ int LMS7002M::SetInterfaceFrequency(float_type cgen_freq_Hz, const uint8_t interpolation, const uint8_t decimation) { int status = 0; @@ -2999,46 +2807,48 @@ void LMS7002M::ConfigureLML_RF2BB( const LMLSampleSource s0, const LMLSampleSource s1, const LMLSampleSource s2, const LMLSampleSource s3) { //map a sample source to a position - std::map m; - m[LMLSampleSource::AI] = 1; - m[LMLSampleSource::AQ] = 0; - m[LMLSampleSource::BI] = 3; - m[LMLSampleSource::BQ] = 2; + const std::map m{ + { LMLSampleSource::AI, 1 }, + { LMLSampleSource::AQ, 0 }, + { LMLSampleSource::BI, 3 }, + { LMLSampleSource::BQ, 2 }, + }; //load the same config on both LMLs //only one will get used based on direction - this->Modify_SPI_Reg_bits(LMS7param(LML1_S3S), m[s3]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_S2S), m[s2]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_S1S), m[s1]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_S0S), m[s0]); + this->Modify_SPI_Reg_bits(LMS7param(LML1_S3S), m.at(s3)); + this->Modify_SPI_Reg_bits(LMS7param(LML1_S2S), m.at(s2)); + this->Modify_SPI_Reg_bits(LMS7param(LML1_S1S), m.at(s1)); + this->Modify_SPI_Reg_bits(LMS7param(LML1_S0S), m.at(s0)); - this->Modify_SPI_Reg_bits(LMS7param(LML2_S3S), m[s3]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_S2S), m[s2]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_S1S), m[s1]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_S0S), m[s0]); + this->Modify_SPI_Reg_bits(LMS7param(LML2_S3S), m.at(s3)); + this->Modify_SPI_Reg_bits(LMS7param(LML2_S2S), m.at(s2)); + this->Modify_SPI_Reg_bits(LMS7param(LML2_S1S), m.at(s1)); + this->Modify_SPI_Reg_bits(LMS7param(LML2_S0S), m.at(s0)); } void LMS7002M::ConfigureLML_BB2RF( const LMLSampleSource s0, const LMLSampleSource s1, const LMLSampleSource s2, const LMLSampleSource s3) { //map a sample source to a position - std::map m; - m[s3] = 2; - m[s2] = 3; - m[s0] = 1; - m[s1] = 0; + const std::map m{ + { s3, 2 }, + { s2, 3 }, + { s0, 1 }, + { s1, 0 }, + }; //load the same config on both LMLs //only one will get used based on direction - this->Modify_SPI_Reg_bits(LMS7param(LML1_BQP), m[LMLSampleSource::BQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_BIP), m[LMLSampleSource::BI]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_AQP), m[LMLSampleSource::AQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML1_AIP), m[LMLSampleSource::AI]); + this->Modify_SPI_Reg_bits(LMS7param(LML1_BQP), m.at(LMLSampleSource::BQ)); + this->Modify_SPI_Reg_bits(LMS7param(LML1_BIP), m.at(LMLSampleSource::BI)); + this->Modify_SPI_Reg_bits(LMS7param(LML1_AQP), m.at(LMLSampleSource::AQ)); + this->Modify_SPI_Reg_bits(LMS7param(LML1_AIP), m.at(LMLSampleSource::AI)); - this->Modify_SPI_Reg_bits(LMS7param(LML2_BQP), m[LMLSampleSource::BQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_BIP), m[LMLSampleSource::BI]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_AQP), m[LMLSampleSource::AQ]); - this->Modify_SPI_Reg_bits(LMS7param(LML2_AIP), m[LMLSampleSource::AI]); + this->Modify_SPI_Reg_bits(LMS7param(LML2_BQP), m.at(LMLSampleSource::BQ)); + this->Modify_SPI_Reg_bits(LMS7param(LML2_BIP), m.at(LMLSampleSource::BI)); + this->Modify_SPI_Reg_bits(LMS7param(LML2_AQP), m.at(LMLSampleSource::AQ)); + this->Modify_SPI_Reg_bits(LMS7param(LML2_AIP), m.at(LMLSampleSource::AI)); } int LMS7002M::SetRxDCRemoval(const bool enable) @@ -3132,7 +2942,7 @@ void LMS7002M::EnableValuesCache(bool enabled) useCache = enabled; } -bool LMS7002M::IsValuesCacheEnabled() +bool LMS7002M::IsValuesCacheEnabled() const { return useCache; } @@ -3142,11 +2952,6 @@ MCU_BD* LMS7002M::GetMCUControls() const return mcuControl; } -void LMS7002M::EnableCalibrationByMCU(bool enabled) -{ - mCalibrationByMCU = enabled; -} - float_type LMS7002M::GetTemperature() { if (CalibrateInternalADC(32) != 0) @@ -3177,13 +2982,14 @@ void LMS7002M::SetLogCallback(std::function callback int LMS7002M::CopyChannelRegisters(const Channel src, const Channel dest, const bool copySX) { - Channel ch = this->GetActiveChannel(); //remember used channel + ChannelScope scope(this); std::vector addrToWrite; addrToWrite = mRegistersMap->GetUsedAddresses(1); if (!copySX) { - for (uint32_t address = MemorySectionAddresses[SX][0]; address <= MemorySectionAddresses[SX][1]; ++address) + const auto& SXMemoryAddresses = MemorySectionAddresses.at(MemorySection::SX); + for (uint32_t address = SXMemoryAddresses.at(0); address <= SXMemoryAddresses.at(1); ++address) addrToWrite.erase(std::find(addrToWrite.begin(), addrToWrite.end(), address)); } for (auto address : addrToWrite) @@ -3193,7 +2999,7 @@ int LMS7002M::CopyChannelRegisters(const Channel src, const Channel dest, const } if (controlPort) UploadAll(); - this->SetActiveChannel(ch); + return 0; } @@ -3319,7 +3125,7 @@ float_type LMS7002M::GetSampleRate(TRXDir dir) return interface_Hz; } -int LMS7002M::SetGFIRFilter(TRXDir dir, unsigned ch, bool enabled, double bandwidth) +int LMS7002M::SetGFIRFilter(TRXDir dir, Channel ch, bool enabled, double bandwidth) { ChannelScope scope(this, ch); const bool bypassFIR = !enabled; @@ -3336,7 +3142,7 @@ int LMS7002M::SetGFIRFilter(TRXDir dir, unsigned ch, bool enabled, double bandwi Modify_SPI_Reg_bits(LMS7param(GFIR3_BYP_RXTSP), bypassFIR); const bool sisoDDR = Get_SPI_Reg_bits(LMS7_LML1_SISODDR); const bool clockIsNotInverted = !(enabled | sisoDDR); - if (ch % 2) + if (ch == LMS7002M::Channel::ChB) { Modify_SPI_Reg_bits(LMS7param(CDSN_RXBLML), clockIsNotInverted); Modify_SPI_Reg_bits(LMS7param(CDS_RXBLML), enabled ? 3 : 0); @@ -3423,7 +3229,7 @@ int LMS7002M::SetGFIRFilter(TRXDir dir, unsigned ch, bool enabled, double bandwi ss << std::endl; lime::info(ss.str()); - return ResetLogicregisters(); + return ResetLogicRegisters(); } void LMS7002M::SetOnCGENChangeCallback(CGENChangeCallbackType callback, void* userData) diff --git a/src/lms7002m/LMS7002M_RxTxCalibrations.cpp b/src/lms7002m/LMS7002M_RxTxCalibrations.cpp index e3d2460a9..b6f30a419 100644 --- a/src/lms7002m/LMS7002M_RxTxCalibrations.cpp +++ b/src/lms7002m/LMS7002M_RxTxCalibrations.cpp @@ -169,9 +169,6 @@ uint32_t LMS7002M::GetRSSI(RSSI_measurements* measurements) return rssi; } -/** @brief Calibrates Transmitter. DC correction, IQ gains, IQ phase correction -@return 0-success, other-failure -*/ int LMS7002M::CalibrateTx(float_type bandwidth_Hz, bool useExtLoopback) { if (TrxCalib_RF_LimitLow > bandwidth_Hz) @@ -266,9 +263,6 @@ int LMS7002M::CalibrateTx(float_type bandwidth_Hz, bool useExtLoopback) return 0; } -/** @brief Calibrates Receiver. DC offset, IQ gains, IQ phase correction - @return 0-success, other-failure -*/ int LMS7002M::CalibrateRx(float_type bandwidth_Hz, bool useExtLoopback) { if (TrxCalib_RF_LimitLow > bandwidth_Hz) @@ -389,11 +383,6 @@ int LMS7002M::CalibrateRx(float_type bandwidth_Hz, bool useExtLoopback) return 0; } -/** @brief Loads given DC_REG values into registers - @param dir TxTSP or RxTSP selection - @param I DC_REG I value - @param Q DC_REG Q value -*/ int LMS7002M::LoadDC_REG_IQ(TRXDir dir, int16_t I, int16_t Q) { if (dir == TRXDir::Tx) diff --git a/src/lms7002m/LMS7002M_gainCalibrations.cpp b/src/lms7002m/LMS7002M_gainCalibrations.cpp index a1eacb841..044c01353 100644 --- a/src/lms7002m/LMS7002M_gainCalibrations.cpp +++ b/src/lms7002m/LMS7002M_gainCalibrations.cpp @@ -15,8 +15,8 @@ int LMS7002M::CalibrateTxGainSetup() SPI_write(0x0020, value); //RxTSP - SetDefaults(RxTSP); - SetDefaults(RxNCO); + SetDefaults(MemorySection::RxTSP); + SetDefaults(MemorySection::RxNCO); Modify_SPI_Reg_bits(LMS7param(AGC_MODE_RXTSP), 1); Modify_SPI_Reg_bits(LMS7param(AGC_AVG_RXTSP), 1); Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), 1); @@ -31,7 +31,7 @@ int LMS7002M::CalibrateTxGainSetup() Modify_SPI_Reg_bits(0x010D, 4, 1, 0xF); //RBB - SetDefaults(RBB); + SetDefaults(MemorySection::RBB); Modify_SPI_Reg_bits(LMS7param(PD_LPFL_RBB), 1); Modify_SPI_Reg_bits(LMS7param(INPUT_CTL_PGA_RBB), 3); Modify_SPI_Reg_bits(LMS7param(G_PGA_RBB), 12); @@ -42,7 +42,7 @@ int LMS7002M::CalibrateTxGainSetup() //AFE const int isel_dac_afe = Get_SPI_Reg_bits(LMS7param(ISEL_DAC_AFE)); - SetDefaults(AFE); + SetDefaults(MemorySection::AFE); Modify_SPI_Reg_bits(LMS7param(ISEL_DAC_AFE), isel_dac_afe); if (ch == 2) { @@ -52,7 +52,7 @@ int LMS7002M::CalibrateTxGainSetup() //BIAS const int rp_calib_bias = Get_SPI_Reg_bits(LMS7param(RP_CALIB_BIAS)); - SetDefaults(BIAS); + SetDefaults(MemorySection::BIAS); Modify_SPI_Reg_bits(LMS7param(RP_CALIB_BIAS), rp_calib_bias); //LDO @@ -62,7 +62,7 @@ int LMS7002M::CalibrateTxGainSetup() //use configured xbuf settings //CGEN - SetDefaults(CGEN); + SetDefaults(MemorySection::CGEN); status = SetFrequencyCGEN(61.44e6); if (status != 0) return status; @@ -77,8 +77,8 @@ int LMS7002M::CalibrateTxGainSetup() const int isinc = Get_SPI_Reg_bits(LMS7param(ISINC_BYP_TXTSP)); const int txcmixGainLSB = Get_SPI_Reg_bits(LMS7param(CMIX_GAIN_TXTSP)); const int txcmixGainMSB = Get_SPI_Reg_bits(LMS7param(CMIX_GAIN_TXTSP_R3)); - SetDefaults(TxTSP); - SetDefaults(TxNCO); + SetDefaults(MemorySection::TxTSP); + SetDefaults(MemorySection::TxNCO); Modify_SPI_Reg_bits(LMS7param(CMIX_GAIN_TXTSP), txcmixGainLSB); Modify_SPI_Reg_bits(LMS7param(CMIX_GAIN_TXTSP_R3), txcmixGainMSB); Modify_SPI_Reg_bits(LMS7param(ISINC_BYP_TXTSP), isinc); @@ -97,7 +97,7 @@ int LMS7002M::CalibrateTxGainSetup() return 0; } -int LMS7002M::CalibrateTxGain(float maxGainOffset_dBFS, float* actualGain_dBFS) +int LMS7002M::CalibrateTxGain() { if (!controlPort) { diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index 19492ff12..e2788da94 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -215,7 +215,7 @@ void TRXLooper::Start() //int64_t startPoint = std::chrono::time_point_cast(pcStreamStart).time_since_epoch().count(); //printf("Stream%i start %lius\n", chipId, startPoint); // if (!mConfig.alignPhase) - // lms->ResetLogicregisters(); + // lms->ResetLogicRegisters(); } /// @brief Stops the stream and cleans up all the memory. From b734f2f95753181e96939cfc25313dad3355c2e3 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 8 Feb 2024 14:08:52 +0200 Subject: [PATCH 28/46] Document all the variables in the public includes folder --- src/include/Register.h | 36 +++++++++++++++------ src/include/limesuite/DeviceNode.h | 17 +++++++--- src/include/limesuite/IComms.h | 7 ++-- src/include/limesuite/LMS7002M.h | 15 +-------- src/include/limesuite/LMS7002M_parameters.h | 12 +++---- src/include/limesuite/SDRDevice.h | 1 + src/include/limesuite/StreamComposite.h | 9 +++--- src/include/limesuite/commonTypes.h | 12 +++++-- src/lms7002m/LMS7002M_RxTxCalibrations.cpp | 2 +- 9 files changed, 67 insertions(+), 44 deletions(-) diff --git a/src/include/Register.h b/src/include/Register.h index f7b1244b3..ff079954d 100644 --- a/src/include/Register.h +++ b/src/include/Register.h @@ -1,34 +1,52 @@ #ifndef LIME_REGISTER_H #define LIME_REGISTER_H -#include +#include namespace lime { -inline constexpr uint32_t bitMask(uint8_t msb, uint8_t lsb) +/** + * @brief Gets the bit mask for the register + * @param msb The index of the most significant bit + * @param lsb The index of the least significant bit + * @return The mask of the bits of the register. + */ +constexpr uint32_t bitMask(uint8_t msb, uint8_t lsb) { return (~(~0u << (msb - lsb + 1))) << (lsb); } +/** + * @brief A structure for holding information about a register. + */ struct Register { - Register() + /// @brief Constructs the register with default values. + constexpr Register() : address(0) , defaultValue(0) , msb(15) , lsb(0) , twoComplement(false){}; + + /// @brief Constructs the register with the given values. + /// @param address The memory address of the register. + /// @param msb The index of the most significant bit of the register. + /// @param lsb The index of the least significant bit of the register. + /// @param defaultValue The default value of the register. + /// @param twocomplement Whether the register is represented in a Two's Complement way. constexpr Register(uint16_t address, uint8_t msb, uint8_t lsb, uint16_t defaultValue, bool twocomplement) : address(address) , defaultValue(defaultValue) , msb(msb) , lsb(lsb) , twoComplement(twocomplement){}; - uint16_t address; - uint16_t defaultValue; - uint8_t msb; - uint8_t lsb; - bool twoComplement; + + uint16_t address; ///< The memory address. + uint16_t defaultValue; ///< The default value of the register. + uint8_t msb; ///< The index of the most significant bit of the register. + uint8_t lsb; ///< The index of the least significant bit of the register. + bool twoComplement; ///< Indicates if the register is represented in a Two's Complement way. }; } // namespace lime -#endif // LIME_REGISTER_H \ No newline at end of file +#endif // LIME_REGISTER_H diff --git a/src/include/limesuite/DeviceNode.h b/src/include/limesuite/DeviceNode.h index 9af6977ee..fef45bd3b 100644 --- a/src/include/limesuite/DeviceNode.h +++ b/src/include/limesuite/DeviceNode.h @@ -3,21 +3,30 @@ #include "DeviceNodeClass.h" #include +#include +#include namespace lime { +/// @brief Structure describing a device node in the device node tree. struct DeviceNode { + /// @brief Default constructor for the node. DeviceNode(){}; + + /// @brief The constructor for the device node. + /// @param name The name of the node. + /// @param nodeClass The device class of the node. + /// @param ptr The pointer to the device. DeviceNode(const std::string& name, eDeviceNodeClass nodeClass, void* ptr) : name(name) , deviceNodeClass(nodeClass) , ptr(ptr) { } - std::string name; - eDeviceNodeClass deviceNodeClass; - void* ptr; - std::vector> children; + std::string name; ///< The name of the node. + eDeviceNodeClass deviceNodeClass; ///< The device class of the node. + void* ptr; ///< The pointer to the device. + std::vector> children; ///< The children of this node in the device tree. }; } // namespace lime diff --git a/src/include/limesuite/IComms.h b/src/include/limesuite/IComms.h index 744e16e44..57917cf21 100644 --- a/src/include/limesuite/IComms.h +++ b/src/include/limesuite/IComms.h @@ -62,10 +62,11 @@ class LIME_API II2C virtual int I2CRead(int address, uint8_t* dest, uint32_t length) = 0; }; +/// @brief The structure for writing and reading custom parameters struct CustomParameterIO { - int32_t id; - double value; - std::string units; + int32_t id; ///< The ID of the parameter + double value; ///< The value of the parameter. + std::string units; ///< The units of the parameter. }; /** @brief An interface for general device communications */ diff --git a/src/include/limesuite/LMS7002M.h b/src/include/limesuite/LMS7002M.h index 63d28afc1..dbab16e19 100644 --- a/src/include/limesuite/LMS7002M.h +++ b/src/include/limesuite/LMS7002M.h @@ -25,19 +25,6 @@ class ISPI; class LMS7002M_RegistersMap; class MCU_BD; -struct RSSI_measurements { - void clear() - { - amplitudeFFT.clear(); - amplitudeGeortzelF.clear(); - amplitudeGeortzelFPGA.clear(); - } - - std::vector amplitudeFFT; - std::vector amplitudeGeortzelF; - std::vector amplitudeGeortzelFPGA; -}; - typedef double float_type; /*! @brief Class for communicating with the LMS7002M chip. @@ -950,7 +937,7 @@ class LIME_API LMS7002M static const std::array, 3> gVCO_frequency_table; static const std::array gCGEN_VCO_frequencies; - uint32_t GetRSSI(RSSI_measurements* measurements = nullptr); + uint32_t GetRSSI(); void SetRxDCOFF(int8_t offsetI, int8_t offsetQ); int CalibrateTxGainSetup(); diff --git a/src/include/limesuite/LMS7002M_parameters.h b/src/include/limesuite/LMS7002M_parameters.h index 6c5623a40..f085b61d4 100644 --- a/src/include/limesuite/LMS7002M_parameters.h +++ b/src/include/limesuite/LMS7002M_parameters.h @@ -19,12 +19,12 @@ extern "C" { /** @brief Structure defining a LMS7002M parameter. */ struct LMS7Parameter { - uint16_t address; - uint8_t msb; - uint8_t lsb; - uint16_t defaultValue; - const char* name; - const char* tooltip; + uint16_t address; ///< The address of the parameter + uint8_t msb; ///< The index of the most significant bit of the parameter. + uint8_t lsb; ///< The index of the least significant bit of the paramerer. + uint16_t defaultValue; ///< The default value of the parameter. + const char* name; ///< The name of the parameter. + const char* tooltip; ///< The tooltip of the parameter. }; static const struct LMS7Parameter LMS7_LRST_TX_B = { 0x0020, 15, 15, 1, "LRST_TX_B", "Resets all the logic registers to the default state for Tx MIMO channel B" }; diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index 6ab336d62..cc3b0ae9e 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -155,6 +155,7 @@ class LIME_API SDRDevice struct StreamConfig { /// @brief Extra configuration settings for a stream. struct Extras { + /// @brief The settings structure for a packet transmission. struct PacketTransmission { PacketTransmission(); diff --git a/src/include/limesuite/StreamComposite.h b/src/include/limesuite/StreamComposite.h index 93bede494..a9b334a62 100644 --- a/src/include/limesuite/StreamComposite.h +++ b/src/include/limesuite/StreamComposite.h @@ -8,10 +8,11 @@ namespace lime { +/** @brief Structure for holding information about the aggregate stream. */ struct LIME_API StreamAggregate { - SDRDevice* device; - std::vector channels; - int32_t streamIndex; + SDRDevice* device; ///< The device the stream is coming from. + std::vector channels; ///< The channels the device is streaming with. + int32_t streamIndex; ///< The index of the stream. }; /** @brief Class for managing streaming from multiple devices at the same time. */ @@ -49,4 +50,4 @@ class LIME_API StreamComposite std::vector mActiveAggregates; }; -} // namespace lime \ No newline at end of file +} // namespace lime diff --git a/src/include/limesuite/commonTypes.h b/src/include/limesuite/commonTypes.h index c0ed50284..438394af7 100644 --- a/src/include/limesuite/commonTypes.h +++ b/src/include/limesuite/commonTypes.h @@ -2,16 +2,22 @@ namespace lime { +/// @brief The direction of the transmission enum class TRXDir : bool { Rx, Tx }; +/// @brief Structure describing the range possible. struct Range { + /// @brief Constructs the range structure, + /// @param min The minimum value of the range (default 0.0) + /// @param max The maximum value of the range (default 0.0) + /// @param step The step of the range (default 0.0 - no step) constexpr Range(double min = 0.0, double max = 0.0, double step = 0.0) : min(min) , max(max) , step(step){}; - double min; - double max; - double step; + double min; ///< The minimum value of the range + double max; ///< The maximum value of the range + double step; ///< The step of the range (or 0.0 for any step) }; /** diff --git a/src/lms7002m/LMS7002M_RxTxCalibrations.cpp b/src/lms7002m/LMS7002M_RxTxCalibrations.cpp index b6f30a419..84c547f3f 100644 --- a/src/lms7002m/LMS7002M_RxTxCalibrations.cpp +++ b/src/lms7002m/LMS7002M_RxTxCalibrations.cpp @@ -159,7 +159,7 @@ static int SetExtLoopback(IConnection* port, uint8_t ch, bool enable, bool tx) */ /** @brief Flips the CAPTURE bit and returns digital RSSI value */ -uint32_t LMS7002M::GetRSSI(RSSI_measurements* measurements) +uint32_t LMS7002M::GetRSSI() { //delay to make sure RSSI gets enough samples to refresh before reading it this_thread::sleep_for(chrono::microseconds(50)); From a7f1a93eea48ff953c95efb14ed529bfb1993d95 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 20 Feb 2024 15:23:33 +0200 Subject: [PATCH 29/46] OpStatus documentation fixes --- src/API/LMS_APIWrapper.cpp | 34 +++---- src/FPGA_common/FPGA_common.cpp | 20 ++-- src/FPGA_common/WriteRegistersBatch.cpp | 2 +- src/boards/LimeSDR_X3/SlaveSelectShim.h | 2 +- src/include/limesuite/IComms.h | 8 +- src/include/limesuite/LMS7002M.h | 118 +++++++++++++----------- src/include/limesuite/OpStatus.h | 4 + src/include/limesuite/SDRDevice.h | 33 ++++++- src/include/limesuite/StreamComposite.h | 2 +- src/protocols/TRXLooper.cpp | 2 + 10 files changed, 134 insertions(+), 91 deletions(-) diff --git a/src/API/LMS_APIWrapper.cpp b/src/API/LMS_APIWrapper.cpp index 974969417..92a8eb491 100644 --- a/src/API/LMS_APIWrapper.cpp +++ b/src/API/LMS_APIWrapper.cpp @@ -628,7 +628,7 @@ API_EXPORT int CALL_CONV LMS_GetNormalizedGain(lms_device_t* device, bool dir_tx if (gain) *gain = (deviceGain - range.min) / (range.max - range.min); - return returnValue == OpStatus::SUCCESS ? 0 : -1; + return OpStatusToReturnCode(returnValue); } API_EXPORT int CALL_CONV LMS_GetGaindB(lms_device_t* device, bool dir_tx, size_t chan, unsigned* gain) @@ -648,7 +648,7 @@ API_EXPORT int CALL_CONV LMS_GetGaindB(lms_device_t* device, bool dir_tx, size_t if (gain) *gain = std::lround(deviceGain) + 12; - return returnValue == OpStatus::SUCCESS ? 0 : -1; + return OpStatusToReturnCode(returnValue); } API_EXPORT int CALL_CONV LMS_Calibrate(lms_device_t* device, bool dir_tx, size_t chan, double bw, unsigned flags) @@ -723,10 +723,10 @@ API_EXPORT int CALL_CONV LMS_SetTestSignal( } }; - try { + try + { apiDevice->device->SetTestSignal(apiDevice->moduleIndex, direction, chan, enumToTestStruct(sig), dc_i, dc_q); - } - catch (...) + } catch (...) { lime::error("Failed to set %s channel %i test signal.", ToString(direction).c_str(), chan); } @@ -1784,10 +1784,10 @@ API_EXPORT int CALL_CONV LMS_WriteLMSReg(lms_device_t* device, uint32_t address, return -1; } - try { + try + { apiDevice->device->WriteRegister(apiDevice->moduleIndex, address, val); - } - catch(...) + } catch (...) { return lime::error("Failed to write register at %04X.", address); } @@ -1803,11 +1803,11 @@ API_EXPORT int CALL_CONV LMS_ReadLMSReg(lms_device_t* device, uint32_t address, return -1; } - try { + try + { if (val) *val = apiDevice->device->ReadRegister(apiDevice->moduleIndex, address); - } - catch (...) + } catch (...) { return lime::error("Failed to read register at %04X.", address); } @@ -1823,10 +1823,10 @@ API_EXPORT int CALL_CONV LMS_WriteFPGAReg(lms_device_t* device, uint32_t address return -1; } - try { + try + { apiDevice->device->WriteRegister(apiDevice->moduleIndex, address, val, true); - } - catch (...) + } catch (...) { return lime::error("Failed to write register at %04X.", address); } @@ -1842,11 +1842,11 @@ API_EXPORT int CALL_CONV LMS_ReadFPGAReg(lms_device_t* device, uint32_t address, return -1; } - try { + try + { if (val) *val = apiDevice->device->ReadRegister(apiDevice->moduleIndex, address, true); - } - catch (...) + } catch (...) { return lime::error("Failed to read register at %04X.", address); } diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index adce125fd..8c76600a3 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -101,7 +101,7 @@ void FPGA::EnableValuesCache(bool enabled) /// @brief Writes the specified value into the specified address into the FPGA. /// @param address The address to write to. /// @param value The value to write. -/// @return The operation status (0 on success). +/// @return The operation status. OpStatus FPGA::WriteRegister(uint32_t address, uint32_t value) { return WriteRegisters(&address, &value, 1); @@ -120,7 +120,7 @@ int FPGA::ReadRegister(uint32_t address) /// @param addrs The addresses to write to. /// @param data The values to write into the memory. /// @param cnt The amount of values to write. -/// @return The success status of the operation (0 on success). +/// @return The status of the operation. OpStatus FPGA::WriteRegisters(const uint32_t* addrs, const uint32_t* data, unsigned cnt) { std::vector spiBuffer; @@ -197,7 +197,7 @@ OpStatus FPGA::WriteRegisters(const uint32_t* addrs, const uint32_t* data, unsig /// @brief Writes the given data blocks into LMS7002M chip. /// @param data The data to write. /// @param length The length of the data to write. -/// @return Whether the operation succeedded or not. +/// @return The status of the operation. OpStatus FPGA::WriteLMS7002MSPI(const uint32_t* data, uint32_t length) { #ifndef NDEBUG @@ -211,7 +211,7 @@ OpStatus FPGA::WriteLMS7002MSPI(const uint32_t* data, uint32_t length) /// @param writeData The addresses to read from. /// @param readData The storage to store the read data. /// @param length The length of the data to read. -/// @return Whether the operation succeedded or not. +/// @return The status of the operation. OpStatus FPGA::ReadLMS7002MSPI(const uint32_t* writeData, uint32_t* readData, uint32_t length) { return lms7002mPort->SPI(writeData, readData, length); @@ -221,7 +221,7 @@ OpStatus FPGA::ReadLMS7002MSPI(const uint32_t* writeData, uint32_t* readData, ui /// @param addrs The addresses to read. /// @param data The data array to write the read values to. /// @param cnt The amount of registers to read. -/// @return The operation status (0 on success). +/// @return The operation status. OpStatus FPGA::ReadRegisters(const uint32_t* addrs, uint32_t* data, unsigned cnt) { std::vector spiBuffer; @@ -304,7 +304,7 @@ OpStatus FPGA::ReadRegisters(const uint32_t* addrs, uint32_t* data, unsigned cnt } /// @brief Tells the FPGA to start streaming sample data. -/// @return The operation status (0 on success). +/// @return The operation status. OpStatus FPGA::StartStreaming() { lime::debug("%s", __func__); @@ -316,7 +316,7 @@ OpStatus FPGA::StartStreaming() } /// @brief Tells the FPGA to stop streaming sample data. -/// @return The operation status (0 on success). +/// @return The operation status. OpStatus FPGA::StopStreaming() { lime::debug("%s", __func__); @@ -328,7 +328,7 @@ OpStatus FPGA::StopStreaming() } /// @brief Resets the timestamp of the FPGA. -/// @return The operation status (0 on success). +/// @return The operation status. OpStatus FPGA::ResetTimestamp() { lime::debug("%s", __func__); @@ -443,7 +443,7 @@ OpStatus FPGA::SetPllClock(uint8_t clockIndex, int nSteps, bool waitLock, bool d @param inputFreq Input frequency. @param clocks List of clocks to configure. @param clockCount Number of clocks to configure. - @return 0 on success, other on failure. + @return The operation status. */ OpStatus FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_PLL_clock* clocks, const uint8_t clockCount) { @@ -847,7 +847,7 @@ int FPGA::Samples2FPGAPacketPayload( } /// @brief Configures FPGA PLLs to LimeLight interface frequency. -/// @return 0 on success; other on failure. +/// @return The operation status. OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase) { lime::debug("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz txPhase:%g rxPhase:%g", diff --git a/src/FPGA_common/WriteRegistersBatch.cpp b/src/FPGA_common/WriteRegistersBatch.cpp index c83550b20..bd9540815 100644 --- a/src/FPGA_common/WriteRegistersBatch.cpp +++ b/src/FPGA_common/WriteRegistersBatch.cpp @@ -21,7 +21,7 @@ WriteRegistersBatch::~WriteRegistersBatch() } /// @brief Writes the modified values into the FPGA. -/// @return The operation status (0 on success). +/// @return The operation status. OpStatus WriteRegistersBatch::Flush() { OpStatus status = owner->WriteRegisters(addrs.data(), values.data(), addrs.size()); diff --git a/src/boards/LimeSDR_X3/SlaveSelectShim.h b/src/boards/LimeSDR_X3/SlaveSelectShim.h index ed24a4572..661107fd0 100644 --- a/src/boards/LimeSDR_X3/SlaveSelectShim.h +++ b/src/boards/LimeSDR_X3/SlaveSelectShim.h @@ -22,7 +22,7 @@ class LIME_API SlaveSelectShim : public ISPI /** @brief Send the reset device command to the device under this shim. - @return The success status of the operation (0 on success), + @return The status of the operation. */ virtual OpStatus ResetDevice(); diff --git a/src/include/limesuite/IComms.h b/src/include/limesuite/IComms.h index 780f1c58a..ad3595f46 100644 --- a/src/include/limesuite/IComms.h +++ b/src/include/limesuite/IComms.h @@ -19,7 +19,7 @@ class LIME_API ISPI @param MOSI Main Out Sub In (data output from main). @param MISO Main In Sub Out (data output from sub). @param count Input/output data length. - @returns Whether the operation succeedded or not. + @returns The operation status. */ virtual OpStatus SPI(const uint32_t* MOSI, uint32_t* MISO, uint32_t count) = 0; @@ -29,7 +29,7 @@ class LIME_API ISPI @param MOSI Main Out Sub In (data output from main). @param MISO Main In Sub Out (data output from sub). @param count Input/output data length. - @returns Whether the operation succeedded or not. + @returns The operation status. */ virtual OpStatus SPI(uint32_t spiBusAddress, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) = 0; }; @@ -45,7 +45,7 @@ class LIME_API II2C @param address Inter-Integrated Circuit slave address. @param data Output buffer. @param length Output data length. - @return 0 on success. + @return The operation status. */ virtual OpStatus I2CWrite(int address, const uint8_t* data, uint32_t length) = 0; @@ -58,7 +58,7 @@ class LIME_API II2C @param address The address of the slave. @param [out] dest Buffer to store read data from the slave. @param length Number of bytes to read. - @return 0 on success. + @return The operation status. */ virtual OpStatus I2CRead(int address, uint8_t* dest, uint32_t length) = 0; }; diff --git a/src/include/limesuite/LMS7002M.h b/src/include/limesuite/LMS7002M.h index d41c7c343..6e6732a69 100644 --- a/src/include/limesuite/LMS7002M.h +++ b/src/include/limesuite/LMS7002M.h @@ -136,19 +136,19 @@ class LIME_API LMS7002M * @param dir Rx or Tx * @param channel true for the transmit size, false for receive * @param enable true to enable, false to disable - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus EnableChannel(TRXDir dir, const uint8_t channel, const bool enable); /*! * @brief Writes all registers from host to chip - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus UploadAll(); /*! * @brief Reads all registers from the chip to host - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus DownloadAll(); @@ -163,25 +163,25 @@ class LIME_API LMS7002M * @param src The channel to copy from. * @param dest The channel to copy to. * @param copySX Whether to copy the SX registers or not. - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus CopyChannelRegisters(const Channel src, const Channel dest, bool copySX); /*! * @brief Sends reset signal to chip, after reset enables B channel controls - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus ResetChip(); /*! * Perform soft-reset sequence over SPI - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus SoftReset(); /*! * @brief Resets the logic registers to their default state. - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus ResetLogicRegisters(); @@ -189,14 +189,14 @@ class LIME_API LMS7002M * @brief Reads configuration file and uploads registers to chip * @param filename Configuration source file * @param tuneDynamicValues Whether to tune the dynamic values or not - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus LoadConfig(const std::string& filename, bool tuneDynamicValues = true); /*! * @brief Reads all registers from chip and saves to file * @param filename destination filename - * @return 0-success, other failure + * @return The status of the operation */ OpStatus SaveConfig(const std::string& filename); @@ -223,7 +223,7 @@ class LIME_API LMS7002M * @param param LMS7002M control parameter * @param fromChip read initial value directly from chip * @param value new parameter value - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus Modify_SPI_Reg_bits(const LMS7Parameter& param, const uint16_t value, bool fromChip = false); @@ -234,7 +234,7 @@ class LIME_API LMS7002M * @param lsb Least significant bit index * @param value new bits value, the value is shifted left by lsb bits * @param fromChip read initial value directly from chip - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus Modify_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, uint16_t value, bool fromChip = false); @@ -243,15 +243,15 @@ class LIME_API LMS7002M * @param address SPI address * @param data new register value * @param toChip whether we're writing to the chip or not - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SPI_write(uint16_t address, uint16_t data, bool toChip = false); /*! * @brief Reads whole register value from given address * @param address SPI address - * @param status operation status(optional) * @param fromChip read value directly from chip + * @param status The operation success status (optional). * @return register value */ uint16_t SPI_read(uint16_t address, bool fromChip = false, OpStatus* status = 0); @@ -259,7 +259,7 @@ class LIME_API LMS7002M /*! * @brief Performs registers test by writing known data and confirming readback data * @param fileName The name of the file to write the test output to. - * @return 0-registers test passed, other-failure + * @return The operation status. */ OpStatus RegistersTest(const std::string& fileName = "registersTest.txt"); @@ -274,7 +274,7 @@ class LIME_API LMS7002M * @brief Calibrates Receiver. DC offset, IQ gains, IQ phase correction * @param bandwidth_Hz The bandwidth to calibrate the device for (in Hz) * @param useExtLoopback Whether to use external loopback or not. - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus CalibrateRx(float_type bandwidth_Hz, const bool useExtLoopback = false); @@ -282,46 +282,46 @@ class LIME_API LMS7002M * @brief Calibrates Transmitter. DC correction, IQ gains, IQ phase correction * @param bandwidth_Hz The bandwidth to calibrate the device for (in Hz) * @param useExtLoopback Whether to use external loopback or not. - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus CalibrateTx(float_type bandwidth_Hz, const bool useExtLoopback = false); /** * @brief Tunes the Low Pass Filter for the TX direction. * @param tx_lpf_freq_RF The frequency (in Hz) to tune the filter to. - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus TuneTxFilter(const float_type tx_lpf_freq_RF); /** * @brief Tunes the Low Pass Filter for the RX direction. * @param rx_lpf_freq_RF The frequency (in Hz) to tune the filter to. - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus TuneRxFilter(const float_type rx_lpf_freq_RF); /*! * @brief Calibrates the internal Analog to Digital Converter on the chip. * @param clkDiv The clock division ratio for measurement loop. - * @return 0 for success, else error + * @return The status of the operation */ OpStatus CalibrateInternalADC(int clkDiv = 32); /*! * @brief Calibrates the RP_BIAS of the chip. - * @return 0 for success, else error + * @return The status of the operation */ OpStatus CalibrateRP_BIAS(); /*! * @brief Calibrates the TX gain. - * @return 0 for success, else error + * @return The status of the operation */ OpStatus CalibrateTxGain(); /** * @brief Calibrates the Analog RSSI - * @return 0 for success, else error + * @return The status of the operation */ OpStatus CalibrateAnalogRSSI_DC_Offset(); @@ -329,7 +329,7 @@ class LIME_API LMS7002M * Set the RX PGA gain in dB * @param gain In dB range -12.0, 19.0 dB * @param channel The channel to set it for - * @return 0 for success, else error + * @return The status of the operation */ OpStatus SetRBBPGA_dB(const float_type gain, const Channel channel); @@ -344,7 +344,7 @@ class LIME_API LMS7002M * Set the RX LNA gain in dB * @param gain In dB range 0.0, 30.0 dB * @param channel The channel to set it for - * @return 0 for success, else error + * @return The status of the operation */ OpStatus SetRFELNA_dB(const float_type gain, const Channel channel); @@ -359,7 +359,7 @@ class LIME_API LMS7002M * Set the RX loopback LNA gain in dB * @param gain In dB range 0.0, 40.0 dB * @param channel The channel to set it for - * @return 0 for success, else error + * @return The status of the operation */ OpStatus SetRFELoopbackLNA_dB(const float_type gain, const Channel channel); @@ -374,7 +374,7 @@ class LIME_API LMS7002M * Set the RX TIA gain in dB * @param gain In dB range 0.0, 12.0 dB * @param channel The channel to set it for - * @return 0 for success, else error + * @return The status of the operation */ OpStatus SetRFETIA_dB(const float_type gain, const Channel channel); @@ -389,7 +389,7 @@ class LIME_API LMS7002M * Set the TX PAD gain in dB * @param gain In dB range -52.0, 0.0 dB * @param channel The channel to set it for - * @return 0 for success, else error + * @return The status of the operation */ OpStatus SetTRFPAD_dB(const float_type gain, const Channel channel); @@ -404,7 +404,7 @@ class LIME_API LMS7002M * Set the TBB frontend gain in dB * @param gain In dB relative to optimal gain (0 - optimal gain, >0 may cause saturation) * @param channel The channel to set it for - * @return 0 for success, else error + * @return The status of the operation */ OpStatus SetTBBIAMP_dB(const float_type gain, const Channel channel); @@ -419,7 +419,7 @@ class LIME_API LMS7002M * Set the TX loopback PAD gain in dB * @param gain In dB range -4.3, 0.0 dB * @param channel The channel to set it for - * @return 0 for success, else error + * @return The status of the operation */ OpStatus SetTRFLoopbackPAD_dB(const float_type gain, const Channel channel); @@ -443,7 +443,7 @@ class LIME_API LMS7002M /*! * @brief Sets the RFE input path. * @param path The enumeration value of the path to set it to - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetPathRFE(PathRFE path); @@ -456,7 +456,7 @@ class LIME_API LMS7002M /*! * Set the TRF Band selection. * @param band 1 or 2 - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus SetBandTRF(const int band); @@ -471,7 +471,7 @@ class LIME_API LMS7002M * @param direction The direction to set the antenna for. * @param channel The channel to set the antenna for. * @param path The index of the antenna to use. - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetPath(TRXDir direction, uint8_t channel, uint8_t path); @@ -479,7 +479,7 @@ class LIME_API LMS7002M * @brief Sets the reference clock of the SX * @param dir Rx/Tx module selection * @param freq_Hz The frequency to set the reference clock to (in Hz) - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetReferenceClk_SX(TRXDir dir, float_type freq_Hz); @@ -502,7 +502,7 @@ class LIME_API LMS7002M * @param freq_Hz desired frequency in Hz * @param retainNCOfrequencies recalculate NCO coefficients to keep currently set frequencies * @param output if not null outputs calculated CGEN parameters - * @return 0-success, other-cannot deliver desired frequency + * @return The status of the operation */ OpStatus SetFrequencyCGEN(float_type freq_Hz, const bool retainNCOfrequencies = false, CGEN_details* output = nullptr); @@ -524,7 +524,7 @@ class LIME_API LMS7002M * @param dir Rx/Tx module selection * @param freq_Hz desired frequency in Hz * @param output if not null outputs intermediate calculation values - * @return 0-success, other-cannot deliver requested frequency + * @return The status of the operation */ OpStatus SetFrequencySX(TRXDir dir, float_type freq_Hz, SX_details* output = nullptr); @@ -533,7 +533,7 @@ class LIME_API LMS7002M * @param dir Rx/Tx module selection * @param freq_Hz desired frequency in Hz * @param BW The bandwidth (in Hz) - * @return 0-success, other-cannot deliver requested frequency + * @return The status of the operation */ OpStatus SetFrequencySXWithSpurCancelation(TRXDir dir, float_type freq_Hz, float_type BW); @@ -546,7 +546,18 @@ class LIME_API LMS7002M ///VCO modules available for tuning enum class VCO_Module : uint8_t { VCO_CGEN, VCO_SXR, VCO_SXT }; + + /*! + * @brief Performs VCO tuning operations for CLKGEN + * @return The status of the operation + */ OpStatus TuneCGENVCO(); + + /*! + * @brief Performs VCO tuning operations for CLKGEN, SXR, SXT modules + * @param module module selection for tuning 0-cgen, 1-SXR, 2-SXT + * @return The status of the operation + */ OpStatus TuneVCO(VCO_Module module); /*! @@ -554,7 +565,7 @@ class LIME_API LMS7002M * @param dir TxTSP or RxTSP selection * @param I DC_REG I value * @param Q DC_REG Q value - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus LoadDC_REG_IQ(TRXDir dir, int16_t I, int16_t Q); @@ -563,7 +574,7 @@ class LIME_API LMS7002M * @param dir transmitter or receiver selection * @param index NCO index from 0 to 15 * @param freq_Hz desired NCO frequency - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetNCOFrequency(TRXDir dir, uint8_t index, float_type freq_Hz); @@ -580,7 +591,7 @@ class LIME_API LMS7002M * @brief Sets chosen NCO phase offset angle when memory table MODE is 0 * @param dir transmitter or receiver selection * @param angle_deg phase offset angle in degrees - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetNCOPhaseOffsetForMode0(TRXDir dir, float_type angle_deg); @@ -589,7 +600,7 @@ class LIME_API LMS7002M * @param dir transmitter or receiver selection * @param index PHO index from 0 to 15 * @param angle_deg phase offset angle in degrees - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetNCOPhaseOffset(TRXDir dir, uint8_t index, float_type angle_deg); @@ -614,7 +625,7 @@ class LIME_API LMS7002M * @param gfirIndex GFIR index from 0 to 2. * @param coef Array of returned coefficients (normalized from -1 to 1) * @param coefCount Number of coefficients to read. - * @return 0-success, other-failure. + * @return The status of the operation. */ OpStatus GetGFIRCoefficients(TRXDir dir, uint8_t gfirIndex, float_type* coef, uint8_t coefCount); @@ -624,7 +635,7 @@ class LIME_API LMS7002M * @param gfirIndex GIR index from 0 to 2 * @param coef array of coefficients (normalized from -1 to 1) * @param coefCount number of coefficients - * @return 0-success, other-failure + * @return The status of the operation * * This function does not change GFIR*_L or GFIR*_N parameters, they have to be set manually */ @@ -636,7 +647,7 @@ class LIME_API LMS7002M * @param ch The channel for which to set up the filter * @param enabled Whether to enable or disable the GFIR filter * @param bandwidth The bandwidth (in Hz) to set the filter for. - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetGFIRFilter(TRXDir dir, Channel ch, bool enabled, double bandwidth); @@ -646,7 +657,7 @@ class LIME_API LMS7002M * @param freq_Hz The frequency array to set. * @param count The amount of frequencies to set (max 16) * @param phaseOffset The phase offset of the NCO to set. - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetNCOFrequencies(TRXDir dir, const float_type* freq_Hz, uint8_t count, float_type phaseOffset); @@ -664,7 +675,7 @@ class LIME_API LMS7002M * @param angles_deg The angles of the NCO to set (in degrees). * @param count The amount of angles to set (max 16) * @param frequencyOffset The offset of the NCO (in Hz). - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetNCOPhases(TRXDir dir, const float_type* angles_deg, uint8_t count, float_type frequencyOffset); @@ -682,7 +693,7 @@ class LIME_API LMS7002M * @param cgen_freq_Hz The clock frequency to set (in Hz) * @param interpolation The HBI interpolation ratio (actual ratio is pow(2, interpolation + 1), 7 for bypass) * @param decimation The HBD decimation ratio (actual ratio is pow(2, decimation + 1), 7 for bypass) - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetInterfaceFrequency(float_type cgen_freq_Hz, const uint8_t interpolation, const uint8_t decimation); @@ -730,7 +741,7 @@ class LIME_API LMS7002M /*! * @brief Enables or disables the DC corrector bypass * @param enable Enables or disables the - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetRxDCRemoval(const bool enable); @@ -743,7 +754,7 @@ class LIME_API LMS7002M /*! * Enables/disables TDD mode * @param enable true - use same PLL for Tx and Rx, false - us seperate PLLs - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus EnableSXTDD(bool enable); @@ -752,7 +763,7 @@ class LIME_API LMS7002M * @param dir true for tx, false for rx * @param I the real adjustment [+1.0, -1.0] * @param Q the imaginary adjustment [+1.0, -1.0] - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SetDCOffset(TRXDir dir, const float_type I, const float_type Q); @@ -770,7 +781,7 @@ class LIME_API LMS7002M * @param phase the phase adjustment [+pi, -pi] * @param gainI the real gain adjustment [+1.0, 0.0] * @param gainQ the imaginary gain adjustment [+1.0, 0.0] - * @return 0 - success, other - failure + * @return The status of the operation */ OpStatus SetIQBalance(const TRXDir dir, const float_type phase, const float_type gainI, const float_type gainQ); @@ -794,6 +805,7 @@ class LIME_API LMS7002M * @brief Sets the frequency of the selected clock. * @param clk_id The enumerator value of the clock to set. * @param freq The frequency (in Hz) to set the clock to. + * @return The operation success status. */ OpStatus SetClockFreq(ClockID clk_id, double freq); @@ -841,7 +853,7 @@ class LIME_API LMS7002M * @param spiData registers data to be written * @param cnt number of registers to write * @param toChip force write to chip - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, uint16_t cnt, bool toChip = false); @@ -850,7 +862,7 @@ class LIME_API LMS7002M * @param spiAddr SPI addresses to read * @param spiData array for read data * @param cnt number of registers to read - * @return 0-success, other-failure + * @return The status of the operation */ OpStatus SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_t cnt); @@ -903,7 +915,7 @@ class LIME_API LMS7002M /*! * @brief Sets given module registers to default values - * @return 0-success, other-failure + * @return The status of the operation */ virtual OpStatus SetDefaults(MemorySection module); diff --git a/src/include/limesuite/OpStatus.h b/src/include/limesuite/OpStatus.h index 78f107afa..902946d48 100644 --- a/src/include/limesuite/OpStatus.h +++ b/src/include/limesuite/OpStatus.h @@ -5,6 +5,7 @@ namespace lime { +/// @brief The possible status codes from operations. enum class OpStatus { SUCCESS = 0, ERROR = -1, @@ -19,6 +20,9 @@ enum class OpStatus { ABORTED = -10, }; +/// @brief Converts a given OpStatus value into a human readable C-string. +/// @param value The value to convert. +/// @return The C-string representing the status. const char* ToCString(OpStatus value); } // namespace lime diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index 87d8ef960..b47da32f6 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -353,6 +353,7 @@ class LIME_API SDRDevice /// @brief Configures the device using the given configuration. /// @param config The configuration to set up the device with. /// @param moduleIndex The device index to configure. + /// @return The status of the operation. virtual OpStatus Configure(const SDRConfig& config, uint8_t moduleIndex) = 0; /// @brief Gets the Descriptor of the SDR Device. @@ -360,14 +361,16 @@ class LIME_API SDRDevice virtual const Descriptor& GetDescriptor() const = 0; /// @brief Initializes the device with initial settings. - /// @return The success status of the initialization (0 on success). + /// @return The success status of the initialization. virtual OpStatus Init() = 0; /// @brief Resets the device. + /// @return The status of the operation. virtual OpStatus Reset() = 0; /// @brief Gets the current status of the GPS locks. /// @param status The pointer to which to output the GPS status. + /// @return The status of the operation. virtual OpStatus GetGPSLock(GPS_Lock* status) = 0; /// @brief Enables or disables the specified channel. @@ -375,6 +378,7 @@ class LIME_API SDRDevice /// @param trx The direction of the channel to configure. /// @param channel The channel to configure. /// @param enable Whether to enable the channel or not. + /// @return The status of the operation. virtual OpStatus EnableChannel(uint8_t moduleIndex, TRXDir trx, uint8_t channel, bool enable) = 0; /// @brief Gets the frequency of a specified clock. @@ -387,6 +391,7 @@ class LIME_API SDRDevice /// @param clk_id The clock ID to set the frequency of. /// @param freq The new frequency of the specified clock (in Hz). /// @param channel The channel to set the frequency of. + /// @return The status of the operation. virtual OpStatus SetClockFreq(uint8_t clk_id, double freq, uint8_t channel) = 0; /// @brief Gets the current frequency of the given channel. @@ -401,6 +406,7 @@ class LIME_API SDRDevice /// @param trx The direction to configure. /// @param channel The channel to configure. /// @param frequency The frequency to set the channel to (in Hz). + /// @return The status of the operation. virtual OpStatus SetFrequency(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double frequency) = 0; /// @brief Gets the current frequency of the NCO. @@ -418,6 +424,7 @@ class LIME_API SDRDevice /// @param index The index of the NCO to use. /// @param frequency The frequency of the NCO to set (in Hz). /// @param phaseOffset Phase offset angle (in degrees) + /// @return The status of the operation. virtual OpStatus SetNCOFrequency( uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t index, double frequency, double phaseOffset = -1.0) = 0; @@ -441,6 +448,7 @@ class LIME_API SDRDevice /// @param channel The channel to configure. /// @param sampleRate The target sample rate (in Hz) /// @param oversample The RF oversampling ratio. + /// @return The status of the operation. virtual OpStatus SetSampleRate(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double sampleRate, uint8_t oversample) = 0; /// @brief Gets the current value of the specified gain. @@ -473,6 +481,7 @@ class LIME_API SDRDevice /// @param trx The direction to configure. /// @param channel The channel to configure. /// @param lpf The bandwidth of the Low Pass Filter to set it to (in Hz). + /// @return The status of the operation. virtual OpStatus SetLowPassFilter(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double lpf) = 0; /// @brief Gets the currently set antenna of the device. @@ -487,6 +496,7 @@ class LIME_API SDRDevice /// @param trx The direction to configure. /// @param channel The channel to configure. /// @param path The ID of the antenna to set the device to use. + /// @return The status of the operation. virtual OpStatus SetAntenna(uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t path) = 0; /// @brief Gets the current status of the test signal mode. @@ -503,6 +513,7 @@ class LIME_API SDRDevice /// @param signalConfiguration The configuration of the test mode to set. /// @param dc_i The I value of the test mode to send (0 for defaults) /// @param dc_q The Q value of the test mode to send (0 for defaults) + /// @return The status of the operation. virtual OpStatus SetTestSignal(uint8_t moduleIndex, TRXDir direction, uint8_t channel, @@ -522,6 +533,7 @@ class LIME_API SDRDevice /// @param trx The direction to configure. /// @param channel The channel to configure. /// @param isAutomatic Whether to use the DC corrector bypass or not (false = bypass the corrector, true = use the corrector) + /// @return The status of the operation. virtual OpStatus SetDCOffsetMode(uint8_t moduleIndex, TRXDir trx, uint8_t channel, bool isAutomatic) = 0; /// @brief Gets the DC I and Q corrector values. @@ -536,6 +548,7 @@ class LIME_API SDRDevice /// @param trx The direction to configure. /// @param channel The channel to configure. /// @param offset The offsets of the I and Q channels. + /// @return The status of the operation. virtual OpStatus SetDCOffset(uint8_t moduleIndex, TRXDir trx, uint8_t channel, const complex64f_t& offset) = 0; /// @brief Gets the current I and Q gain corrector values. @@ -550,6 +563,7 @@ class LIME_API SDRDevice /// @param trx The direction to configure. /// @param channel The channel to configure. /// @param balance The I and Q corrector values to set. + /// @return The status of the operation. virtual OpStatus SetIQBalance(uint8_t moduleIndex, TRXDir trx, uint8_t channel, const complex64f_t& balance) = 0; /// @brief Gets whether the VCO comparators of the clock generator are locked or not. @@ -580,16 +594,19 @@ class LIME_API SDRDevice /// @param address The address of the memory to write to. /// @param value The value to write to the device's memory. /// @param useFPGA Whether to write to the FPGA or not (default false) + /// @return The status of the operation. virtual OpStatus WriteRegister(uint8_t moduleIndex, unsigned int address, unsigned int value, bool useFPGA = false) = 0; /// @brief Loads the configuration of a device from a given file. /// @param moduleIndex The device index to write the configuration into. /// @param filename The file to read the data from. + /// @return The status of the operation. virtual OpStatus LoadConfig(uint8_t moduleIndex, const std::string& filename) = 0; /// @brief Saves the current configuration of the device into a given file. /// @param moduleIndex The device index to save the data from. /// @param filename The file to save the information to. + /// @return The status of the operation. virtual OpStatus SaveConfig(uint8_t moduleIndex, const std::string& filename) = 0; /// @brief Gets the given parameter from the device. @@ -604,6 +621,7 @@ class LIME_API SDRDevice /// @param channel The channel to configure. /// @param parameterKey The key of the paremeter to write to. /// @param value The value to write to the address. + /// @return The status of the operation. virtual OpStatus SetParameter(uint8_t moduleIndex, uint8_t channel, const std::string& parameterKey, uint16_t value) = 0; /// @brief Gets the given parameter from the device. @@ -622,6 +640,7 @@ class LIME_API SDRDevice /// @param msb The index of the most significant bit of the address to modify. (16-bit register) /// @param lsb The index of the least significant bit of the address to modify. (16-bit register) /// @param value The value to write to the address. + /// @return The status of the operation. virtual OpStatus SetParameter( uint8_t moduleIndex, uint8_t channel, uint16_t address, uint8_t msb, uint8_t lsb, uint16_t value) = 0; @@ -630,6 +649,7 @@ class LIME_API SDRDevice /// @param trx The direction of the channel to configure. /// @param channel The channel to configure. /// @param bandwidth The bandwidth of the channel to calibrate for (in Hz). + /// @return The status of the operation. virtual OpStatus Calibrate(uint8_t moduleIndex, TRXDir trx, uint8_t channel, double bandwidth) = 0; /// @brief Configures the GFIR with the settings. @@ -637,6 +657,7 @@ class LIME_API SDRDevice /// @param trx The direction of the channel to configure. /// @param channel The channel to configure. /// @param settings The settings of the GFIR to set. + /// @return The status of the operation. virtual OpStatus ConfigureGFIR( uint8_t moduleIndex, TRXDir trx, uint8_t channel, ChannelConfig::Direction::GFIRFilter settings) = 0; @@ -654,6 +675,7 @@ class LIME_API SDRDevice /// @param channel The channel to set the filter of. /// @param gfirID The ID of the GFIR to set. /// @param coefficients The coefficients (normalized in the range [-1; 1]) to set the GFIR to. + /// @return The status of the operation. virtual OpStatus SetGFIRCoefficients( uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t gfirID, std::vector coefficients) = 0; @@ -663,10 +685,12 @@ class LIME_API SDRDevice /// @param channel The channel to set the filter of. /// @param gfirID The ID of the GFIR to set. /// @param enabled Whether the specifed GFIR should be enabled or disabled. + /// @return The status of the operation. virtual OpStatus SetGFIR(uint8_t moduleIndex, TRXDir trx, uint8_t channel, uint8_t gfirID, bool enabled) = 0; /// @brief Synchronizes the cached changed register values on the host with the real values on the device. /// @param toChip The direction in which to synchronize (true = uploads to the device). + /// @return The status of the operation. virtual OpStatus Synchronize(bool toChip) = 0; /// @brief Enable or disable register value caching on the host side. @@ -681,12 +705,13 @@ class LIME_API SDRDevice /// @brief Sets the hardware timestamp to the provided one by applying a constant offset. /// @param moduleIndex The device index to configure. /// @param now What the definition of the current time should be. + /// @return The status of the operation. virtual OpStatus SetHardwareTimestamp(uint8_t moduleIndex, const uint64_t now) = 0; /// @brief Sets up all the streams on a device. /// @param config The configuration to use for setting the streams up. /// @param moduleIndex The index of the device to set up. - /// @return Success status (0 on success). + /// @return The status code of the operation. virtual OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) = 0; /// @brief Starts all the set up streams on the device. @@ -730,7 +755,7 @@ class LIME_API SDRDevice /// @param moduleIndex The index of the device to upload the waveform to. /// @param samples The samples to upload to the device. /// @param count The amount of samples to upload to the device. - /// @return Operation status (0 on success). + /// @return Operation status. virtual OpStatus UploadTxWaveform(const StreamConfig& config, uint8_t moduleIndex, const void** samples, uint32_t count) { return OpStatus::NOT_IMPLEMENTED; @@ -800,7 +825,7 @@ class LIME_API SDRDevice /// @param data The data to upload to the device. /// @param length The length of the memory to upload. /// @param callback The callback to call for status updates. - /// @return The success status of the operation (0 on success). + /// @return The success status of the operation. virtual OpStatus UploadMemory( eMemoryDevice device, uint8_t moduleIndex, const char* data, size_t length, UploadMemoryCallback callback) { diff --git a/src/include/limesuite/StreamComposite.h b/src/include/limesuite/StreamComposite.h index 9a2b22a27..0c5f8e7a8 100644 --- a/src/include/limesuite/StreamComposite.h +++ b/src/include/limesuite/StreamComposite.h @@ -27,7 +27,7 @@ class LIME_API StreamComposite /// @brief Sets up the streams with the given configuration. /// @param config The configuration to set up the streams with. - /// @return The status of the operation (0 on success). + /// @return The status of the operation. OpStatus StreamSetup(const SDRDevice::StreamConfig& config); /// @brief Starts all of the aggregated streams. diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index f785874f3..a5b29cec9 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -55,6 +55,7 @@ uint64_t TRXLooper::GetHardwareTimestamp() const /// @brief Sets the hardware timestamp. /// @param now The current timestamp to set. +/// @return The status of the operation. OpStatus TRXLooper::SetHardwareTimestamp(const uint64_t now) { mTimestampOffset = now - mRx.lastTimestamp.load(std::memory_order_relaxed); @@ -63,6 +64,7 @@ OpStatus TRXLooper::SetHardwareTimestamp(const uint64_t now) /// @brief Sets up the stream of this looper. /// @param cfg The configuration settings to set up the stream with. +/// @return The status of the operation. OpStatus TRXLooper::Setup(const SDRDevice::StreamConfig& cfg) { if (mRx.thread.joinable() || mTx.thread.joinable()) From b5d22f8054b07baa823ff03f1a40bcb60df8de7a Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 20 Feb 2024 16:23:26 +0200 Subject: [PATCH 30/46] Minor fixups --- src/FPGA_common/WriteRegistersBatch.cpp | 2 +- src/comms/PCIe/TxBufferManager.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FPGA_common/WriteRegistersBatch.cpp b/src/FPGA_common/WriteRegistersBatch.cpp index bd9540815..fbe648e90 100644 --- a/src/FPGA_common/WriteRegistersBatch.cpp +++ b/src/FPGA_common/WriteRegistersBatch.cpp @@ -3,7 +3,7 @@ #ifndef NDEBUG #define ASSERT_WARNING(cond, message) \ if (!cond) \ - printf("W: %s (%s)\n", message, #cond) + lime::warning("%s (%s)\n", message, #cond) #else #define ASSERT_WARNING(cond, message) #endif diff --git a/src/comms/PCIe/TxBufferManager.h b/src/comms/PCIe/TxBufferManager.h index 77d47ca35..f383a9e4f 100644 --- a/src/comms/PCIe/TxBufferManager.h +++ b/src/comms/PCIe/TxBufferManager.h @@ -10,7 +10,7 @@ namespace lime { -/** +/** @brief A class for managing the transmission buffer for the PCIe transfer. @tparam T The samples packet input type. */ @@ -169,4 +169,4 @@ template class TxBufferManager } // namespace lime -#endif // LIME_TXBUFFERMANAGER_H \ No newline at end of file +#endif // LIME_TXBUFFERMANAGER_H From 2249901d1bb4bb7751f14862b96d27d6c8d1dced Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 20 Feb 2024 16:34:32 +0200 Subject: [PATCH 31/46] clang-format --- src/CDCM6208/CDCM6208_Dev.h | 8 ++++---- src/FPGA_common/FPGA_common.cpp | 19 +++++++++++-------- src/boards/LimeSDR/LimeSDR.h | 1 - src/boards/LimeSDR_X3/SlaveSelectShim.h | 2 +- .../MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp | 3 ++- src/comms/PCIe/AvgRmsCounter.h | 7 ++----- src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp | 3 ++- src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp | 3 ++- 8 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/CDCM6208/CDCM6208_Dev.h b/src/CDCM6208/CDCM6208_Dev.h index ae8f9f64d..5496eab78 100644 --- a/src/CDCM6208/CDCM6208_Dev.h +++ b/src/CDCM6208/CDCM6208_Dev.h @@ -73,15 +73,15 @@ struct CDCM_Outputs { }; /** @brief Class for controlling the CDCM6208 2:8 Clock Generator, Jitter Cleaner With Fractional Dividers. - * + * * More information: https://www.ti.com/product/CDCM6208 */ class LIME_API CDCM_Dev { public: - /** + /** @brief Constructs a new CDCM_Dev object. - + @param comms The communications path to use. @param SPI_BASE_ADDR The base address for the API interface. */ @@ -144,7 +144,7 @@ class LIME_API CDCM_Dev double DecToFrac(double target, int* num, int* den); /** - @brief Checks if the given double is an integer. + @brief Checks if the given double is an integer. @param var The double to check. @return Whether the double is an integer or not. */ diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 8c76600a3..fee65b458 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -462,7 +462,10 @@ OpStatus FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, F //check if all clocks are above 5MHz const double PLLlowerLimit = 5e6; if (inputFreq < PLLlowerLimit) - return ReportError(OpStatus::OUT_OF_RANGE, "FPGA SetPllFrequency: PLL[%i] input frequency must be >=%g MHz", pllIndex, PLLlowerLimit / 1e6); + return ReportError(OpStatus::OUT_OF_RANGE, + "FPGA SetPllFrequency: PLL[%i] input frequency must be >=%g MHz", + pllIndex, + PLLlowerLimit / 1e6); for (int i = 0; i < clockCount; ++i) { lime::debug("CLK[%i] Fout:%.3f MHz bypass:%i phase:%g findPhase: %i", @@ -473,8 +476,11 @@ OpStatus FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, F clocks[i].findPhase); willDoPhaseSearch |= clocks[i].findPhase; if (clocks[i].outFrequency < PLLlowerLimit && !clocks[i].bypass) - return ReportError( - OpStatus::OUT_OF_RANGE, "FPGA SetPllFrequency: PLL[%i], clock[%i] must be >=%g MHz", pllIndex, i, PLLlowerLimit / 1e6); + return ReportError(OpStatus::OUT_OF_RANGE, + "FPGA SetPllFrequency: PLL[%i], clock[%i] must be >=%g MHz", + pllIndex, + i, + PLLlowerLimit / 1e6); } uint16_t drct_clk_ctrl_0005 = ReadRegister(0x0005); @@ -850,11 +856,8 @@ int FPGA::Samples2FPGAPacketPayload( /// @return The operation status. OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase) { - lime::debug("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz txPhase:%g rxPhase:%g", - txRate_Hz / 1e6, - rxRate_Hz / 1e6, - txPhase, - rxPhase); + lime::debug( + "FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz txPhase:%g rxPhase:%g", txRate_Hz / 1e6, rxRate_Hz / 1e6, txPhase, rxPhase); lime::FPGA::FPGA_PLL_clock clocks[2]; OpStatus status = OpStatus::SUCCESS; diff --git a/src/boards/LimeSDR/LimeSDR.h b/src/boards/LimeSDR/LimeSDR.h index 40a51af48..6ceedada7 100644 --- a/src/boards/LimeSDR/LimeSDR.h +++ b/src/boards/LimeSDR/LimeSDR.h @@ -32,7 +32,6 @@ class LimeSDR : public LMS7002M_SDRDevice virtual OpStatus SetSampleRate( uint8_t moduleIndex, TRXDir trx, uint8_t channel, double sampleRate, uint8_t oversample) override; - virtual OpStatus SPI(uint32_t chipSelect, const uint32_t* MOSI, uint32_t* MISO, uint32_t count) override; virtual OpStatus StreamSetup(const StreamConfig& config, uint8_t moduleIndex) override; diff --git a/src/boards/LimeSDR_X3/SlaveSelectShim.h b/src/boards/LimeSDR_X3/SlaveSelectShim.h index 661107fd0..48a4de4f0 100644 --- a/src/boards/LimeSDR_X3/SlaveSelectShim.h +++ b/src/boards/LimeSDR_X3/SlaveSelectShim.h @@ -11,7 +11,7 @@ namespace lime { class LIME_API SlaveSelectShim : public ISPI { public: - /** + /** @brief Construct a new Slave Select Shim object @param comms The communications interface to use. @param slaveId The ID of the slave for this shim. diff --git a/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp index 4acd1ff36..f221c856d 100644 --- a/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp +++ b/src/boards/MMX8/LMS64C_FPGA_Over_PCIe_MMX8.cpp @@ -28,7 +28,8 @@ OpStatus LMS64C_FPGA_Over_PCIe_MMX8::CustomParameterRead(std::vector(target), callback, subdeviceIndex); diff --git a/src/comms/PCIe/AvgRmsCounter.h b/src/comms/PCIe/AvgRmsCounter.h index 01ef08b4b..dbb127ef4 100644 --- a/src/comms/PCIe/AvgRmsCounter.h +++ b/src/comms/PCIe/AvgRmsCounter.h @@ -13,14 +13,12 @@ class AvgRmsCounter /** @brief Adds the given value to the accumulators. - @param value The value to add. */ void Add(double value); /** @brief Gets the results of the counters and resets them. - @param[out] avg The average of all the submitted numbers. @param[out] rms The Root Mean Square Average of all the submitted numbers. */ @@ -28,17 +26,16 @@ class AvgRmsCounter /** @brief Gets the current minimum value and resets it. - @return The minimum value recorded. */ double Min(); /** @brief Gets the current maximum value and resets it. - @return The maximum value recorded. */ double Max(); + private: int32_t counter; double avgAccumulator; @@ -49,4 +46,4 @@ class AvgRmsCounter } // namespace lime -#endif // LIME_AVGRMSCOUNTER_H \ No newline at end of file +#endif // LIME_AVGRMSCOUNTER_H diff --git a/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp b/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp index 0a7996420..767c40f11 100644 --- a/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp +++ b/src/lms7002_wxgui/lms7002_pnlRxTSP_view.cpp @@ -1847,7 +1847,8 @@ void lms7002_pnlRXTSP_view::OnbtnSetLPFClick(wxCommandEvent& event) { double bw; txtLPFBW->GetValue().ToDouble(&bw); - if (lmsControl->SetGFIRFilter(TRXDir::Rx, mChannel == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB, true, bw * 1e6) != OpStatus::SUCCESS) + if (lmsControl->SetGFIRFilter(TRXDir::Rx, mChannel == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB, true, bw * 1e6) != + OpStatus::SUCCESS) wxMessageBox(_("GFIR configuration failed"), _("Error")); UpdateGUI(); // API changes nco selection diff --git a/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp b/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp index c7caeeb27..347c3dbcf 100644 --- a/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp +++ b/src/lms7002_wxgui/lms7002_pnlTxTSP_view.cpp @@ -1649,7 +1649,8 @@ void lms7002_pnlTXTSP_view::OnbtnSetLPFClick(wxCommandEvent& event) double bw; txtLPFBW->GetValue().ToDouble(&bw); - if (lmsControl->SetGFIRFilter(TRXDir::Tx, mChannel == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB, true, bw * 1e6) != OpStatus::SUCCESS) + if (lmsControl->SetGFIRFilter(TRXDir::Tx, mChannel == 0 ? LMS7002M::Channel::ChA : LMS7002M::Channel::ChB, true, bw * 1e6) != + OpStatus::SUCCESS) wxMessageBox(_("GFIR configuration failed"), _("Error")); UpdateGUI(); // API changes nco selection } From cf1ae17bcc72bcf503d5d5d0e89ddbeb3f374f9f Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 20 Feb 2024 16:44:02 +0200 Subject: [PATCH 32/46] Fix Windows compile errors --- src/comms/USB/FT601/FT601.cpp | 12 ++++++------ src/comms/USB/FX3/FX3.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/comms/USB/FT601/FT601.cpp b/src/comms/USB/FT601/FT601.cpp index b88e159ab..753272322 100644 --- a/src/comms/USB/FT601/FT601.cpp +++ b/src/comms/USB/FT601/FT601.cpp @@ -170,7 +170,7 @@ int FT601::BeginDataXfer(uint8_t* buffer, uint32_t length, uint8_t endPointAddr) if (ftStatus != FT_IO_PENDING) { lime::error("ERROR BEGIN DATA TRANSFER %d", ftStatus); - context->used = false; + context->isTransferUsed = false; return -1; } @@ -186,7 +186,7 @@ bool FT601::WaitForXfer(int contextHandle, int32_t timeout_ms) USBTransferContext_FT601* context = &dynamic_cast(contexts)[contextHandle]; - if (!context->used) + if (!context->isTransferUsed) { return true; //there is nothing to wait for (signal wait finished) } @@ -209,7 +209,7 @@ int FT601::FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) } USBTransferContext_FT601* context = &dynamic_cast(contexts)[contextHandle]; - if (!context->used) + if (!context->isTransferUsed) { return 0; } @@ -229,7 +229,7 @@ int FT601::FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) } FT_ReleaseOverlapped(mFTHandle, context->inOvLap); - context->used = false; + context->isTransferUsed = false; return length; } @@ -241,10 +241,10 @@ void FT601::AbortEndpointXfers(uint8_t endPointAddr) { USBTransferContext_FT601* context = &dynamic_cast(contexts)[i]; - if (context->used && context->endPointAddr == endPointAddr) + if (context->isTransferUsed && context->endPointAddr == endPointAddr) { FT_ReleaseOverlapped(mFTHandle, context->inOvLap); - context->used = false; + context->isTransferUsed = false; } } diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index 152a1861d..8d899aaaf 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -291,7 +291,7 @@ bool FX3::WaitForXfer(int contextHandle, int32_t timeout_ms) USBTransferContext_FX3* FX3context = &static_cast(contexts)[contextHandle]; - if (!FX3context->used) + if (!FX3context->isTransferUsed) { return true; //there is nothing to wait for (signal wait finished) } @@ -309,7 +309,7 @@ int FX3::FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) USBTransferContext_FX3* FX3context = &static_cast(contexts)[contextHandle]; - if (!FX3context->used) + if (!FX3context->isTransferUsed) { return 0; } @@ -318,7 +318,7 @@ int FX3::FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) long len = length; bool status = FX3context->EndPt->FinishDataXfer(buffer, len, FX3context->inOvLap, FX3context->context); - FX3context->used = false; + FX3context->isTransferUsed = false; FX3context->Reset(); if (!status) @@ -355,7 +355,7 @@ void FX3::WaitForXfers(uint8_t endPointAddr) { USBTransferContext_FX3* FX3context = &static_cast(contexts)[i]; - if (FX3context->used && + if (FX3context->isTransferUsed && ((OutEndPt[i] && OutEndPt[i]->Address == endPointAddr) || (InEndPt[i] && InEndPt[i]->Address == endPointAddr))) { WaitForXfer(i, 250); From b364c01ab7947be27cd1a1b0e1dd9a33e41a1758 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Mon, 26 Feb 2024 09:14:12 +0200 Subject: [PATCH 33/46] clang-format --- src/boards/LMS7002M_SDRDevice.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/boards/LMS7002M_SDRDevice.cpp b/src/boards/LMS7002M_SDRDevice.cpp index 5401aeda5..9c9fe100f 100644 --- a/src/boards/LMS7002M_SDRDevice.cpp +++ b/src/boards/LMS7002M_SDRDevice.cpp @@ -1157,9 +1157,11 @@ OpStatus LMS7002M_SDRDevice::LMS7002ChannelCalibration(LMS7002M* chip, const SDR const SDRDevice::ChannelConfig& ch = config; // TODO: Don't configure GFIR when external ADC/DAC is used - if (ch.rx.enabled && chip->SetGFIRFilter(TRXDir::Rx, enumChannel, ch.rx.gfir.enabled, ch.rx.gfir.bandwidth) != OpStatus::SUCCESS) + if (ch.rx.enabled && + chip->SetGFIRFilter(TRXDir::Rx, enumChannel, ch.rx.gfir.enabled, ch.rx.gfir.bandwidth) != OpStatus::SUCCESS) return lime::ReportError(OpStatus::ERROR, "Rx ch%i GFIR config failed", i); - if (ch.tx.enabled && chip->SetGFIRFilter(TRXDir::Tx, enumChannel, ch.tx.gfir.enabled, ch.tx.gfir.bandwidth) != OpStatus::SUCCESS) + if (ch.tx.enabled && + chip->SetGFIRFilter(TRXDir::Tx, enumChannel, ch.tx.gfir.enabled, ch.tx.gfir.bandwidth) != OpStatus::SUCCESS) return lime::ReportError(OpStatus::ERROR, "Tx ch%i GFIR config failed", i); if (ch.rx.calibrate && ch.rx.enabled) From 6819411acdf7d7ffee1ecacada515ee929f7861d Mon Sep 17 00:00:00 2001 From: Dominykas Date: Mon, 26 Feb 2024 09:15:20 +0200 Subject: [PATCH 34/46] Fix Windows compile --- src/comms/USB/FX3/FX3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comms/USB/FX3/FX3.cpp b/src/comms/USB/FX3/FX3.cpp index 1ae8ad368..b7b853e2b 100644 --- a/src/comms/USB/FX3/FX3.cpp +++ b/src/comms/USB/FX3/FX3.cpp @@ -336,7 +336,7 @@ void FX3::AbortEndpointXfers(uint8_t endPointAddr) std::scoped_lock lock{ FX3mutex }; USBTransferContext_FX3* FX3context = &static_cast(contexts)[i]; - if (FX3context->used && FX3context->EndPt->Address == endPointAddr) + if (FX3context->isTransferUsed && FX3context->EndPt->Address == endPointAddr) { FX3context->EndPt->Abort(); } From b7d9df861298e5442dbbc99f283ff03d0c5faaec Mon Sep 17 00:00:00 2001 From: Dominykas Date: Mon, 26 Feb 2024 11:00:45 +0200 Subject: [PATCH 35/46] Add documentation for the freshly added changes --- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 1 + src/boards/MMX8/MM_X8.cpp | 1 + src/comms/USB/FT601/FT601.h | 3 +- src/comms/USB/FX3/FX3.h | 32 ++++--- src/include/limesuite/SDRDevice.h | 7 +- src/include/limesuite/complex.h | 108 +++++++++++++++++------ 6 files changed, 109 insertions(+), 43 deletions(-) diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index 089abac1d..e6dbc6da2 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -110,6 +110,7 @@ OpStatus LimeSDR_XTRX::LMS1_UpdateFPGAInterface(void* userData) /// @param spiRFsoc The communications port to the LMS7002M chip. /// @param spiFPGA The communications port to the device's FPGA. /// @param sampleStream The communications port to send and receive sample data. +/// @param control The serial port communication of the device. /// @param refClk The reference clock of the device. LimeSDR_XTRX::LimeSDR_XTRX(std::shared_ptr spiRFsoc, std::shared_ptr spiFPGA, diff --git a/src/boards/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index e7b14303c..14c792cbc 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -28,6 +28,7 @@ static double X8ReferenceClock = 30.72e6; /// @param spiLMS7002M The communications ports to the LMS7002M chips. /// @param spiFPGA The communications ports to the device's FPGA chips. /// @param trxStreams The communications ports to send and receive sample data. +/// @param control The serial port communication of the device. /// @param adfComms The communications port to the device's ADF4002 chip. LimeSDR_MMX8::LimeSDR_MMX8(std::vector>& spiLMS7002M, std::vector>& spiFPGA, diff --git a/src/comms/USB/FT601/FT601.h b/src/comms/USB/FT601/FT601.h index d46f1f6fd..32b50fc07 100644 --- a/src/comms/USB/FT601/FT601.h +++ b/src/comms/USB/FT601/FT601.h @@ -43,7 +43,6 @@ class FT601 : public USBGeneric virtual int FinishDataXfer(uint8_t* buffer, uint32_t length, int contextHandle) override; virtual void AbortEndpointXfers(uint8_t endPointAddr) override; #endif - virtual int GetUSBContextIndex() override; /** @brief Resets the stream buffers of the device. @@ -61,6 +60,8 @@ class FT601 : public USBGeneric int FT_FlushPipe(unsigned char ep); uint32_t mUsbCounter; #endif + + virtual int GetUSBContextIndex() override; }; } // namespace lime diff --git a/src/comms/USB/FX3/FX3.h b/src/comms/USB/FX3/FX3.h index 3fde96b6c..686248002 100644 --- a/src/comms/USB/FX3/FX3.h +++ b/src/comms/USB/FX3/FX3.h @@ -44,19 +44,25 @@ class FX3 : public USBGeneric override; #endif - static constexpr int CTR_W_REQCODE = 0xC1; - static constexpr int CTR_W_VALUE = 0x0000; - static constexpr int CTR_W_INDEX = 0x0000; - - static constexpr int CTR_R_REQCODE = 0xC0; - static constexpr int CTR_R_VALUE = 0x0000; - static constexpr int CTR_R_INDEX = 0x0000; - - static constexpr uint8_t CONTROL_BULK_OUT_ADDRESS = 0x0F; - static constexpr uint8_t CONTROL_BULK_IN_ADDRESS = 0x8F; - - static constexpr uint8_t STREAM_BULK_OUT_ADDRESS = 0x01; - static constexpr uint8_t STREAM_BULK_IN_ADDRESS = 0x81; + static constexpr int CTR_W_REQCODE = + 0xC1; ///< The request field of the setup packet for the write operation for a control transfer. + static constexpr int CTR_W_VALUE = 0x0000; ///< The value of the setup packet for the write operation for a control transfer. + static constexpr int CTR_W_INDEX = 0x0000; ///< The index of the setup packet for the write operation for a control transfer. + + static constexpr int CTR_R_REQCODE = + 0xC0; ///< The request field of the setup packet for the read operation for a control transfer. + static constexpr int CTR_R_VALUE = + 0x0000; ///< The value field of the setup packet for the read operation for a control transfer. + static constexpr int CTR_R_INDEX = + 0x0000; ///< The index field of the setup packet for the read operation for a control transfer. + + static constexpr uint8_t CONTROL_BULK_OUT_ADDRESS = + 0x0F; ///< The memory address for writing information via the bulk transfer protocol. + static constexpr uint8_t CONTROL_BULK_IN_ADDRESS = + 0x8F; ///< THe memory address for reading information via the bulk transfer protocol. + + static constexpr uint8_t STREAM_BULK_OUT_ADDRESS = 0x01; ///< The memory address to which to write the samples to broadcast. + static constexpr uint8_t STREAM_BULK_IN_ADDRESS = 0x81; ///< The memory address from which to read the incoming samples. protected: virtual int GetUSBContextIndex() override; diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index 1585bce68..64de7211b 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -268,12 +268,17 @@ class LIME_API SDRDevice /// @brief The enumeration describing the scale of the test signal. enum class Scale : uint8_t { Full, Half }; - complex16_t dcValue; + complex16_t dcValue; ///< The value to use when in DC mode. Divide divide; ///< The current divide of the test signal. Scale scale; ///< The current scale of the test signal. bool enabled; ///< Denotes whether test mode is enabled or not. bool dcMode; ///< The DC mode of the test mode. + /// @brief The constructor for the Test Signal storage class. + /// @param enabled Whether the test signal is enabled or not. + /// @param dcMode Whether the DC mode is enabled or not. + /// @param divide The divide mode of the test signal. + /// @param scale The scale of the dest signal. TestSignal(bool enabled = false, bool dcMode = false, Divide divide = Divide::Div8, Scale scale = Scale::Half) : dcValue(0, 0) , divide(divide) diff --git a/src/include/limesuite/complex.h b/src/include/limesuite/complex.h index 902811c42..ef7b22c53 100644 --- a/src/include/limesuite/complex.h +++ b/src/include/limesuite/complex.h @@ -5,15 +5,24 @@ namespace lime { -/** @brief Structure to hold a 12 bit integer complex number. */ +/// @brief Structure to hold a 12 bit integer complex number. struct complex12compressed_t { - complex12compressed_t() + constexpr complex12compressed_t() : complex12compressed_t(0, 0) { } - complex12compressed_t(int16_t i, int16_t q) { Set(i, q); } - int16_t real() const + /// @brief Constructs the 12 bit compressed complex number. + /// @param i The I value of the number. + /// @param q The Q value of the number. + constexpr complex12compressed_t(int16_t i, int16_t q) + : data{ 0, 0, 0 } + { + Set(i, q); + } + + /// @copydoc POD_complex_t::real() + constexpr int16_t real() const { int16_t value = data[0]; value |= (data[1] << 8); @@ -22,13 +31,16 @@ struct complex12compressed_t { value >>= 4; return value; } - void real(int16_t value) + + /// @copydoc POD_complex_t::real(T) + constexpr void real(int16_t value) { data[0] = value; data[1] = (data[1] & 0xF0) | ((value >> 8) & 0x0F); } - int16_t imag() const + /// @copydoc POD_complex_t::imag() + constexpr int16_t imag() const { int16_t value = data[1]; value |= (data[2] << 8); @@ -36,57 +48,83 @@ struct complex12compressed_t { value >>= 4; return value; } - void imag(int16_t value) + + /// @copydoc POD_complex_t::imag(T) + constexpr void imag(int16_t value) { data[1] = (value << 4) | (data[1] & 0x0F); data[2] = value >> 4; } - void Set(int16_t i, int16_t q) + /// @copydoc POD_complex_t::Set() + constexpr void Set(int16_t ival, int16_t qval) { - data[0] = i; - data[1] = (q << 4) | ((i >> 8) & 0x0F); - data[2] = q >> 4; + data[0] = ival; + data[1] = (qval << 4) | ((ival >> 8) & 0x0F); + data[2] = qval >> 4; } private: uint8_t data[3]; }; -// complex number structure for plain data types (int, float...) +/// @brief Complex number structure for plain data types (int, float...) +/// @tparam T The type of the number to hold. template struct POD_complex_t { - POD_complex_t() + constexpr POD_complex_t() : POD_complex_t(0, 0) { } - POD_complex_t(T real, T imag) + + /// @brief Constructs the complex number with the specified values. + /// @param real The I value of the number. + /// @param imag The Q value of the number. + constexpr POD_complex_t(T real, T imag) : i(real) , q(imag) { } - T real() const { return i; } - void real(T value) { i = value; } - T imag() const { return q; } - void imag(T value) { q = value; } + /// @brief Gets the I (real) value of the complex number. + /// @return The I value of the complex number. + constexpr T real() const { return i; } + + /// @brief Sets the I (real) value of the complex number. + /// @param value The value to set the complex number's I component to. + constexpr void real(T value) { i = value; } + + /// @brief Gets the Q (imaginary) value of the complex number. + /// @return The Q value of the complex number. + constexpr T imag() const { return q; } - void Set(T ival, T qval) + /// @brief Sets the Q (imaginary) value of the complex number. + /// @param value The value to set the complex number's Q component to. + constexpr void imag(T value) { q = value; } + + /// @brief Sets both values of the complex number. + /// @param ival The I (real) component of the complex number. + /// @param qval The Q (imaginary) component of the complex number. + constexpr void Set(T ival, T qval) { i = ival; q = qval; } - T i; - T q; + T i; ///< The I component of the number. + T q; ///< The Q component of the number. }; /** @brief Structure to hold a 16 bit integer complex number. */ struct complex16_t : public POD_complex_t { - complex16_t() + constexpr complex16_t() : complex16_t(0, 0) { } - complex16_t(int16_t re, int16_t im) + + /// @brief Constructs the 16 bit integer complex number. + /// @param re The I (real) component of the number. + /// @param im The Q (imaginary) component of the number. + constexpr complex16_t(int16_t re, int16_t im) : POD_complex_t(re, im) { } @@ -94,20 +132,34 @@ struct complex16_t : public POD_complex_t { /** @brief Structure to hold a 32 bit float complex number. */ struct complex32f_t : public POD_complex_t { - complex32f_t() + constexpr complex32f_t() : complex32f_t(0, 0) { } - complex32f_t(float re, float im) + + /// @brief Constructs the 32 bit floating-point complex number. + /// @param re The I (real) component of the number. + /// @param im The Q (imaginary) component of the number. + constexpr complex32f_t(float re, float im) : POD_complex_t(re, im) { } }; /** @brief Structure to hold a 64 bit float complex number. */ -struct complex64f_t { - double i; ///< The I component of the number. - double q; ///< The Q component of the number. +struct complex64f_t : public POD_complex_t { + constexpr complex64f_t() + : complex64f_t(0, 0) + { + } + + /// @brief Constructs the 64 bit floating-point complex number. + /// @param re The I (real) component of the number. + /// @param im The Q (imaginary) component of the number. + constexpr complex64f_t(double re, double im) + : POD_complex_t(re, im) + { + } }; } // namespace lime From bf7e993afe556c0bb9e84d083b5c7c490a4e1eba Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 5 Mar 2024 13:04:54 +0200 Subject: [PATCH 36/46] Fix (mis)documentations --- src/FPGA_common/FPGA_common.cpp | 1 - src/SDRDevice.cpp | 51 ------------------------------- src/include/limesuite/SDRDevice.h | 4 +++ 3 files changed, 4 insertions(+), 52 deletions(-) delete mode 100644 src/SDRDevice.cpp diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 3e3770115..693909e74 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -445,7 +445,6 @@ OpStatus FPGA::SetPllClock(uint8_t clockIndex, int nSteps, bool waitLock, bool d @param pllIndex Index of FPGA PLL. @param inputFreq Input frequency. @param clocks List of clocks to configure. - @param clockCount Number of clocks to configure. @return The operation status. */ OpStatus FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, std::vector& clocks) diff --git a/src/SDRDevice.cpp b/src/SDRDevice.cpp deleted file mode 100644 index 78351c6b2..000000000 --- a/src/SDRDevice.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "limesuite/SDRDevice.h" - -using namespace lime; - -SDRDevice::StreamConfig::Extras::Extras() -{ - memset(this, 0, sizeof(Extras)); - usePoll = true; -}; - -SDRDevice::StreamConfig::StreamConfig() -{ - memset(this, 0, sizeof(StreamConfig)); -} - -SDRDevice::StreamConfig::~StreamConfig() -{ - if (extraConfig) - delete extraConfig; -} - -SDRDevice::StreamConfig& SDRDevice::StreamConfig::operator=(const SDRDevice::StreamConfig& src) -{ - if (this == &src) - return *this; - - if (extraConfig) - { - delete extraConfig; - extraConfig = nullptr; - } - memcpy(this, &src, sizeof(SDRDevice::StreamConfig)); - if (src.extraConfig) - { - this->extraConfig = new Extras(); - *this->extraConfig = *src.extraConfig; - } - return *this; -} - -void SDRDevice::StreamStart(const std::vector moduleIndexes) -{ - for (uint8_t i : moduleIndexes) - StreamStart(i); -}; - -void SDRDevice::StreamStop(const std::vector moduleIndexes) -{ - for (uint8_t i : moduleIndexes) - StreamStop(i); -}; \ No newline at end of file diff --git a/src/include/limesuite/SDRDevice.h b/src/include/limesuite/SDRDevice.h index 8ed8b5078..b5d2ea906 100644 --- a/src/include/limesuite/SDRDevice.h +++ b/src/include/limesuite/SDRDevice.h @@ -715,12 +715,16 @@ class LIME_API SDRDevice /// @param moduleIndex The index of the device to start the streams on. virtual void StreamStart(uint8_t moduleIndex) = 0; + /// @brief Starts all the set up streams on the devices. + /// @param moduleIndexes The indices of the devices to start the streams on. virtual void StreamStart(const std::vector moduleIndexes); /// @brief Stops all the set up streams on the device. /// @param moduleIndex The index of the device to stop the streams on. virtual void StreamStop(uint8_t moduleIndex) = 0; + /// @brief Stops all the set up streams on the devices. + /// @param moduleIndexes The indices of the devices to stop the streams on. virtual void StreamStop(const std::vector moduleIndexes); /// @brief Reveives samples from all the active streams in the device. From 519defb7aabeebb854bcf1c464edc4a464e32d74 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 5 Mar 2024 13:14:21 +0200 Subject: [PATCH 37/46] Add missing extern C comment --- src/mcu_program/common_src/lms7002m_filters.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mcu_program/common_src/lms7002m_filters.c b/src/mcu_program/common_src/lms7002m_filters.c index 0510aa2da..83cf5c5de 100644 --- a/src/mcu_program/common_src/lms7002m_filters.c +++ b/src/mcu_program/common_src/lms7002m_filters.c @@ -867,5 +867,5 @@ TxFilterSearchEndStage : { } #ifdef __cplusplus -} +} // extern C #endif From ff565541bcbfb691786b80737307bc96bac44d05 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 5 Mar 2024 13:17:44 +0200 Subject: [PATCH 38/46] Fix unnecessary // clang-format off --- amarisoft-plugin/gainTable.h | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/amarisoft-plugin/gainTable.h b/amarisoft-plugin/gainTable.h index 3d84e6bba..b88ffeea6 100644 --- a/amarisoft-plugin/gainTable.h +++ b/amarisoft-plugin/gainTable.h @@ -2,15 +2,12 @@ #include -// clang-format off - struct RxGainRow { int lna; int pga; }; - -static std::array rxGainTable{{ +static std::array rxGainTable{ { { 1, 12 }, { 1, 13 }, { 2, 12 }, @@ -61,15 +58,15 @@ static std::array rxGainTable{{ { 15, 28 }, { 15, 29 }, { 15, 30 }, - { 15, 31 } -}}; + { 15, 31 }, +} }; struct TxGainRow { int main; int lin; }; -static std::array txGainTable{{ +static std::array txGainTable{ { { 30, 30 }, { 30, 30 }, { 29, 29 }, @@ -120,7 +117,5 @@ static std::array txGainTable{{ { 3, 3 }, { 2, 2 }, { 1, 1 }, - { 0, 0 } -}}; - -// clang-format on + { 0, 0 }, +} }; From 5980b60531252e7e652518b03bb0e3eadb60ac38 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Tue, 5 Mar 2024 14:27:03 +0200 Subject: [PATCH 39/46] Document undocumented parameters in otherwise documented functions --- src/ADF4002/ADF4002.cpp | 1 + src/FPGA_common/FPGA_common.cpp | 40 ++++++++++++++++++++++++--------- src/lms7002m/MCU_BD.cpp | 8 +++++-- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/ADF4002/ADF4002.cpp b/src/ADF4002/ADF4002.cpp index 928875b6b..4c574c5be 100644 --- a/src/ADF4002/ADF4002.cpp +++ b/src/ADF4002/ADF4002.cpp @@ -326,6 +326,7 @@ void ADF4002::CalculateRN() } /** @brief Writes configuration to chip + * @param data The data to write to the chip. */ void ADF4002::GetConfig(unsigned char data[12]) { diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 693909e74..faca67f27 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -663,8 +663,14 @@ OpStatus FPGA::SetDirectClocking(int clockIndex) return OpStatus::SUCCESS; } -/** @brief Parses FPGA packet payload into samples -*/ +/** @brief Parses FPGA packet payload into samples. + @param buffer The buffer to parse. + @param bufLen The length of the buffer to parse. + @param mimo Whether the payload contains multiple (two) channels. + @param compressed Whether the samples are in 12-bit (true) or 16-bit (false) integer format. + @param samples The output buffer of the samples. + @return The amount of samples parsed. + */ int FPGA::FPGAPacketPayload2Samples(const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex16_t* const* samples) { if (compressed) //compressed samples @@ -714,8 +720,14 @@ int FPGA::FPGAPacketPayload2Samples(const uint8_t* buffer, int bufLen, bool mimo return bufLen / sizeof(complex16_t); } -/** @brief Parses FPGA packet payload into samples -*/ +/** @brief Parses FPGA packet payload into samples. + @param buffer The buffer to parse. + @param bufLen The length of the buffer to parse. + @param mimo Whether the payload contains multiple (two) channels. + @param compressed Whether the samples are in 12-bit (true) or 16-bit (false) integer format. + @param samples The output buffer of the samples. + @return The amount of samples parsed. + */ int FPGA::FPGAPacketPayload2SamplesFloat( const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex32f_t* const* samples) { @@ -867,6 +879,11 @@ int FPGA::Samples2FPGAPacketPayload( } /// @brief Configures FPGA PLLs to LimeLight interface frequency. +/// @param txRate_Hz The transmit rate (in Hz). +/// @param rxRate_Hz The receive rate (in Hz). +/// @param txPhase The transmit phase offset (in degrees). +/// @param rxPhase The receive phase offset (in degrees). +/// @param chipIndex The chip to configure. /// @return The operation status. OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase, int chipIndex) { @@ -918,14 +935,17 @@ OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPha return status; } -/** @brief Configures FPGA PLLs to LimeLight interface frequency -*/ -OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int channel) +/// @brief Configures FPGA PLLs to LimeLight interface frequency. +/// @param txRate_Hz The transmit rate (in Hz). +/// @param rxRate_Hz The receive rate (in Hz). +/// @param chipIndex The chip to configure. +/// @return The operation status. +OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int chipIndex) { - lime::debug("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz channel:%i", txRate_Hz / 1e6, rxRate_Hz / 1e6, channel); - SelectModule(channel); + lime::debug("FPGA::SetInterfaceFreq tx:%.3f MHz rx:%.3f MHz channel:%i", txRate_Hz / 1e6, rxRate_Hz / 1e6, chipIndex); + SelectModule(chipIndex); //PrintStackTrace(); - const int pll_ind = (channel == 1) ? 2 : 0; + const int pll_ind = (chipIndex == 1) ? 2 : 0; const int txPLLindex = pll_ind; const int rxPLLindex = txPLLindex + 1; OpStatus status = OpStatus::SUCCESS; diff --git a/src/lms7002m/MCU_BD.cpp b/src/lms7002m/MCU_BD.cpp index 63321e9cd..b97090894 100644 --- a/src/lms7002m/MCU_BD.cpp +++ b/src/lms7002m/MCU_BD.cpp @@ -471,7 +471,9 @@ void MCU_BD::Wait_CLK_Cycles(int delay) } /** @brief Upload program code from memory into MCU - @return 0:success, -1:failed + * @param m_iMode1 The high bit of the mode + * @param m_iMode0 The low bit of the mode + * @return 0:success, -1:failed */ int MCU_BD::Program_MCU(int m_iMode1, int m_iMode0) { @@ -958,6 +960,7 @@ std::string MCU_BD::GetProgramFilename() const } /** @brief Starts algorithm in MCU + * @param id The ID of the procedure to execute */ void MCU_BD::RunProcedure(uint8_t id) { @@ -974,7 +977,8 @@ void MCU_BD::RunProcedure(uint8_t id) } /** @brief Waits for MCU to finish executing program -@return 0 success, 255 idle, 244 running, else algorithm status + * @param timeout_ms The timeout to wait for (in ms) + * @return 0 success, 255 idle, 244 running, else algorithm status */ int MCU_BD::WaitForMCU(uint32_t timeout_ms) { From 053dd0c2822a89234200777445c00cf31d183b50 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 7 Mar 2024 10:34:45 +0200 Subject: [PATCH 40/46] Fix a broken function --- src/Si5351C/Si5351C.cpp | 7 +++---- src/Si5351C/Si5351C.h | 2 +- src/Si5351C/Si5351C_wxgui.h | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Si5351C/Si5351C.cpp b/src/Si5351C/Si5351C.cpp index 4ffde26f1..144724355 100644 --- a/src/Si5351C/Si5351C.cpp +++ b/src/Si5351C/Si5351C.cpp @@ -573,7 +573,7 @@ Si5351C::Status Si5351C::UploadConfiguration() @brief Loads register values for Si5356A from file @param FName input filename */ -bool Si5351C::LoadRegValuesFromFile(string FName) +void Si5351C::LoadRegValuesFromFile(string FName) { fstream fin; fin.open(FName, ios::in); @@ -587,16 +587,15 @@ bool Si5351C::LoadRegValuesFromFile(string FName) while (!fin.eof()) { fin.getline(line, len); - if (line[0] == '#') - continue; if (strcmp(line, "#END_PROFILE") == 0) break; + if (line[0] == '#') + continue; sscanf(line, "%i,%x", &addr, &value); m_newConfiguration[addr] = value; } fin.close(); - return false; } /** @brief Calculates multisynth dividers and VCO frequencies diff --git a/src/Si5351C/Si5351C.h b/src/Si5351C/Si5351C.h index 54a25254e..8325c199f 100644 --- a/src/Si5351C/Si5351C.h +++ b/src/Si5351C/Si5351C.h @@ -96,7 +96,7 @@ class LIME_API Si5351C Si5351C(II2C& i2c_comms); ~Si5351C(); - bool LoadRegValuesFromFile(std::string FName); + void LoadRegValuesFromFile(std::string FName); void SetPLL(unsigned char id, unsigned long CLKIN_Hz, int CLK_SRC); void SetClock(unsigned char id, unsigned long fOut_Hz, bool enabled = true, bool inverted = false); diff --git a/src/Si5351C/Si5351C_wxgui.h b/src/Si5351C/Si5351C_wxgui.h index 2be7344dd..bb0642870 100644 --- a/src/Si5351C/Si5351C_wxgui.h +++ b/src/Si5351C/Si5351C_wxgui.h @@ -140,7 +140,6 @@ class Si5351C_wxgui : public wxFrame void OnButton1Click(wxCommandEvent& event); void OnbtnReadStatusClick(wxCommandEvent& event); void OnbtnClearStatusClick(wxCommandEvent& event); - bool LoadRegValuesFromFile(std::string FName); unsigned char m_newConfiguration[255]; lime::SDRDevice* device; //*) From e892d29f78551ff69c265e7eb3768ad4a1238f6d Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 7 Mar 2024 10:35:29 +0200 Subject: [PATCH 41/46] Fix undocumented return values on otherwise documented functions --- src/Si5351C/Si5351C.cpp | 4 +++- src/lms7002m/MCU_BD.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Si5351C/Si5351C.cpp b/src/Si5351C/Si5351C.cpp index 144724355..581f60c8e 100644 --- a/src/Si5351C/Si5351C.cpp +++ b/src/Si5351C/Si5351C.cpp @@ -526,7 +526,9 @@ Si5351C::~Si5351C() { } -/** @brief Sends Configuration to Si5351C +/** + * @brief Sends Configuration to Si5351C + * @return The status code of the operation */ Si5351C::Status Si5351C::UploadConfiguration() { diff --git a/src/lms7002m/MCU_BD.cpp b/src/lms7002m/MCU_BD.cpp index b97090894..1c5f00e15 100644 --- a/src/lms7002m/MCU_BD.cpp +++ b/src/lms7002m/MCU_BD.cpp @@ -925,7 +925,9 @@ int MCU_BD::RunInstr_MCU(unsigned short* pPCVAL) return retval; } -/** @brief Returns information about programming or reading data progress +/** + * @brief Returns information about programming or reading data progress + * @returns The structure containing information about the progress info. */ MCU_BD::ProgressInfo MCU_BD::GetProgressInfo() const { From 9ef418a192bcaff1d3fbc1c6f8fb97abbf24765c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominykas=20Petkevi=C4=8Dius?= Date: Fri, 8 Mar 2024 11:19:01 +0200 Subject: [PATCH 42/46] Fix minor typo --- src/include/limesuite/LMS7002M.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/limesuite/LMS7002M.h b/src/include/limesuite/LMS7002M.h index 6e6732a69..4dff2cd96 100644 --- a/src/include/limesuite/LMS7002M.h +++ b/src/include/limesuite/LMS7002M.h @@ -632,7 +632,7 @@ class LIME_API LMS7002M /*! * @brief Uploads given FIR coefficients to chip * @param dir Transmitter or receiver selection - * @param gfirIndex GIR index from 0 to 2 + * @param gfirIndex GFIR index from 0 to 2 * @param coef array of coefficients (normalized from -1 to 1) * @param coefCount number of coefficients * @return The status of the operation From 57750a1240a562f610d4718b936960ab49511646 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 14 Mar 2024 13:03:35 +0200 Subject: [PATCH 43/46] Fix misdocumentation --- src/ADF4002/ADF4002.cpp | 4 ++-- src/boards/LimeSDR_X3/LimeSDR_X3.cpp | 4 ++-- src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp | 4 ++-- src/boards/MMX8/MM_X8.cpp | 5 +++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/ADF4002/ADF4002.cpp b/src/ADF4002/ADF4002.cpp index 4c574c5be..8c3ed4602 100644 --- a/src/ADF4002/ADF4002.cpp +++ b/src/ADF4002/ADF4002.cpp @@ -325,8 +325,8 @@ void ADF4002::CalculateRN() lblFvco = dFvco; } -/** @brief Writes configuration to chip - * @param data The data to write to the chip. +/** @brief Gets the configuration from chip + * @param data The data to read from the chip. */ void ADF4002::GetConfig(unsigned char data[12]) { diff --git a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp index 9b94a49a6..d5fc6d2b7 100644 --- a/src/boards/LimeSDR_X3/LimeSDR_X3.cpp +++ b/src/boards/LimeSDR_X3/LimeSDR_X3.cpp @@ -156,8 +156,6 @@ OpStatus LimeSDR_X3::LMS1_UpdateFPGAInterface(void* userData) /// @brief Constructs a new LimeSDR_X3 object /// -/// Do not perform any unnecessary configuring to device in constructor, so you -/// could read back it's state for debugging purposes /// @param spiLMS7002M The communications port to the LMS7002M chips. /// @param spiFPGA The communications port to the device's FPGA. /// @param trxStreams The communications ports to send and receive sample data. @@ -171,6 +169,8 @@ LimeSDR_X3::LimeSDR_X3(std::shared_ptr spiLMS7002M, , mfpgaPort(spiFPGA) , mConfigInProgress(false) { + /// Do not perform any unnecessary configuring to device in constructor, so you + /// could read back it's state for debugging purposes SDRDevice::Descriptor& desc = mDeviceDescriptor; LMS64CProtocol::FirmwareInfo fw; diff --git a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp index 981c23d2b..dc85aa73d 100644 --- a/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp +++ b/src/boards/LimeSDR_XTRX/LimeSDR_XTRX.cpp @@ -105,8 +105,6 @@ OpStatus LimeSDR_XTRX::LMS1_UpdateFPGAInterface(void* userData) /// @brief Constructs a new LimeSDR_XTRX object /// -/// Do not perform any unnecessary configuring to device in constructor, so you -/// could read back it's state for debugging purposes. /// @param spiRFsoc The communications port to the LMS7002M chip. /// @param spiFPGA The communications port to the device's FPGA. /// @param sampleStream The communications port to send and receive sample data. @@ -124,6 +122,8 @@ LimeSDR_XTRX::LimeSDR_XTRX(std::shared_ptr spiRFsoc, , mSerialPort(control) , mConfigInProgress(false) { + /// Do not perform any unnecessary configuring to device in constructor, so you + /// could read back it's state for debugging purposes. SDRDevice::Descriptor& desc = mDeviceDescriptor; desc.name = GetDeviceName(LMS_DEV_LIMESDR_XTRX); diff --git a/src/boards/MMX8/MM_X8.cpp b/src/boards/MMX8/MM_X8.cpp index 12e1167ca..655105208 100644 --- a/src/boards/MMX8/MM_X8.cpp +++ b/src/boards/MMX8/MM_X8.cpp @@ -23,8 +23,6 @@ static double X8ReferenceClock = 30.72e6; /// @brief Constructs the LimeSDR_MMX8 object. /// -/// Do not perform any unnecessary configuring to device in constructor, so you -/// could read back it's state for debugging purposes /// @param spiLMS7002M The communications ports to the LMS7002M chips. /// @param spiFPGA The communications ports to the device's FPGA chips. /// @param trxStreams The communications ports to send and receive sample data. @@ -37,6 +35,9 @@ LimeSDR_MMX8::LimeSDR_MMX8(std::vector>& spiLMS7002M, std::shared_ptr adfComms) : mTRXStreamPorts(trxStreams) { + /// Do not perform any unnecessary configuring to device in constructor, so you + /// could read back it's state for debugging purposes + mMainFPGAcomms = spiFPGA[8]; SDRDevice::Descriptor& desc = mDeviceDescriptor; desc.name = GetDeviceName(LMS_DEV_LIMESDR_MMX8); From 41c252ffdead930418d86e47f2fe97d3dc528393 Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 14 Mar 2024 13:06:02 +0200 Subject: [PATCH 44/46] Extract IntToChannel to a function --- src/lms7002m/LMS7002M.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/lms7002m/LMS7002M.cpp b/src/lms7002m/LMS7002M.cpp index 4e3a708d5..8d76a70da 100644 --- a/src/lms7002m/LMS7002M.cpp +++ b/src/lms7002m/LMS7002M.cpp @@ -43,6 +43,11 @@ constexpr std::array, 3> LMS7002M::gVCO_frequency_tabl }; constexpr std::array LMS7002M::gCGEN_VCO_frequencies{ 1930e6, 2940e6 }; +constexpr LMS7002M::Channel IntToChannel(int channel) +{ + return channel > 0 ? LMS7002M::Channel::ChB : LMS7002M::Channel::ChA; +} + /// Define for parameter enumeration if prefix might be needed extern std::vector> LMS7parameterList; @@ -144,7 +149,7 @@ class ChannelScope { assert(index < 2); mStoredValue = chip->GetActiveChannel(!useCache); - auto expectedChannel = index > 0 ? LMS7002M::Channel::ChB : LMS7002M::Channel::ChA; + auto expectedChannel = IntToChannel(index); if (mStoredValue == expectedChannel) return; @@ -283,7 +288,7 @@ OpStatus LMS7002M::EnableChannel(TRXDir dir, const uint8_t channel, const bool e { ChannelScope scope(this, channel, false); - const Channel ch = channel > 0 ? Channel::ChB : Channel::ChA; + const Channel ch = IntToChannel(channel); const bool isTx = dir == TRXDir::Tx; //--- LML --- @@ -1358,7 +1363,7 @@ OpStatus LMS7002M::SetFrequencyCGEN(const float_type freq_Hz, const bool retainN txModeNCO = Get_SPI_Reg_bits(LMS7param(MODE_TX), true); for (int ch = 0; ch < 2; ++ch) { - this->SetActiveChannel((ch == 0) ? Channel::ChA : Channel::ChB); + this->SetActiveChannel(IntToChannel(ch)); for (int i = 0; i < 16 && rxModeNCO == 0; ++i) rxNCO[ch].push_back(GetNCOFrequency(TRXDir::Rx, i, false)); for (int i = 0; i < 16 && txModeNCO == 0; ++i) @@ -1402,7 +1407,7 @@ OpStatus LMS7002M::SetFrequencyCGEN(const float_type freq_Hz, const bool retainN //recalculate NCO for (int ch = 0; ch < 2 && retainNCOfrequencies; ++ch) { - this->SetActiveChannel((ch == 0) ? Channel::ChA : Channel::ChB); + this->SetActiveChannel(IntToChannel(ch)); for (int i = 0; i < 16 && rxModeNCO == 0; ++i) SetNCOFrequency(TRXDir::Rx, i, rxNCO[ch][i]); for (int i = 0; i < 16 && txModeNCO == 0; ++i) From ad9eefecadb286ba8480647f5424546a705f66eb Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 14 Mar 2024 13:06:44 +0200 Subject: [PATCH 45/46] Fix FPGA functionality changes --- src/FPGA_common/FPGA_common.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/FPGA_common/FPGA_common.cpp b/src/FPGA_common/FPGA_common.cpp index 471caba4a..cf3669857 100644 --- a/src/FPGA_common/FPGA_common.cpp +++ b/src/FPGA_common/FPGA_common.cpp @@ -11,6 +11,8 @@ #include #include "samplesConversion.h" +using namespace std; + #ifndef NDEBUG #define ASSERT_WARNING(cond, message) \ if (!cond) \ @@ -356,8 +358,8 @@ OpStatus FPGA::ResetTimestamp() OpStatus FPGA::WaitTillDone(uint16_t pollAddr, uint16_t doneMask, uint16_t errorMask, const std::string& title) { - const auto timeout = std::chrono::seconds(3); - auto t1 = std::chrono::high_resolution_clock::now(); + const auto timeout = chrono::seconds(3); + auto t1 = chrono::high_resolution_clock::now(); bool done = false; uint16_t error = 0; if (!title.empty()) @@ -850,6 +852,7 @@ OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPha txPhase, rxPhase, chipIndex); + SelectModule(chipIndex); OpStatus status = OpStatus::SUCCESS; const uint32_t addr = 0x002A; @@ -931,7 +934,7 @@ OpStatus FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int chipInde } if (!phaseSearch) - return SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz); + return SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz, chipIndex); std::vector dataRdA; std::vector dataRdB; From e0b3ed5335de63a3b23f8eba186b61e32b8a4b1c Mon Sep 17 00:00:00 2001 From: Dominykas Date: Thu, 14 Mar 2024 13:08:17 +0200 Subject: [PATCH 46/46] Decouple SamplesPacket from SDRDevice --- src/comms/PCIe/TRXLooper_PCIE.cpp | 6 +++--- src/comms/PCIe/TxBufferManager.h | 6 +++--- src/comms/USB/TRXLooper_USB.cpp | 6 +++--- src/protocols/SamplesPacket.h | 11 +++++------ src/protocols/TRXLooper.cpp | 24 ++++++------------------ 5 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/comms/PCIe/TRXLooper_PCIE.cpp b/src/comms/PCIe/TRXLooper_PCIE.cpp index 019e7ad2d..1e158fb12 100644 --- a/src/comms/PCIe/TRXLooper_PCIE.cpp +++ b/src/comms/PCIe/TRXLooper_PCIE.cpp @@ -290,10 +290,10 @@ void TRXLooper_PCIE::TransmitPacketsLoop() } // drop old packets before forming, Rx is needed to get current timestamp - if (srcPkt->metadata.waitForTimestamp && mConfig.channels.at(lime::TRXDir::Rx).size() > 0) + if (srcPkt->useTimestamp && mConfig.channels.at(lime::TRXDir::Rx).size() > 0) { int64_t rxNow = mRx.lastTimestamp.load(std::memory_order_relaxed); - const int64_t txAdvance = srcPkt->metadata.timestamp - rxNow; + const int64_t txAdvance = srcPkt->timestamp - rxNow; if (mConfig.hintSampleRate) { int64_t timeAdvance = ts_to_us(mConfig.hintSampleRate, txAdvance); @@ -713,7 +713,7 @@ void TRXLooper_PCIE::ReceivePacketsLoop() uint8_t* buffer = dmaBuffers[dma.swIndex % bufferCount]; const FPGA_RxDataPacket* pkt = reinterpret_cast(buffer); if (outputPkt) - outputPkt->metadata.timestamp = pkt->counter; + outputPkt->timestamp = pkt->counter; const int srcPktCount = mRxArgs.packetsToBatch; for (int i = 0; i < srcPktCount; ++i) diff --git a/src/comms/PCIe/TxBufferManager.h b/src/comms/PCIe/TxBufferManager.h index 2aff32fc4..92d59a5b4 100644 --- a/src/comms/PCIe/TxBufferManager.h +++ b/src/comms/PCIe/TxBufferManager.h @@ -86,11 +86,11 @@ template class TxBufferManager payloadSize = 0; } - header->ignoreTimestamp(!src->metadata.waitForTimestamp); + header->ignoreTimestamp(!src->useTimestamp); if (payloadSize == 0) { ++packetsCreated; - header->counter = src->metadata.timestamp; + header->counter = src->timestamp; bytesUsed += sizeof(StreamHeader); } const uint32_t freeSpace = std::min(maxPayloadSize - payloadSize, mCapacity - bytesUsed - 16); @@ -138,7 +138,7 @@ template class TxBufferManager } if (!hasSpace()) return true; - return src->metadata.flushPartialPacket || sendBuffer; + return src->flush || sendBuffer; } /// @brief Gets the current size of the transfer. diff --git a/src/comms/USB/TRXLooper_USB.cpp b/src/comms/USB/TRXLooper_USB.cpp index 79bfeb17c..0d4a563cf 100644 --- a/src/comms/USB/TRXLooper_USB.cpp +++ b/src/comms/USB/TRXLooper_USB.cpp @@ -191,11 +191,11 @@ void TRXLooper_USB::TransmitPacketsLoop() { header->Clear(); ++packetsCreated; - header->counter = srcPkt->metadata.timestamp; + header->counter = srcPkt->timestamp; bytesUsed += sizeof(StreamHeader); } - header->ignoreTimestamp(!srcPkt->metadata.waitForTimestamp); + header->ignoreTimestamp(!srcPkt->useTimestamp); const uint32_t freeSpace = std::min(maxPayloadSize - payloadSize, bufferSize - bytesUsed); uint32_t transferCount = std::min(freeSpace / bytesForFrame, static_cast(srcPkt->size())); @@ -234,7 +234,7 @@ void TRXLooper_USB::TransmitPacketsLoop() payloadSize = 0; packetsCreated = 0; - mTx.stats.timestamp = srcPkt->metadata.timestamp; + mTx.stats.timestamp = srcPkt->timestamp; header = reinterpret_cast(&buffers[bufferIndex * bufferSize]); payloadPtr = reinterpret_cast(header) + sizeof(StreamHeader); diff --git a/src/protocols/SamplesPacket.h b/src/protocols/SamplesPacket.h index f10633551..ad0e9225f 100644 --- a/src/protocols/SamplesPacket.h +++ b/src/protocols/SamplesPacket.h @@ -4,8 +4,6 @@ #include #include -#include "limesuite/SDRDevice.h" - namespace lime { /** @@ -113,7 +111,7 @@ template class SamplesPacket for (uint8_t i = 0; i < chCount; ++i) head[i] += toPop * frameSize; offset += toPop; - metadata.timestamp += toPop; // Also offset timestamp + timestamp += toPop; // Also offset timestamp return toPop; } @@ -172,6 +170,10 @@ template class SamplesPacket } } + uint64_t timestamp; ///< The timestamp of the packet. + bool useTimestamp; ///< Whether to use the timestamp or not. + bool flush; ///< Whether to flush the whole packet early or not. + private: uint8_t* head[chCount]; uint8_t* tail[chCount]; @@ -181,9 +183,6 @@ template class SamplesPacket uint32_t length; uint32_t mCapacity; uint8_t frameSize; - - public: - SDRDevice::StreamMeta metadata; ///< The stream metadata of the packet. }; } // namespace lime diff --git a/src/protocols/TRXLooper.cpp b/src/protocols/TRXLooper.cpp index df8ad53d2..59dee1a6d 100644 --- a/src/protocols/TRXLooper.cpp +++ b/src/protocols/TRXLooper.cpp @@ -265,14 +265,12 @@ template uint32_t TRXLooper::StreamRxTemplate(T* const* dest, uint32_t //auto start = high_resolution_clock::now(); while (samplesProduced < count) { - if (!mRx.stagingPacket && !mRx.fifo->pop(&mRx.stagingPacket, firstIteration, 250)) - { + if (!mRx.stagingPacket && !mRx.fifo->pop(&mRx.stagingPacket, firstIteration, 2000)) return samplesProduced; - } if (!timestampSet && meta) { - meta->timestamp = mRx.stagingPacket->metadata.timestamp; + meta->timestamp = mRx.stagingPacket->timestamp; timestampSet = true; } @@ -340,12 +338,10 @@ template uint32_t TRXLooper::StreamTxTemplate(const T* const* samples, const int packetsToBatch = mTx.packetsToBatch; const int32_t outputPktSize = SamplesPacketType::headerSize + packetsToBatch * samplesInPkt * sizeof(T); - if (mTx.stagingPacket && mTx.stagingPacket->metadata.timestamp + mTx.stagingPacket->size() != meta->timestamp) + if (mTx.stagingPacket && mTx.stagingPacket->timestamp + mTx.stagingPacket->size() != meta->timestamp) { if (!mTx.fifo->push(mTx.stagingPacket)) - { return 0; - } mTx.stagingPacket = nullptr; } @@ -359,21 +355,17 @@ template uint32_t TRXLooper::StreamTxTemplate(const T* const* samples, mTx.memPool->Allocate(outputPktSize), samplesInPkt * packetsToBatch, sizeof(T)); if (!mTx.stagingPacket) - { break; - } mTx.stagingPacket->Reset(); - mTx.stagingPacket->metadata.timestamp = ts; - mTx.stagingPacket->metadata.waitForTimestamp = useTimestamp; + mTx.stagingPacket->timestamp = ts; + mTx.stagingPacket->useTimestamp = useTimestamp; } int consumed = mTx.stagingPacket->push(src, samplesRemaining); src[0] += consumed; if (useChannelB) - { src[1] += consumed; - } samplesRemaining -= consumed; ts += consumed; @@ -381,14 +373,10 @@ template uint32_t TRXLooper::StreamTxTemplate(const T* const* samples, if (mTx.stagingPacket->isFull() || flush) { if (samplesRemaining == 0) - { - mTx.stagingPacket->metadata.flushPartialPacket = flush; - } + mTx.stagingPacket->flush = flush; if (!mTx.fifo->push(mTx.stagingPacket)) - { break; - } mTx.stagingPacket = nullptr; }