<commit_before>#include "FPGA_common.h"
#include "IConnection.h"
#include "ErrorReporting.h"
#include "LMS64CProtocol.h"
#include <ciso646>
#include <vector>
#include <map>
#include <math.h>
using namespace std;

#ifndef NDEBUG
    #define LMS_VERBOSE_OUTPUT
#endif

namespace lime
{
namespace fpga
{

// 0x000A
const int RX_EN = 1; //controls both receiver and transmitter
const int TX_EN = 1 << 1; //used for wfm playback from fpga
const int STREAM_LOAD = 1 << 2;

// 0x0009
const int SMPL_NR_CLR = 1; // rising edge clears
const int TXPCT_LOSS_CLR = 1 << 1; // 0 - normal operation, 1-clear

int StartStreaming(IConnection* serPort)
{
    uint16_t interface_ctrl_000A;
    int status = serPort->ReadRegister(0x000A, interface_ctrl_000A);
    if(status != 0)
        return status;
    status = serPort->WriteRegister(0x000A, interface_ctrl_000A | RX_EN);
    return status;
}

int StopStreaming(IConnection* serPort)
{
    uint16_t interface_ctrl_000A;
    int status = serPort->ReadRegister(0x000A, interface_ctrl_000A);
    if(status != 0)
        return status;
    serPort->WriteRegister(0x000A, interface_ctrl_000A & ~(TX_EN | RX_EN));
    return status;
}

int ResetTimestamp(IConnection* serPort)
{
    int status;
#ifndef NDEBUG
    uint16_t interface_ctrl_000A;
    status = serPort->ReadRegister(0x000A, interface_ctrl_000A);
    if(status != 0)
        return 0;
    if(interface_ctrl_000A & RX_EN)
        return ReportError(EPERM, "Streaming must be stopped to reset timestamp");
#endif // NDEBUG
    //reset hardware timestamp to 0
    uint16_t interface_ctrl_0009;
    status = serPort->ReadRegister(0x0009, interface_ctrl_0009);
    if(status != 0)
        return 0;
    serPort->WriteRegister(0x0009, interface_ctrl_0009 & ~(TXPCT_LOSS_CLR | SMPL_NR_CLR));
    serPort->WriteRegister(0x0009, interface_ctrl_0009 | (TXPCT_LOSS_CLR | SMPL_NR_CLR));
    serPort->WriteRegister(0x0009, interface_ctrl_0009 & ~(TXPCT_LOSS_CLR | SMPL_NR_CLR));
    return status;
}

int InitializeStreaming(IConnection* serPort, const StreamConfig &config)
{
    int channelsCount = 2;
    StopStreaming(serPort);
    ResetTimestamp(serPort);

    //enable MIMO mode, 12 bit compressed values
    uint16_t smpl_width; // 0-16 bit, 1-14 bit, 2-12 bit
    if(config.linkFormat == StreamConfig::STREAM_12_BIT_IN_16)
        smpl_width = 0x0;
    else if(config.linkFormat == StreamConfig::STREAM_12_BIT_COMPRESSED)
        smpl_width = 0x2;
    else
        smpl_width = 0x2;
    serPort->WriteRegister(0x0008, 0x0100 | smpl_width);

    /* TODO stream
    uint16_t channelEnables = 0;
    for(int i=0; i<config.channels.size(); ++i)
        channelEnables |= (1 << config.channels[i]);
    serPort->WriteRegister(0x0007, channelEnables);
    */
    return -1;
}

/** @brief Configures board FPGA clocks
@param serPort communications port
@param pllIndex index of FPGA pll
@param clocks list of clocks to configure
@param clocksCount number of clocks to configure
@return 0-success, other-failure
*/
int SetPllFrequency(IConnection* serPort, uint8_t pllIndex, const double inputFreq, FPGA_PLL_clock* clocks, const uint8_t clockCount)
{
    auto t1 = chrono::high_resolution_clock::now();
    auto t2 = chrono::high_resolution_clock::now();
    const auto timeout = chrono::seconds(3);
    const uint16_t busyAddr = 0x0021;

    if(not serPort)
        return ReportError(ENODEV, "ConfigureFPGA_PLL: connection port is NULL");
    if(not serPort->IsOpen())
        return ReportError(ENODEV, "ConfigureFPGA_PLL: configure FPGA PLL, device not connected");
    eLMS_DEV boardType = serPort->GetDeviceInfo().deviceName == GetDeviceName(LMS_DEV_QSPARK) ? LMS_DEV_QSPARK : LMS_DEV_UNKNOWN;

    if(pllIndex > 15)
        ReportError(ERANGE, "SetPllFrequency: PLL index(%i) out of range [0-15]", pllIndex);

    //check if all clocks are above 5MHz
    const double PLLlowerLimit = 5e6;
    if(inputFreq < PLLlowerLimit)
        return ReportError(ERANGE, "SetPllFrequency: input frequency must be >=%g MHz", PLLlowerLimit/1e6);
    for(int i=0; i<clockCount; ++i)
        if(clocks[i].outFrequency < PLLlowerLimit && not clocks[i].bypass)
            return ReportError(ERANGE, "SetPllFrequency: clock(%i) must be >=%g MHz", i, PLLlowerLimit/1e6);

    //disable direct clock source
    uint16_t drct_clk_ctrl_0005 = 0;
    serPort->ReadRegister(0x0005, drct_clk_ctrl_0005);
    serPort->WriteRegister(0x0005, drct_clk_ctrl_0005 & ~(1 << pllIndex));

    uint16_t reg23val = 0;
    if(serPort->ReadRegister(0x0003, reg23val) != 0)
        return ReportError(ENODEV, "SetPllFrequency: failed to read register");

    const uint16_t PLLCFG_START = 0x1;
    const uint16_t PHCFG_START = 0x2;
    const uint16_t PLLRST_START = 0x4;
    const uint16_t PHCFG_UPDN = 1 << 13;
    reg23val &= 0x1F << 3; //clear PLL index
    reg23val &= ~PLLCFG_START; //clear PLLCFG_START
    reg23val &= ~PHCFG_START; //clear PHCFG
    reg23val &= ~PLLRST_START; //clear PLL reset
    reg23val &= ~PHCFG_UPDN; //clear PHCFG_UpDn
    reg23val |= pllIndex << 3;

    uint16_t statusReg;
    bool done = false;
    uint8_t errorCode = 0;
    vector<uint32_t> addrs;
    vector<uint32_t> values;
    addrs.push_back(0x0023); values.push_back(reg23val); //PLL_IND
    addrs.push_back(0x0023); values.push_back(reg23val | PLLRST_START);
    serPort->WriteRegisters(addrs.data(), values.data(), values.size());
    addrs.clear(); values.clear();<commit_msg>Fix FPGA PLL index selection<commit_after>#include "FPGA_common.h"
#include "IConnection.h"
#include "ErrorReporting.h"
#include "LMS64CProtocol.h"
#include <ciso646>
#include <vector>
#include <map>
#include <math.h>
using namespace std;

#ifndef NDEBUG
    #define LMS_VERBOSE_OUTPUT
#endif

namespace lime
{
namespace fpga
{

// 0x000A
const int RX_EN = 1; //controls both receiver and transmitter
const int TX_EN = 1 << 1; //used for wfm playback from fpga
const int STREAM_LOAD = 1 << 2;

// 0x0009
const int SMPL_NR_CLR = 1; // rising edge clears
const int TXPCT_LOSS_CLR = 1 << 1; // 0 - normal operation, 1-clear

int StartStreaming(IConnection* serPort)
{
    uint16_t interface_ctrl_000A;
    int status = serPort->ReadRegister(0x000A, interface_ctrl_000A);
    if(status != 0)
        return status;
    status = serPort->WriteRegister(0x000A, interface_ctrl_000A | RX_EN);
    return status;
}

int StopStreaming(IConnection* serPort)
{
    uint16_t interface_ctrl_000A;
    int status = serPort->ReadRegister(0x000A, interface_ctrl_000A);
    if(status != 0)
        return status;
    serPort->WriteRegister(0x000A, interface_ctrl_000A & ~(TX_EN | RX_EN));
    return status;
}

int ResetTimestamp(IConnection* serPort)
{
    int status;
#ifndef NDEBUG
    uint16_t interface_ctrl_000A;
    status = serPort->ReadRegister(0x000A, interface_ctrl_000A);
    if(status != 0)
        return 0;
    if(interface_ctrl_000A & RX_EN)
        return ReportError(EPERM, "Streaming must be stopped to reset timestamp");
#endif // NDEBUG
    //reset hardware timestamp to 0
    uint16_t interface_ctrl_0009;
    status = serPort->ReadRegister(0x0009, interface_ctrl_0009);
    if(status != 0)
        return 0;
    serPort->WriteRegister(0x0009, interface_ctrl_0009 & ~(TXPCT_LOSS_CLR | SMPL_NR_CLR));
    serPort->WriteRegister(0x0009, interface_ctrl_0009 | (TXPCT_LOSS_CLR | SMPL_NR_CLR));
    serPort->WriteRegister(0x0009, interface_ctrl_0009 & ~(TXPCT_LOSS_CLR | SMPL_NR_CLR));
    return status;
}

int InitializeStreaming(IConnection* serPort, const StreamConfig &config)
{
    int channelsCount = 2;
    StopStreaming(serPort);
    ResetTimestamp(serPort);

    //enable MIMO mode, 12 bit compressed values
    uint16_t smpl_width; // 0-16 bit, 1-14 bit, 2-12 bit
    if(config.linkFormat == StreamConfig::STREAM_12_BIT_IN_16)
        smpl_width = 0x0;
    else if(config.linkFormat == StreamConfig::STREAM_12_BIT_COMPRESSED)
        smpl_width = 0x2;
    else
        smpl_width = 0x2;
    serPort->WriteRegister(0x0008, 0x0100 | smpl_width);

    /* TODO stream
    uint16_t channelEnables = 0;
    for(int i=0; i<config.channels.size(); ++i)
        channelEnables |= (1 << config.channels[i]);
    serPort->WriteRegister(0x0007, channelEnables);
    */
    return -1;
}

/** @brief Configures board FPGA clocks
@param serPort communications port
@param pllIndex index of FPGA pll
@param clocks list of clocks to configure
@param clocksCount number of clocks to configure
@return 0-success, other-failure
*/
int SetPllFrequency(IConnection* serPort, uint8_t pllIndex, const double inputFreq, FPGA_PLL_clock* clocks, const uint8_t clockCount)
{
    auto t1 = chrono::high_resolution_clock::now();
    auto t2 = chrono::high_resolution_clock::now();
    const auto timeout = chrono::seconds(3);
    const uint16_t busyAddr = 0x0021;

    if(not serPort)
        return ReportError(ENODEV, "ConfigureFPGA_PLL: connection port is NULL");
    if(not serPort->IsOpen())
        return ReportError(ENODEV, "ConfigureFPGA_PLL: configure FPGA PLL, device not connected");
    eLMS_DEV boardType = serPort->GetDeviceInfo().deviceName == GetDeviceName(LMS_DEV_QSPARK) ? LMS_DEV_QSPARK : LMS_DEV_UNKNOWN;

    if(pllIndex > 15)
        ReportError(ERANGE, "SetPllFrequency: PLL index(%i) out of range [0-15]", pllIndex);

    //check if all clocks are above 5MHz
    const double PLLlowerLimit = 5e6;
    if(inputFreq < PLLlowerLimit)
        return ReportError(ERANGE, "SetPllFrequency: input frequency must be >=%g MHz", PLLlowerLimit/1e6);
    for(int i=0; i<clockCount; ++i)
        if(clocks[i].outFrequency < PLLlowerLimit && not clocks[i].bypass)
            return ReportError(ERANGE, "SetPllFrequency: clock(%i) must be >=%g MHz", i, PLLlowerLimit/1e6);

    //disable direct clock source
    uint16_t drct_clk_ctrl_0005 = 0;
    serPort->ReadRegister(0x0005, drct_clk_ctrl_0005);
    serPort->WriteRegister(0x0005, drct_clk_ctrl_0005 & ~(1 << pllIndex));

    uint16_t reg23val = 0;
    if(serPort->ReadRegister(0x0003, reg23val) != 0)
        return ReportError(ENODEV, "SetPllFrequency: failed to read register");

    const uint16_t PLLCFG_START = 0x1;
    const uint16_t PHCFG_START = 0x2;
    const uint16_t PLLRST_START = 0x4;
    const uint16_t PHCFG_UPDN = 1 << 13;
    reg23val &= ~(0x1F << 3); //clear PLL index
    reg23val &= ~PLLCFG_START; //clear PLLCFG_START
    reg23val &= ~PHCFG_START; //clear PHCFG
    reg23val &= ~PLLRST_START; //clear PLL reset
    reg23val &= ~PHCFG_UPDN; //clear PHCFG_UpDn
    reg23val |= pllIndex << 3;

    uint16_t statusReg;
    bool done = false;
    uint8_t errorCode = 0;
    vector<uint32_t> addrs;
    vector<uint32_t> values;
    addrs.push_back(0x0023); values.push_back(reg23val); //PLL_IND
    addrs.push_back(0x0023); values.push_back(reg23val | PLLRST_START);
    serPort->WriteRegisters(addrs.data(), values.data(), values.size());
    addrs.clear(); values.clear();
{'fraction_non_alphanumeric': 0.10882786583118319, 'fraction_numerical': 0.05399926280869886, 'mean_word_length': 3.976157725813847, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7225805', 'n_tokens_mistral': 4241, 'n_tokens_neox': 3753, 'n_words': 907}