QPSK transmission and reception using example c code

Hi all,

I wanted to test my fmcomms3 using QPSK generated data (qpskwithfilt_txt.zip found in AD-FMCOMMS2/3/4 Datafiles wiki page). Because i have prolem in iio oscilloscope, i tried to send data by modifying ad9361-iiostream.c code as follows to read qpsk data from qpskwithfilt.txt, send it, receive data and store it in a csv file.

5657.ad9361-iiostream.c.txt
/*
 * libiio - AD9361 IIO streaming example
 *
 * Copyright (C) 2014 IABG mbH
 * Author: Michael Feilen <feilen_at_iabg.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 *
 * Modified by DDR/RTY Oct 2016.
 *
 **/

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <math.h>
#include <iio.h>

/* helper macros */
#define MHZ(x) ((long long)(x*1000000.0 + .5))
#define GHZ(x) ((long long)(x*1000000000.0 + .5))

/* RX is input, TX is output */
enum iodev { RX, TX };

/* common RX and TX streaming params */
struct stream_cfg {
	long long bw_hz; // Analog banwidth in Hz
	long long fs_hz; // Baseband sample rate in Hz
	long long lo_hz; // Local oscillator frequency in Hz
	const char* rfport; // Port name
};

/* static scratch mem for strings */
static char tmpstr[64];

/* IIO structs required for streaming */
static struct iio_context *ctx   = NULL;
static struct iio_channel *rx0_i = NULL;
static struct iio_channel *rx0_q = NULL;
static struct iio_channel *tx0_i = NULL;
static struct iio_channel *tx0_q = NULL;
static struct iio_buffer  *rxbuf = NULL;
static struct iio_buffer  *txbuf = NULL;

static bool stop;

/* signal generator: make a sine wave */

/* cleanup and exit */
static void shutdown()
{
	printf("* Destroying buffers\n");
	if (rxbuf) { iio_buffer_destroy(rxbuf); }
	if (txbuf) { iio_buffer_destroy(txbuf); }

	printf("* Disabling streaming channels\n");
	if (rx0_i) { iio_channel_disable(rx0_i); }
	if (rx0_q) { iio_channel_disable(rx0_q); }
	if (tx0_i) { iio_channel_disable(tx0_i); }
	if (tx0_q) { iio_channel_disable(tx0_q); }

	printf("* Destroying context\n");
	if (ctx) { iio_context_destroy(ctx); }
	exit(0);
}

static void handle_sig(int sig)
{
	printf("Waiting for process to finish...\n");
	stop = true;
}

/* check return value of attr_write function */
static void errchk(int v, const char* what) {
	 if (v < 0) { fprintf(stderr, "Error %d writing to channel \"%s\"\nvalue may not be supported.\n", v, what); shutdown(); }
}

/* write attribute: long long int */
static void wr_ch_lli(struct iio_channel *chn, const char* what, long long val)
{
	errchk(iio_channel_attr_write_longlong(chn, what, val), what);
}

/* write attribute: string */
static void wr_ch_str(struct iio_channel *chn, const char* what, const char* str)
{
	errchk(iio_channel_attr_write(chn, what, str), what);
}

/* helper function generating channel names */
static char* get_ch_name(const char* type, int id)
{
	snprintf(tmpstr, sizeof(tmpstr), "%s%d", type, id);
	return tmpstr;
}

/* returns ad9361 phy device */
static struct iio_device* get_ad9361_phy(struct iio_context *ctx)
{
	struct iio_device *dev =  iio_context_find_device(ctx, "ad9361-phy");
	assert(dev && "No ad9361-phy found");
	return dev;
}

/* finds AD9361 streaming IIO devices */
static bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev)
{
	switch (d) {
	case TX: *dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); return *dev != NULL;
	case RX: *dev = iio_context_find_device(ctx, "cf-ad9361-lpc");  return *dev != NULL;
	default: assert(0); return false;
	}
}

/* finds AD9361 streaming IIO channels */
static bool get_ad9361_stream_ch(struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn)
{
	*chn = iio_device_find_channel(dev, get_ch_name("voltage", chid), d == TX);
	if (!*chn)
		*chn = iio_device_find_channel(dev, get_ch_name("altvoltage", chid), d == TX);
	return *chn != NULL;
}

