This example libiio program is meant to exercise the features of IIO functionality on the AD9361 found on the AD-FMCOMMS2-EBZ, AD-FMCOMMS3-EBZ, and the ADRV9361-Z7035 RF SOM.
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#define MHZ(x) ((long long)(x*1000000.0 + .5))
#define GHZ(x) ((long long)(x*1000000000.0 + .5))
#define IIO_ENSURE(expr) { \
if (!(expr)) { \
(void) fprintf(stderr, "assertion failed (%s:%d)\n", __FILE__, __LINE__); \
(void) abort(); \
} \
}
enum iodev { RX, TX };
struct stream_cfg {
long long bw_hz;
long long fs_hz;
long long lo_hz;
const char* rfport;
};
static char tmpstr[64];
static bool stop;
static void shutdown(void)
{
printf("* Destroying buffers\n");
printf("* Disabling streaming channels\n");
printf("* Destroying context\n");
exit(0);
}
static void handle_sig(int sig)
{
printf("Waiting for process to finish... Got signal %d\n", sig);
stop = true;
}
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(); }
}
static void wr_ch_lli(
struct iio_channel *chn,
const char* what,
long long val)
{
}
static void wr_ch_str(
struct iio_channel *chn,
const char* what,
const char* str)
{
}
static char* get_ch_name(const char* type, int id)
{
snprintf(tmpstr, sizeof(tmpstr), "%s%d", type, id);
return tmpstr;
}
{
IIO_ENSURE(dev && "No ad9361-phy found");
return dev;
}
static bool get_ad9361_stream_dev(
enum iodev d,
struct iio_device **dev)
{
switch (d) {
default: IIO_ENSURE(0); return false;
}
}
static bool get_ad9361_stream_ch(
enum iodev d,
struct iio_device *dev,
int chid,
struct iio_channel **chn)
{
if (!*chn)
return *chn != NULL;
}
static bool get_phy_chan(
enum iodev d,
int chid,
struct iio_channel **chn)
{
switch (d) {
case RX: *chn =
iio_device_find_channel(get_ad9361_phy(), get_ch_name(
"voltage", chid),
false);
return *chn != NULL;
case TX: *chn =
iio_device_find_channel(get_ad9361_phy(), get_ch_name(
"voltage", chid),
true);
return *chn != NULL;
default: IIO_ENSURE(0); return false;
}
}
static bool get_lo_chan(
enum iodev d,
struct iio_channel **chn)
{
switch (d) {
case RX: *chn =
iio_device_find_channel(get_ad9361_phy(), get_ch_name(
"altvoltage", 0),
true);
return *chn != NULL;
case TX: *chn =
iio_device_find_channel(get_ad9361_phy(), get_ch_name(
"altvoltage", 1),
true);
return *chn != NULL;
default: IIO_ENSURE(0); return false;
}
}
bool cfg_ad9361_streaming_ch(struct stream_cfg *cfg, enum iodev type, int chid)
{
printf("* Acquiring AD9361 phy channel %d\n", chid);
if (!get_phy_chan(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);
printf("* Acquiring AD9361 %s lo channel\n", type == TX ? "TX" : "RX");
if (!get_lo_chan(type, &chn)) { return false; }
wr_ch_lli(chn, "frequency", cfg->lo_hz);
return true;
}
int main (int argc, char **argv)
{
size_t nrx = 0;
size_t ntx = 0;
struct stream_cfg rxcfg;
struct stream_cfg txcfg;
signal(SIGINT, handle_sig);
rxcfg.bw_hz = MHZ(2);
rxcfg.fs_hz = MHZ(2.5);
rxcfg.lo_hz = GHZ(2.5);
rxcfg.rfport = "A_BALANCED";
txcfg.bw_hz = MHZ(1.5);
txcfg.fs_hz = MHZ(2.5);
txcfg.lo_hz = GHZ(2.5);
txcfg.rfport = "A";
printf("* Acquiring IIO context\n");
if (argc == 1) {
}
else if (argc == 2) {
}
printf("* Acquiring AD9361 streaming devices\n");
IIO_ENSURE(get_ad9361_stream_dev(TX, &tx) && "No tx dev found");
IIO_ENSURE(get_ad9361_stream_dev(RX, &rx) && "No rx dev found");
printf("* Configuring AD9361 for streaming\n");
IIO_ENSURE(cfg_ad9361_streaming_ch(&rxcfg, RX, 0) && "RX port 0 not found");
IIO_ENSURE(cfg_ad9361_streaming_ch(&txcfg, TX, 0) && "TX port 0 not found");
printf("* Initializing AD9361 IIO streaming channels\n");
IIO_ENSURE(get_ad9361_stream_ch(RX, rx, 0, &rx0_i) && "RX chan i not found");
IIO_ENSURE(get_ad9361_stream_ch(RX, rx, 1, &rx0_q) && "RX chan q not found");
IIO_ENSURE(get_ad9361_stream_ch(TX, tx, 0, &tx0_i) && "TX chan i not found");
IIO_ENSURE(get_ad9361_stream_ch(TX, tx, 1, &tx0_q) && "TX chan q not found");
printf("* Enabling IIO streaming channels\n");
printf("* Creating non-cyclic IIO buffers with 1 MiS\n");
if (!rxbuf) {
perror("Could not create RX buffer");
shutdown();
}
if (!txbuf) {
perror("Could not create TX buffer");
shutdown();
}
printf("* Starting IO streaming (press CTRL+C to cancel)\n");
while (!stop)
{
ssize_t nbytes_rx, nbytes_tx;
char *p_dat, *p_end;
ptrdiff_t p_inc;
if (nbytes_tx < 0) { printf("Error pushing buf %d\n", (int) nbytes_tx); shutdown(); }
if (nbytes_rx < 0) { printf("Error refilling buf %d\n",(int) nbytes_rx); shutdown(); }
for (p_dat = (
char *)
iio_buffer_first(rxbuf, rx0_i); p_dat < p_end; p_dat += p_inc) {
const int16_t i = ((int16_t*)p_dat)[0];
const int16_t q = ((int16_t*)p_dat)[1];
((int16_t*)p_dat)[0] = q;
((int16_t*)p_dat)[1] = i;
}
for (p_dat = (
char *)
iio_buffer_first(txbuf, tx0_i); p_dat < p_end; p_dat += p_inc) {
((int16_t*)p_dat)[0] = 0 << 4;
((int16_t*)p_dat)[1] = 0 << 4;
}
printf("\tRX %8.2f MSmp, TX %8.2f MSmp\n", nrx/1e6, ntx/1e6);
}
shutdown();
return 0;
}
void * iio_buffer_first(const struct iio_buffer *buffer, const struct iio_channel *chn)
Find the first sample of a channel in a buffer.
Definition: buffer.c:250
ptrdiff_t iio_buffer_step(const struct iio_buffer *buffer)
Get the step size between two samples of one channel.
Definition: buffer.c:288
void * iio_buffer_end(const struct iio_buffer *buffer)
Get the address that follows the last sample in a buffer.
Definition: buffer.c:293
void iio_buffer_destroy(struct iio_buffer *buffer)
Destroy the given buffer.
Definition: buffer.c:104
ssize_t iio_buffer_refill(struct iio_buffer *buffer)
Fetch more samples from the hardware.
Definition: buffer.c:123
ssize_t iio_buffer_push(struct iio_buffer *buffer)
Send the samples to the hardware.
Definition: buffer.c:147
struct iio_buffer * iio_device_create_buffer(const struct iio_device *dev, size_t samples_count, bool cyclic)
Create an input or output buffer associated to the given device.
Definition: buffer.c:26
void iio_channel_enable(struct iio_channel *chn)
Enable the given channel.
Definition: channel.c:452
ssize_t iio_channel_attr_write(const struct iio_channel *chn, const char *attr, const char *src)
Set the value of the given channel-specific attribute.
Definition: channel.c:419
int iio_channel_attr_write_longlong(const struct iio_channel *chn, const char *attr, long long val)
Set the value of the given channel-specific attribute.
Definition: channel.c:729
void iio_channel_disable(struct iio_channel *chn)
Disable the given channel.
Definition: channel.c:458
struct iio_context * iio_create_default_context(void)
Create a context from local or remote IIO devices.
Definition: context.c:415
void iio_context_destroy(struct iio_context *ctx)
Destroy the given context.
Definition: context.c:258
unsigned int iio_context_get_devices_count(const struct iio_context *ctx)
Enumerate the devices found in the given context.
Definition: context.c:280
struct iio_device * iio_context_find_device(const struct iio_context *ctx, const char *name)
Try to find a device structure by its ID, label or name.
Definition: context.c:294
struct iio_context * iio_create_context_from_uri(const char *uri)
Create a context from a URI description.
Definition: context.c:394
ssize_t iio_device_get_sample_size(const struct iio_device *dev)
Get the current sample size.
Definition: device.c:483
struct iio_channel * iio_device_find_channel(const struct iio_device *dev, const char *name, bool output)
Try to find a channel structure by its name of ID.
Definition: device.c:157
An input or output buffer, used to read or write samples.
Represents an input or output channel of a device.
Contains the representation of an IIO context.
Represents a device in the IIO context.