Hi Michael,
Thank you for your reply.
I have a 10.txt file and there are some datas in it, like the format:
TEXT
1 0
1 0
1 0
... ...
First I use the function analyse_wavefile() to convert the datas, and then use iio_channel_convert_inverse() to change the datas from analayse_wavefile() to hardware format, then use iio_buffer_push() to send the datas. But the problem is I cann't receive any datas similar to the 10.txt or datas after analyse_wavefile() or the hardware format datas. I don't know why. Even though it has deviation in ad9361, but I think the receive datas should similar to the TX.
My program is as follows:
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <iio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <math.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 */
static 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];
static char *converse_buf = NULL;
/* 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;
/* cleanup and exit */
static void shutdown(int s)
{
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);
}
/* 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(0); }
}
/* 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); //Set the value of the given channel-specific attribute
}
/* 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 */
static 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;
}
static unsigned short convert(double scale, float val)
{
return (short) (val * scale);
}
static int analyse_wavefile(const char *file_name, char **buf, int *count, int tx_channels)
{
int ret, j, i = 0, size, rep;
double max = 0.0, val[4], scale = 0.0;
double i1, q1, i2, q2;
char line[80];
FILE *infile = fopen(file_name, "r");
*buf = NULL;
if (infile == NULL)
printf("infile is NULL\n");
if (fgets(line, 80, infile) != NULL)
{
if (strncmp(line, "TEXT", 4) == 0)
{
/* Unscaled samples need to be in the range +- 2047 */
if (strncmp(line, "TEXTU", 5) == 0)
scale = 16.0; /* scale up to 16-bit */
ret = sscanf(line, "TEXT%*c REPEAT %d", &rep);
if (ret != 1)
{
rep = 1;
}
size = 0;
while (fgets(line, 80, infile))
{
ret = sscanf(line, "%lf%*[, \t]%lf%*[, \t]%lf%*[, \t]%lf",
&val[0], &val[1], &val[2], &val[3]);
if (!(ret == 4 || ret == 2))
{
fclose(infile);
return -2;
}
for (i = 0; i < ret; i++)
if (fabs(val[i]) > max)
max = fabs(val[i]);
size += tx_channels * 2;
}
size *= rep;
if (scale == 0.0)
scale = 32752.0 / max;
if (max > 32752.0)
fprintf(stderr, "ERROR: DAC Waveform Samples > +/- 2047.0\n");
while ((size % 8) != 0)
size *= 2;
converse_buf = malloc(size);
*buf = malloc(size);
if (*buf == NULL)
return 0;
unsigned long long *sample = *((unsigned long long **) buf);
unsigned int *sample_32 = *((unsigned int **) buf);
unsigned short *sample_16 = *((unsigned short **) buf);
rewind(infile);
if (fgets(line, 80, infile) != NULL)
{
if (strncmp(line, "TEXT", 4) == 0)
{
size = 0;
i = 0;
while (fgets(line, 80, infile))
{
ret = sscanf(line, "%lf%*[, \t]%lf%*[, \t]%lf%*[, \t]%lf",
&i1, &q1, &i2, &q2);
for (j = 0; j < rep; j++)
{
if (ret == 4 && tx_channels >= 4)
{
sample[i++] = ((unsigned long long) convert(scale, q2) << 48) |
((unsigned long long) convert(scale, i2) << 32) |
((unsigned long long) convert(scale, q1) << 16) |
((unsigned long long) convert(scale, i1) << 0);
if (tx_channels == 8)
sample[i++] = ((unsigned long long) convert(scale, q2) << 48) |
((unsigned long long) convert(scale, i2) << 32) |
((unsigned long long) convert(scale, q1) << 16) |
((unsigned long long) convert(scale, i1) << 0);
}
else if (ret == 2 && tx_channels >= 4)
{
sample[i++] = ((unsigned long long) convert(scale, q1) << 48) |
((unsigned long long) convert(scale, i1) << 32) |
((unsigned long long) convert(scale, q1) << 16) |
((unsigned long long) convert(scale, i1) << 0);
if (tx_channels == 8)
sample[i++] = ((unsigned long long) convert(scale, q1) << 48) |
((unsigned long long) convert(scale, i1) << 32) |
((unsigned long long) convert(scale, q1) << 16) |
((unsigned long long) convert(scale, i1) << 0);
}
else if (ret > 1 && tx_channels == 2)
{
sample_32[i++] = ((unsigned int) convert(scale, q1) << 16) |
((unsigned int) convert(scale, i1) << 0);
}
else if (ret > 1 && tx_channels == 1)
{
sample_16[i++] = convert(scale, i1);
}
size += tx_channels * 2;
}
}
}
}
/*
* When we are in 1 TX mode it is possible that the number of bytes
* is not a multiple of 8, but only a multiple of 4. In this case
* we'll send the same buffer twice to make sure that it becomes a
* multiple of 8.
*/
while ((size % 8) != 0)
{
memcpy(*buf + size, *buf, size);
//memcpy(converse_buf + size, converse_buf, size);
size += size;
}
fclose(infile);
*count = size;
}
}
return 0;
}
/* simple configuration and streaming */
int main (int argc, char **argv)
{
// Streaming devices
struct iio_device *tx;
struct iio_device *rx;
// RX and TX sample counters
//size_t nrx = 0;
//size_t ntx = 0;
// Stream configurations
struct stream_cfg rxcfg;
struct stream_cfg txcfg;
// Listen to ctrl+c and assert
signal(SIGINT, shutdown);
// RX stream config
rxcfg.bw_hz = MHZ(2); // 2 MHz rf bandwidth
rxcfg.fs_hz = MHZ(2); // 2 MS/s rx sample rate
rxcfg.lo_hz = GHZ(2.5); // 2.5 GHz rf frequency
rxcfg.rfport = "A_BALANCED"; // port A (select for rf freq.)
// TX stream config
txcfg.bw_hz = MHZ(2); // 1.5 MHz rf bandwidth
txcfg.fs_hz = MHZ(2); // 2 MS/s tx sample rate
txcfg.lo_hz = GHZ(2.5); // 2.5 GHz rf frequency
txcfg.rfport = "A"; // port A (select for rf freq.)
printf("* Acquiring IIO context\n");
assert((ctx = iio_create_local_context()) && "No context"); ; // iio_create_network_context("192.168.0.1"); for nw
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);
//printf("* Creating non-cyclic IIO buffers with 1 MiS\n");
//rxbuf = iio_device_create_buffer(rx, 1024*1024, false); //Create an input or output buffer associated to the given device.
//txbuf = iio_device_create_buffer(tx, 1024*1024, false); //1024*1024:The number of samples that the buffer should contain
printf("* Starting IO streaming (press CTRL+C to cancel)\n");
FILE *infile;
ssize_t nbytes_rx, nbytes_tx;
void *p_dat, *p_end;
ptrdiff_t p_inc;
char *buf = NULL;
char *rcvbuf = NULL;
char *rcv_dest_buf = NULL;
struct stat st;
int ret;
int size = 0;
int s_size;
unsigned int buffer_channels = 4;
int cycle_i = 0;
char* file_name = "10.txt";
while (1)
{
ret = analyse_wavefile(file_name, &buf, &size, buffer_channels);
if (ret == -3)
return 0;
if (ret == -1 || buf == NULL)
{
stat(file_name, &st);
converse_buf = malloc(st.st_size);
buf = malloc(st.st_size);
if (buf == NULL)
printf("buf = NULL\n");
infile = fopen(file_name, "r");
size = fread(buf, 1, st.st_size, infile);
fclose(infile);
}
s_size = iio_device_get_sample_size(tx);
if (!s_size)
{
fprintf(stderr, "Unable to create buffer due to sample size: %s\n", strerror(errno));
free(buf);
free(converse_buf);
return 0;
}
txbuf = iio_device_create_buffer(tx, size / s_size, true);
if (!txbuf)
{
fprintf(stderr, "Unable to create buffer: %s\n", strerror(errno));
free(buf);
free(converse_buf);
return 0;
}
rxbuf = iio_device_create_buffer(rx, size / s_size, true);
if (!rxbuf)
{
printf("Can't creat the rxbuf\n");
}
// Refill RX buffer
nbytes_rx = iio_buffer_refill(rxbuf); //On success, the number of bytes read is returned
if (nbytes_rx < 0) { printf("Error refilling buf %d\n",(int) nbytes_rx); shutdown(0); }
iio_channel_convert_inverse(tx0_i, converse_buf, buf);
for(cycle_i = 0; cycle_i < 50; cycle_i ++)
printf("buf = %d\n", buf[cycle_i]);
for(cycle_i = 0; cycle_i < 50; cycle_i ++)
printf("converse_buf = %d\n", converse_buf[cycle_i]);
memcpy(iio_buffer_start(txbuf), converse_buf, iio_buffer_end(txbuf) - iio_buffer_start(txbuf));
iio_buffer_push(txbuf);
free(buf);
free(converse_buf);
rcvbuf = malloc(50);
rcv_dest_buf = malloc(50);
iio_channel_read(rx0_i, rxbuf, rcvbuf, 50);
iio_channel_convert(rx0_i, rcv_dest_buf, rcvbuf);
for(cycle_i = 0; cycle_i < 50; cycle_i ++)
printf("rcv_buf = %d\n", rcvbuf[cycle_i]);
for(cycle_i = 0; cycle_i < 50; cycle_i ++)
printf("rcv_converse_buf = %d\n", rcv_dest_buf[cycle_i]);
// READ: Get pointers to RX buf and read IQ from RX buf port 0
p_inc = iio_buffer_step(rxbuf);
p_end = iio_buffer_end(rxbuf);
for (p_dat = iio_buffer_first(rxbuf, rx0_i); p_dat < p_end; p_dat += p_inc)
{
printf("p_dat0 = %d ",((int16_t*)p_dat)[0]);
//printf("p_dat1 = %d\n",((int16_t*)p_dat)[1]);
}
free(rcvbuf);
free(rcv_dest_buf);
}
return 0;
}
Do this program have errors or lose some steps? I just need to receive datas similar to the 10.txt or datas after analyse_wavefile() or the hardware format datas. It means the point to point communication.
Thank you, friends.