/* finds AD9361 phy IIO configuration channel with id chid */
static bool get_phy_chan(struct iio_context *ctx, enum iodev d, int chid, struct iio_channel **chn)
{
	switch (d) {
	case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), false); return *chn != NULL;
	case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), true);  return *chn != NULL;
	default: assert(0); return false;
	}
}

/* finds AD9361 local oscillator IIO configuration channels */
static bool get_lo_chan(struct iio_context *ctx, enum iodev d, struct iio_channel **chn)
{
	switch (d) {
	 // LO chan is always output, i.e. true
	case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 0), true); return *chn != NULL;
	case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 1), true); return *chn != NULL;
	default: assert(0); return false;
	}
}

/* applies streaming configuration through IIO */
bool cfg_ad9361_streaming_ch(struct iio_context *ctx, struct stream_cfg *cfg, enum iodev type, int chid)
{
	struct iio_channel *chn = NULL;

	// Configure phy and lo channels
	printf("* Acquiring AD9361 phy channel %d\n", chid);
	if (!get_phy_chan(ctx, type, chid, &chn)) {	return false; }
	wr_ch_str(chn, "rf_port_select",     cfg->rfport);
	wr_ch_lli(chn, "rf_bandwidth",       cfg->bw_hz);
	wr_ch_lli(chn, "sampling_frequency", cfg->fs_hz);

	// Configure LO channel
	printf("* Acquiring AD9361 %s lo channel\n", type == TX ? "TX" : "RX");
	if (!get_lo_chan(ctx, type, &chn)) { return false; }
	wr_ch_lli(chn, "frequency", cfg->lo_hz);
	return true;
}

/* simple configuration and streaming */
int main (int argc, char **argv)
{
	// Streaming devices
	struct iio_device *tx;
	struct iio_device *rx;

	// Stream configurations
	struct stream_cfg rxcfg;
	struct stream_cfg txcfg;

	// Listen to ctrl+c and assert
	signal(SIGINT, handle_sig);

	// RX stream config
	rxcfg.bw_hz = MHZ(16.0);   // 2 MHz rf bandwidth
	rxcfg.fs_hz = MHZ(30.72);   // 2.5 MS/s rx sample rate
	rxcfg.lo_hz = GHZ(2.4); // 2.5 GHz rf frequency
	rxcfg.rfport = "A_BALANCED"; // port A (select for rf freq.)

	// slow attack mode?

	// TX stream config
	txcfg.bw_hz = MHZ(16.0); // 1.5 MHz rf bandwidth
	txcfg.fs_hz = MHZ(30.72);   // 2.5 MS/s tx sample rate
	txcfg.lo_hz = GHZ(2.4); // 2.5 GHz rf frequency
	txcfg.rfport = "A"; // port A (select for rf freq.)


	printf("* Acquiring IIO context\n");
	assert((ctx = iio_create_default_context()) && "No context");
	assert(iio_context_get_devices_count(ctx) > 0 && "No devices");

	printf("* Acquiring AD9361 streaming devices\n");
	assert(get_ad9361_stream_dev(ctx, TX, &tx) && "No tx dev found");
	assert(get_ad9361_stream_dev(ctx, RX, &rx) && "No rx dev found");

	printf("* Configuring AD9361 for streaming\n");
	assert(cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
	assert(cfg_ad9361_streaming_ch(ctx, &txcfg, TX, 0) && "TX port 0 not found");

	printf("* Initializing AD9361 IIO streaming channels\n");
	assert(get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i) && "RX chan i not found");
	assert(get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q) && "RX chan q not found");
	assert(get_ad9361_stream_ch(ctx, TX, tx, 0, &tx0_i) && "TX chan i not found");
	assert(get_ad9361_stream_ch(ctx, TX, tx, 1, &tx0_q) && "TX chan q not found");

	printf("* Enabling IIO streaming channels\n");
	iio_channel_enable(rx0_i);
	iio_channel_enable(rx0_q);
	iio_channel_enable(tx0_i);
	iio_channel_enable(tx0_q);

	int buffer_size = 4200;

	printf("* Creating non-cyclic IIO buffers with 1 MiS\n");
	rxbuf = iio_device_create_buffer(rx, buffer_size, false);
	if (!rxbuf) {
		perror("Could not create RX buffer");
		shutdown();
	}
	txbuf = iio_device_create_buffer(tx, buffer_size, false);
	if (!txbuf) {
		perror("Could not create TX buffer");
		shutdown();
	}

	FILE *foutp = fopen("output.csv", "w+");
	FILE *finp = fopen("qpsk_1114newrc.txt", "r");
	int iter=0;
	int16_t QPSKsamplesTX[4200][4];
	float i1,q1,i2,q2;
	for(iter=0;iter<4200;iter++){
		fscanf(finp, "%f,%f,%f,%f\n", &i1,&q1,&i2,&q2);
		QPSKsamplesTX[iter][0]=(int16_t)i1*3200.0;
		QPSKsamplesTX[iter][1]=(int16_t)q1*3200.0;
		QPSKsamplesTX[iter][2]=(int16_t)i2*3200.0;
		QPSKsamplesTX[iter][3]=(int16_t)q2*3200.0;
	}

	printf("* Starting IO streaming (press CTRL+C to cancel)\n");
	while (!stop)
	{
		ssize_t nbytes_rx, nbytes_tx;
		void *p_dat, *p_end;
		ptrdiff_t p_inc;

		// Schedule TX buffer: send to hardware
		nbytes_tx = iio_buffer_push(txbuf);
		if (nbytes_tx < 0) { printf("Error pushing buf %d\n", (int) nbytes_tx); shutdown(); }

		// Refill RX buffer: fetch from hardware
		nbytes_rx = iio_buffer_refill(rxbuf);
		if (nbytes_rx < 0) { printf("Error refilling buf %d\n",(int) nbytes_rx); shutdown(); }

		p_inc = iio_buffer_step(rxbuf);
		p_end = iio_buffer_end(rxbuf);
		for (p_dat = iio_buffer_first(rxbuf, rx0_q); p_dat < p_end; p_dat += p_inc) {
			// Get I and Q and save to CSV
			const int16_t i = ((int16_t*)p_dat)[0]; // Real (I)
			const int16_t q = ((int16_t*)p_dat)[1]; // Imag (Q)
			fprintf(foutp, "%d,%d\n", i, q);
		}

		// WRITE: Get pointers to TX buf and write IQ to TX buf port 0
		p_inc = iio_buffer_step(txbuf);
		p_end = iio_buffer_end(txbuf);
		iter=0;
		for (p_dat = iio_buffer_first(txbuf, tx0_q); p_dat < p_end; p_dat += p_inc) {
			((int16_t *)p_dat)[0] = QPSKsamplesTX[iter][0];
			((int16_t *)p_dat)[1] = QPSKsamplesTX[iter++][1];
		}
	}

	fclose(finp);
	fclose(foutp);

	shutdown();

	return 0;
} 
 

