You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用libiio v0.26实现接收缓冲区到发送缓冲区数据拷贝的问题求助

使用libiio v0.26实现接收缓冲区到发送缓冲区数据拷贝的问题求助

各位好,我目前在基于AD9361芯片开发,想用libiio把接收缓冲区里的IQ数据直接转发到发送缓冲区,实现一个简单的回环功能。我试了两种不同的拷贝方式,但都没能成功实现数据的转发,想请社区的大佬帮忙排查下问题。

以下是我的完整代码:

#include <error.h>
#include <iio.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

#define rx_b_s p_dat = iio_buffer_first(rxbuf, rx0_i)
#define tx_b_s p_dat2 = iio_buffer_first(txbuf, tx0_i)
#define rx_inc p_dat += p_inc
#define tx_inc p_dat2 += p_inc2
#define rx_con p_dat < p_end
#define tx_con p_dat2 < p_end2
#define BUFF_SIZE 1000000
#define KHZ(x) ((long long)(x * 100000.0 + .5))
#define MHZ(x) ((long long)(x * 1000000.0 + .5))
#define GHZ(x) ((long long)(x * 1000000000.0 + .5))

void receive(struct iio_context *ctx, struct iio_channel *RX_LO) {
    struct timeval start_tv, end_tv;
    long long start_us, end_us;
    double elapsed_ms, elapsed_ms2, elapsed_ms3;
    struct iio_device *dev;
    struct iio_device *dev2;
    struct iio_channel *rx0_i, *rx0_q;
    struct iio_channel *tx0_i, *tx0_q;
    struct iio_buffer *rxbuf;
    struct iio_buffer *txbuf;

    dev = iio_context_find_device(ctx, "cf-ad9361-lpc");
    dev2 = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc");

    rx0_i = iio_device_find_channel(dev, "voltage0", false);
    rx0_q = iio_device_find_channel(dev, "voltage1", false);
    tx0_i = iio_device_find_channel(dev2, "voltage2", true);
    tx0_q = iio_device_find_channel(dev2, "voltage3", true);

    if (iio_channel_is_scan_element(rx0_i)) {
        iio_channel_enable(rx0_i);
        printf("RX0_I enabled\n");
    } else {
        printf("RX0_I cannot be enabled\n");
    }
    if (iio_channel_is_scan_element(rx0_q)) {
        iio_channel_enable(rx0_q);
        printf("RX0_Q enabled\n");
    } else {
        printf("RX0_Q cannot be enabled\n");
    }
    if (iio_channel_is_scan_element(tx0_i)) {
        iio_channel_enable(tx0_i);
        printf("TX0_I enabled\n");
    } else {
        printf("TX0_I cannot be enabled\n");
    }
    if (iio_channel_is_scan_element(tx0_q)) {
        iio_channel_enable(tx0_q);
        printf("TX0_Q enabled\n");
    } else {
        printf("RX0_Q cannot be enabled\n"); // 这里疑似笔误,应该是TX0_Q?
    }

    rxbuf = iio_device_create_buffer(dev, BUFF_SIZE, false);
    txbuf = iio_device_create_buffer(dev2, BUFF_SIZE, false);

    if (!rxbuf) {
        perror("Could not create RX buffer\n");
        shutdown();
    }
    if (!txbuf) {
        perror("Could not create TX buffer\n");
        shutdown();
    }

    ssize_t num, num2;
    while (true) {
        void *p_dat1;
        ptrdiff_t p_inc = iio_buffer_step(rxbuf);
        void *p_dat2;
        ptrdiff_t p_inc2 = iio_buffer_step(txbuf);
        void *p_end = iio_buffer_end(rxbuf);
        void *p_end2 = iio_buffer_end(txbuf);
        void *p_start2 = iio_buffer_start(txbuf);
        void *p_start = iio_buffer_start(rxbuf);

        // first variant
        //==========================================================================
        // num=iio_buffer_refill(rxbuf);
        // memcpy(p_start2,p_start,4*BUFF_SIZE);
        // num2=iio_buffer_push(txbuf);
        //==========================================================================

        // second variant
        num = iio_buffer_refill(rxbuf);
        if (num > 0) {
            printf("Refilled:%d\n", num);
        }

        for (p_dat1 = iio_buffer_first(rxbuf, rx0_i), p_dat2 = iio_buffer_start(txbuf); 
             p_dat1 < p_end; 
             p_dat1 += p_inc, p_dat2 += p_inc2) {
            const int16_t i = ((int16_t *)p_dat1)[0];
            const int16_t q = ((int16_t *)p_dat1)[1];
            ((int16_t *)p_dat2)[0] = i;
            ((int16_t *)p_dat2)[1] = q;
        }

        num2 = iio_buffer_push(txbuf);
        if (num2 > 0) {
            printf("Pushed:%d\n", num2);
        }
    }

    iio_buffer_destroy(rxbuf);
    iio_buffer_destroy(txbuf);
}

int main() {
    struct iio_context *ctx;
    struct iio_device *phy;
    struct iio_channel *rec;
    struct iio_channel *transmit;
    struct iio_channel *RX_LO;
    struct iio_channel *TX_LO;

    ctx = iio_create_context_from_uri("ip:192.168.2.1");
    phy = iio_context_find_device(ctx, "ad9361-phy");

    rec = iio_device_find_channel(phy, "voltage0", false);
    transmit = iio_device_find_channel(phy, "voltage0", true);
    RX_LO = iio_device_find_channel(phy, "altvoltage0", true);
    TX_LO = iio_device_find_channel(phy, "altvoltage1", true);

    iio_channel_attr_write_longlong(RX_LO, "frequency", 120000000); /* RX LO frequency 120MHz */
    iio_channel_attr_write_longlong(rec, "rf_bandwidth", 50000000);
    iio_channel_attr_write_longlong(rec, "hardwaregain", 40);
    iio_channel_attr_write_longlong(rec, "sampling_frequency", 50000000);

    iio_channel_attr_write_longlong(TX_LO, "frequency", 1080000000); /*TX LO frequency 1080MHz*/
    iio_channel_attr_write_longlong(transmit, "rf_bandwidth", 50000000);
    iio_channel_attr_write_longlong(transmit, "hardwaregain", 60);
    iio_channel_attr_write_longlong(transmit, "sampling_frequency", 50000000);

    receive(ctx, RX_LO);

    iio_context_destroy(ctx);
    return 0;
}

我注意到代码里有个小细节:TX0_Q启用失败的打印信息写成了RX0_Q cannot be enabled,这应该是个笔误,但暂时不确定是否会影响功能。

回到核心问题:我尝试了两种数据转发方式:

  • 第一种是直接调用memcpy批量拷贝整个接收缓冲区的数据到发送缓冲区
  • 第二种是循环遍历接收缓冲区的每个IQ样本,逐个拷贝到发送缓冲区对应位置

两种方式运行时,控制台都能正常打印RefilledPushed的日志,说明缓冲区的iio_buffer_refilliio_buffer_push操作都返回了成功,但实际上并没有数据被正确发送出去。

我是参考旧版libiio的实现示例来写的,但在新版libiio的文档里没找到关于缓冲区直接转发的详细说明,不确定是不是API使用方式有变化,或者是AD9361的设备配置遗漏了关键步骤?

麻烦大家帮我看看代码里有没有明显错误,或者有没有什么libiio的使用细节我没注意到?

内容来源于stack exchange

火山引擎 最新活动