I imported the received data in Matlab workspace to view constellation (using "scatterplot(Inphase1+i*Quadrature1,4);" command), but i get the following constellation

which is different from the one obtained in AD-FMCOMMS2/3/4 Datafiles wiki page

i tried to filter it using the raised cosine filter found in the transmitter simulink model using the following commands

>> x1 = upfirdn(Inphase1, rcTxFilt1,1 , 4);
>> x2 = upfirdn(Quadrature1, rcTxFilt1,1 , 4);
>> scatterplot(x1+i*x2,4);
but i get the following costellation

I'm not sure if there is some problem in my c code or matlab commands or it misses some processing on the received signal.

Any help would be appreciated

Thanks & Regards



correct subject
[edited by: Aziz_Bl at 2:58 PM (GMT 0) on 23 Apr 2019]
Parents
  • 0
    •  Analog Employees 
    on Apr 24, 2019 3:49 PM

    For both configurations you are experiencing timing offset, which is a standard artifact of any communications system without any synchronization.  When using the qpskfilt files you will need to apply a SRRC filter and apply timing correction.

    In regards to the first plot, you are also saturating the device. Try increasing the TX attenuation.

    For the second configuration, since you have separate devices with independent clocks you will have some frequency offset. This causes the constellation to rotate.

    -Travis

Reply
  • 0
    •  Analog Employees 
    on Apr 24, 2019 3:49 PM

    For both configurations you are experiencing timing offset, which is a standard artifact of any communications system without any synchronization.  When using the qpskfilt files you will need to apply a SRRC filter and apply timing correction.

    In regards to the first plot, you are also saturating the device. Try increasing the TX attenuation.

    For the second configuration, since you have separate devices with independent clocks you will have some frequency offset. This causes the constellation to rotate.

    -Travis

Children
  • Hi , thanks for your reply,

    Is there a function that allows me increasing TX attenuation ?

  • 0
    •  Analog Employees 
    on Apr 24, 2019 7:01 PM in reply to Aziz_Bl
  • Hi ,

    I did as you indicated, i set TX-2 attenuation to -3db by adding the following lines to my code

    chad = iio_device_find_channel(get_ad9361_phy(ctx), "voltage1", true);
    iio_channel_attr_write_double(chad,"hardwaregain",-3.00);

    to minimise the noise i connected TX-2 to RX-2 of my fmcomms3 using a coax cable and i tried the following steps

    STEP1:

    i tried to send the sinusoîdal waveform found in /usr/local/lib/osc/waveforms/

    FILE *finp = fopen("sinewave_0.3.mat.txt", "r");

    i obtained the following signal (plotted in time domain) in my corresponding RX (RX-2): 

    and here is a zoom from it:

    which indicates that i got a correct sine wave

    STEP2:

    i tried to send a qpsk waveform (qpskwithfilt_30.72M.txt) and I got the following signal (plotted in time domain) in RX-2

    here is a zoom from it

    and here is the constellation of it

    => I'm not sure if it is a correct qpsk signal

    STEP3:

    i sent the same waveform (qpskwithfilt_30.72M.txt) using iio oscilloscope and i found the following constellation:

    which indicates that i have a correct qpsk signal in the reception

    Questions:

    Q1- Do you think that the received signal obtained in STEP2 is a correct qpsk signal ?

    Q2- How to modify my code to get a constellation close to the one obtained by iio oscilloscope ?

    Here is my code:

    7536.ad9361-iiostrem.c.txt
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include <assert.h>
    #include <signal.h>
    #include <stdio.h>
    #include <math.h>
    #include <iio.h>
    
    /* helper macros */
    #define MHZ(x) ((long long)(x*1000000.0 + .5))
    #define GHZ(x) ((long long)(x*1000000000.0 + .5))
    
    /* RX is input, TX is output */
    enum iodev { RX, TX };
    
    /* common RX and TX streaming params */
    struct stream_cfg {
    	long long bw_hz; // Analog banwidth in Hz
    	long long fs_hz; // Baseband sample rate in Hz
    	long long lo_hz; // Local oscillator frequency in Hz
    	const char* rfport; // Port name
    };
    
    /* static scratch mem for strings */
    static char tmpstr[64];
    
    /* IIO structs required for streaming */
    static struct iio_context *ctx   = NULL;
    static struct iio_channel *rx0_i = NULL;
    static struct iio_channel *rx0_q = NULL;
    static struct iio_channel *tx0_i = NULL;
    static struct iio_channel *tx0_q = NULL;
    static struct iio_buffer  *rxbuf = NULL;
    static struct iio_buffer  *txbuf = NULL;
    static struct iio_channel  *chad = NULL;
    static bool stop;
    
    /* signal generator: make a sine wave */
    
    /* cleanup and exit */
    static void shutdown()
    {
    	printf("* Destroying buffers\n");
    	if (rxbuf) { iio_buffer_destroy(rxbuf); }
    	if (txbuf) { iio_buffer_destroy(txbuf); }
    
    	printf("* Disabling streaming channels\n");
    	if (rx0_i) { iio_channel_disable(rx0_i); }
    	if (rx0_q) { iio_channel_disable(rx0_q); }
    	if (tx0_i) { iio_channel_disable(tx0_i); }
    	if (tx0_q) { iio_channel_disable(tx0_q); }
    	printf("* Destroying context\n");
    	if (ctx) { iio_context_destroy(ctx); }
    	exit(0);
    }
    
    static void handle_sig(int sig)
    {
    	printf("Waiting for process to finish...\n");
    	stop = true;
    }
    
    /* check return value of attr_write function */
    static void errchk(int v, const char* what) {
    	 if (v < 0) { fprintf(stderr, "Error %d writing to channel \"%s\"\nvalue may not be supported.\n", v, what); shutdown(); }
    }
    
    /* write attribute: long long int */
    static void wr_ch_lli(struct iio_channel *chn, const char* what, long long val)
    {
    	errchk(iio_channel_attr_write_longlong(chn, what, val), what);
    }
    
    /* write attribute: string */
    static void wr_ch_str(struct iio_channel *chn, const char* what, const char* str)
    {
    	errchk(iio_channel_attr_write(chn, what, str), what);
    }
    
    /* helper function generating channel names */
    static char* get_ch_name(const char* type, int id)
    {
    	snprintf(tmpstr, sizeof(tmpstr), "%s%d", type, id);
    	return tmpstr;
    }
    
    /* returns ad9361 phy device */
    static struct iio_device* get_ad9361_phy(struct iio_context *ctx)
    {
    	struct iio_device *dev =  iio_context_find_device(ctx, "ad9361-phy");
    	assert(dev && "No ad9361-phy found");
    	return dev;
    }
    
    /* finds AD9361 streaming IIO devices */
    static bool get_ad9361_stream_dev(struct iio_context *ctx, enum iodev d, struct iio_device **dev)
    {
    	switch (d) {
    	case TX: *dev = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc"); return *dev != NULL;
    	case RX: *dev = iio_context_find_device(ctx, "cf-ad9361-lpc");  return *dev != NULL;
    	default: assert(0); return false;
    	}
    }
    
    /* finds AD9361 streaming IIO channels */
    static bool get_ad9361_stream_ch(struct iio_context *ctx, enum iodev d, struct iio_device *dev, int chid, struct iio_channel **chn)
    {
    	*chn = iio_device_find_channel(dev, get_ch_name("voltage", chid), d == TX);
    	if (!*chn)
    		*chn = iio_device_find_channel(dev, get_ch_name("altvoltage", chid), d == TX);
    	return *chn != NULL;
    }
    
    /* finds AD9361 phy IIO configuration channel with id chid */
    static bool get_phy_chan(struct iio_context *ctx, enum iodev d, int chid, struct iio_channel **chn)
    {
    	switch (d) {
    	case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), false); return *chn != NULL;
    	case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("voltage", chid), true);  return *chn != NULL;
    	default: assert(0); return false;
    	}
    }
    
    /* finds AD9361 local oscillator IIO configuration channels */
    static bool get_lo_chan(struct iio_context *ctx, enum iodev d, struct iio_channel **chn)
    {
    	switch (d) {
    	 // LO chan is always output, i.e. true
    	case RX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 0), true); return *chn != NULL;
    	case TX: *chn = iio_device_find_channel(get_ad9361_phy(ctx), get_ch_name("altvoltage", 1), true); return *chn != NULL;
    	default: assert(0); return false;
    	}
    }
    
    /* applies streaming configuration through IIO */
    bool cfg_ad9361_streaming_ch(struct iio_context *ctx, struct stream_cfg *cfg, enum iodev type, int chid)
    {
    	struct iio_channel *chn = NULL;
    
    	// Configure phy and lo channels
    	printf("* Acquiring AD9361 phy channel %d\n", chid);
    	if (!get_phy_chan(ctx, type, chid, &chn)) {	return false; }
    	wr_ch_str(chn, "rf_port_select",     cfg->rfport);
    	wr_ch_lli(chn, "rf_bandwidth",       cfg->bw_hz);
    	wr_ch_lli(chn, "sampling_frequency", cfg->fs_hz);
    	// Configure LO channel
    	printf("* Acquiring AD9361 %s lo channel\n", type == TX ? "TX" : "RX");
    	if (!get_lo_chan(ctx, type, &chn)) { return false; }
    	wr_ch_lli(chn, "frequency", cfg->lo_hz);
    	return true;
    }
    
    /* simple configuration and streaming */
    int main (int argc, char **argv)
    {
    	// Streaming devices
    	struct iio_device *tx;
    	struct iio_device *rx;
    
    	// Stream configurations
    	struct stream_cfg rxcfg;
    	struct stream_cfg txcfg;
    
    	// Listen to ctrl+c and assert
    	signal(SIGINT, handle_sig);
    
    	// RX stream config
    	rxcfg.bw_hz = 16000000;   // 2 MHz rf bandwidth
    	rxcfg.fs_hz = 30720000;   // 2.5 MS/s rx sample rate
    	rxcfg.lo_hz = GHZ(2.4); // 2.5 GHz rf frequency
    	rxcfg.rfport = "A_BALANCED"; // port A (select for rf freq.)
    
    	// slow attack mode?
    
    	// TX stream config
    	txcfg.bw_hz = 16000000; // 1.5 MHz rf bandwidth
    	txcfg.fs_hz = 30720000;   // 2.5 MS/s tx sample rate
    	txcfg.lo_hz = GHZ(2.4); // 2.5 GHz rf frequency
    	txcfg.rfport = "A"; // port A (select for rf freq.)
    
    
    	printf("* Acquiring IIO context\n");
    	assert((ctx = iio_create_default_context()) && "No context");
    	assert(iio_context_get_devices_count(ctx) > 0 && "No devices");
    
    	printf("* Acquiring AD9361 streaming devices\n");
    	assert(get_ad9361_stream_dev(ctx, TX, &tx) && "No tx dev found");
    	assert(get_ad9361_stream_dev(ctx, RX, &rx) && "No rx dev found");
    
    	printf("* Configuring AD9361 for streaming\n");
    	assert(cfg_ad9361_streaming_ch(ctx, &rxcfg, RX, 0) && "RX port 0 not found");
    	assert(cfg_ad9361_streaming_ch(ctx, &txcfg, TX, 0) && "TX port 0 not found");
    
    	printf("* Initializing AD9361 IIO streaming channels\n");
    	assert(get_ad9361_stream_ch(ctx, RX, rx, 0, &rx0_i) && "RX chan i not found");
    	assert(get_ad9361_stream_ch(ctx, RX, rx, 1, &rx0_q) && "RX chan q not found");
    	assert(get_ad9361_stream_ch(ctx, TX, tx, 0, &tx0_i) && "TX chan i not found");
    	assert(get_ad9361_stream_ch(ctx, TX, tx, 1, &tx0_q) && "TX chan q not found");
    
    	printf("* Enabling IIO streaming channels\n");
    	iio_channel_enable(rx0_i);
    	iio_channel_enable(rx0_q);
    	iio_channel_enable(tx0_i);
    	iio_channel_enable(tx0_q);
    
    	int buffer_size = 24800;
    
    	printf("* Creating non-cyclic IIO buffers with 1 MiS\n");
    	rxbuf = iio_device_create_buffer(rx, buffer_size, false);
    	if (!rxbuf) {
    		perror("Could not create RX buffer");
    		shutdown();
    	}
    	txbuf = iio_device_create_buffer(tx, buffer_size, true);
    	if (!txbuf) {
    		perror("Could not create TX buffer");
    		shutdown();
    	}
    	FILE *foutp = fopen("output.csv", "w+");
    	FILE *finp = fopen("qpskwithfilt_30.72M.txt", "r");
    	int iter=0;
    	int16_t QPSKsamplesTX[24800][2];//,QPSKsamplesRX[24800][2];
    	float i1,q1;
    	for(iter=0;iter<24800;iter++){
    		fscanf(finp, "%f,%f\n", &i1,&q1);
    		QPSKsamplesTX[iter][0]=(int16_t)(i1* 32767.0);
    		QPSKsamplesTX[iter][1]=(int16_t)(q1* 32767.0);
    	}
    	fclose(finp);
            void *p_dat, *p_end;
            ptrdiff_t p_inc;
    
    	p_inc = iio_buffer_step(txbuf);
            p_end = iio_buffer_end(txbuf);
            iter=0;
            for (p_dat = iio_buffer_first(txbuf, tx0_q); p_dat < p_end; p_dat += p_inc) {
           	        ((int16_t *)p_dat)[0] = QPSKsamplesTX[iter][0];
                    ((int16_t *)p_dat)[1] = QPSKsamplesTX[iter++][1];
            }
    
    	iio_buffer_push(txbuf);
    
    	chad = iio_device_find_channel(get_ad9361_phy(ctx), "voltage0", true);
            iio_channel_attr_write_double(chad,"hardwaregain",-3.00);
    	chad = iio_device_find_channel(get_ad9361_phy(ctx), "voltage1", true);
            iio_channel_attr_write_double(chad,"hardwaregain",-3.00);
    
    	printf("* Starting IO streaming (press CTRL+C to cancel)\n");
    	while (!stop)
    	{
    		void *p_dat, *p_end;
    		ptrdiff_t p_inc;
    
    		// Refill RX buffer: fetch from hardware
    		iio_buffer_refill(rxbuf);
    
    		p_inc = iio_buffer_step(rxbuf);
    		p_end = iio_buffer_end(rxbuf);
    		iter=0;
    		for (p_dat = iio_buffer_first(rxbuf, rx0_q); p_dat < p_end; p_dat += p_inc) {
    			fprintf(foutp, "%d,%d\n", ((int16_t*)p_dat)[0], ((int16_t*)p_dat)[1]);
    		}
    	}
    	fclose(foutp);
    	shutdown();
    	return 0;
    }
    

    Thanks & Regards