Skip to content

Commit 835d75a

Browse files
nunojsapcercuei
authored andcommitted
examples: add example for adrv9002
This is analogous to adrv9009-iiostream. Just serves as an example on how to stream data on adrv9002 using libiio. Signed-off-by: Nuno Sá <[email protected]>
1 parent e8be2c7 commit 835d75a

File tree

2 files changed

+314
-1
lines changed

2 files changed

+314
-1
lines changed

examples/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ project(ad9361-iiostream C)
44
project(ad9371-iiostream C)
55
project(adrv9009-iiostream C)
66
project(dummy-iiostream C)
7+
project(adrv9002-iiostream C)
78

89
if (APPLE)
910
# Add relative rpath to iio library (which is in the same framework)
@@ -37,15 +38,19 @@ add_executable(
3738
add_executable(
3839
adrv9009-iiostream adrv9009-iiostream.c ${GETOPT_C_FILE} ${LIBIIO_RC}
3940
)
41+
add_executable(
42+
adrv9002-iiostream adrv9002-iiostream.c ${GETOPT_C_FILE} ${LIBIIO_RC}
43+
)
4044
add_executable(dummy-iiostream dummy-iiostream.c ${GETOPT_C_FILE} ${LIBIIO_RC})
4145

4246
target_link_libraries(ad9361-iiostream iio)
4347
target_link_libraries(ad9371-iiostream iio)
4448
target_link_libraries(adrv9009-iiostream iio)
4549
target_link_libraries(dummy-iiostream iio)
50+
target_link_libraries(adrv9002-iiostream iio)
4651

4752
set(IIO_EXAMPLES_TARGETS ad9361-iiostream ad9371-iiostream adrv9009-iiostream
48-
dummy-iiostream
53+
dummy-iiostream adrv9002-iiostream
4954
)
5055

5156
find_library(PTHREAD_LIBRARIES pthread)

examples/adrv9002-iiostream.c

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
/*
3+
* libiio - Library for interfacing industrial I/O (IIO) devices
4+
*
5+
* Copyright (C) 2021 Analog Devices, Inc.
6+
* Author: Nuno Sá <[email protected]>
7+
*/
8+
#include <iio.h>
9+
#include <stdio.h>
10+
#include <stdint.h>
11+
#include <signal.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
#include <errno.h>
15+
#include <stdbool.h>
16+
17+
#define ARGS(fmt, ...) __VA_ARGS__
18+
#define FMT(fmt, ...) fmt
19+
#define error(...) \
20+
printf("%s, %d: ERROR: " FMT(__VA_ARGS__, 0)"%s", __func__, __LINE__, ARGS(__VA_ARGS__, ""))
21+
22+
#define info(...) \
23+
printf("%s, %d: INFO: " FMT(__VA_ARGS__, 0)"%s", __func__, __LINE__, ARGS(__VA_ARGS__, ""))
24+
25+
/* helper macros */
26+
#define GHZ(x) ((long long)(x * 1000000000.0 + .5))
27+
28+
static bool stop = false;
29+
static struct iio_context *ctx = NULL;
30+
static struct iio_buffer *rxbuf = NULL;
31+
static struct iio_buffer *txbuf = NULL;
32+
static struct iio_channel *rx_chan[2] = { NULL, NULL };
33+
static struct iio_channel *tx_chan[2] = { NULL, NULL };
34+
35+
enum {
36+
I_CHAN,
37+
Q_CHAN
38+
};
39+
40+
#ifdef _WIN32
41+
#include <windows.h>
42+
#include <io.h>
43+
#include <fcntl.h>
44+
45+
BOOL WINAPI sig_handler(DWORD dwCtrlType)
46+
{
47+
/* Runs in its own thread */
48+
switch (dwCtrlType) {
49+
case CTRL_C_EVENT:
50+
case CTRL_CLOSE_EVENT:
51+
stop = true;
52+
return true;
53+
default:
54+
return false;
55+
}
56+
}
57+
58+
static int register_signals(void)
59+
{
60+
if (!SetConsoleCtrlHandler(sig_handler, TRUE))
61+
return -1;
62+
63+
return 0;
64+
}
65+
#else
66+
static void sig_handler(int signum)
67+
{
68+
if (signum == SIGINT || signum == SIGTERM) {
69+
info("Exit....\n");
70+
stop = true;
71+
}
72+
}
73+
74+
static int register_signals(void)
75+
{
76+
struct sigaction sa = {0};
77+
sigset_t mask = {0};
78+
79+
sa.sa_handler = sig_handler;
80+
sigemptyset(&sa.sa_mask);
81+
sigemptyset(&mask);
82+
83+
if (sigaction(SIGTERM, &sa, NULL) < 0) {
84+
error("sigaction: %s\n", strerror(errno));
85+
return -1;
86+
}
87+
88+
if (sigaction(SIGINT, &sa, NULL) < 0) {
89+
error("sigaction: %s\n", strerror(errno));
90+
return -1;
91+
}
92+
93+
sigaddset(&mask, SIGINT);
94+
sigaddset(&mask, SIGTERM);
95+
/* make sure these signals are unblocked */
96+
if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
97+
error("sigprocmask: %s", strerror(errno));
98+
return -1;
99+
}
100+
101+
return 0;
102+
}
103+
#endif
104+
105+
static int configure_tx_lo(void)
106+
{
107+
struct iio_device *phy;
108+
struct iio_channel *chan;
109+
int ret;
110+
long long val;
111+
112+
phy = iio_context_find_device(ctx, "adrv9002-phy");
113+
if (!phy) {
114+
error("Could not find adrv9002_phy\n");
115+
return -ENODEV;
116+
}
117+
118+
chan = iio_device_find_channel(phy, "voltage0", true);
119+
if (!chan) {
120+
error("Could not find TX voltage0 channel\n");
121+
return -ENODEV;
122+
}
123+
124+
/* printout some useful info */
125+
ret = iio_channel_attr_read_longlong(chan, "rf_bandwidth", &val);
126+
if (ret)
127+
return ret;
128+
129+
info("adrv9002 bandwidth: %lld\n", val);
130+
131+
ret = iio_channel_attr_read_longlong(chan, "sampling_frequency", &val);
132+
if (ret)
133+
return ret;
134+
135+
info("adrv9002 sampling_frequency: %lld\n", val);
136+
137+
/* set the LO to 2.5GHz */
138+
val = GHZ(2.5);
139+
chan = iio_device_find_channel(phy, "altvoltage2", true);
140+
if (!chan) {
141+
error("Could not find TX LO channel\n");
142+
return -ENODEV;
143+
}
144+
145+
return iio_channel_attr_write_longlong(chan, "TX1_LO_frequency", val);
146+
}
147+
148+
static void cleanup(void)
149+
{
150+
int c;
151+
152+
if (rxbuf)
153+
iio_buffer_destroy(rxbuf);
154+
155+
if (txbuf)
156+
iio_buffer_destroy(txbuf);
157+
158+
for (c = 0; c < 2; c++) {
159+
if (rx_chan[c])
160+
iio_channel_disable(rx_chan[c]);
161+
162+
if (tx_chan[c])
163+
iio_channel_disable(tx_chan[c]);
164+
}
165+
166+
iio_context_destroy(ctx);
167+
}
168+
169+
static int stream_channels_get_enable(const struct iio_device *dev, struct iio_channel **chan,
170+
bool tx)
171+
{
172+
int c;
173+
const char * const channels[] = {
174+
"voltage0_i", "voltage0_q", "voltage0", "voltage1"
175+
};
176+
177+
for (c = 0; c < 2; c++) {
178+
const char *str = channels[tx * 2 + c];
179+
180+
chan[c] = iio_device_find_channel(dev, str, tx);
181+
if (!chan[c]) {
182+
error("Could not find %s channel tx=%d\n", str, tx);
183+
return -ENODEV;
184+
}
185+
186+
iio_channel_enable(chan[c]);
187+
}
188+
189+
return 0;
190+
}
191+
192+
static void stream(ssize_t rx_sample, ssize_t tx_sample)
193+
{
194+
const struct iio_channel *rx_i_chan = rx_chan[I_CHAN];
195+
const struct iio_channel *tx_i_chan = tx_chan[I_CHAN];
196+
ssize_t nrx = 0;
197+
ssize_t ntx = 0;
198+
199+
while (!stop) {
200+
ssize_t nbytes_rx, nbytes_tx;
201+
int16_t *p_dat, *p_end;
202+
ptrdiff_t p_inc;
203+
204+
205+
nbytes_tx = iio_buffer_push(txbuf);
206+
if (nbytes_tx < 0) {
207+
error("Error pushing buf %zd\n", nbytes_tx);
208+
return;
209+
}
210+
211+
nbytes_rx = iio_buffer_refill(rxbuf);
212+
if (nbytes_rx < 0) {
213+
error("Error refilling buf %zd\n", nbytes_rx);
214+
return;
215+
}
216+
217+
/* READ: Get pointers to RX buf and read IQ from RX buf port 0 */
218+
p_inc = iio_buffer_step(rxbuf);
219+
p_end = iio_buffer_end(rxbuf);
220+
for (p_dat = iio_buffer_first(rxbuf, rx_i_chan); p_dat < p_end;
221+
p_dat += p_inc / sizeof(*p_dat)) {
222+
/* Example: swap I and Q */
223+
int16_t i = p_dat[0];
224+
int16_t q = p_dat[1];
225+
226+
p_dat[0] = q;
227+
p_dat[1] = i;
228+
}
229+
230+
/* WRITE: Get pointers to TX buf and write IQ to TX buf port 0 */
231+
p_inc = iio_buffer_step(txbuf);
232+
p_end = iio_buffer_end(txbuf);
233+
for (p_dat = iio_buffer_first(txbuf, tx_i_chan); p_dat < p_end;
234+
p_dat += p_inc / sizeof(*p_dat)) {
235+
p_dat[0] = 0; /* Real (I) */
236+
p_dat[1] = 0; /* Imag (Q) */
237+
}
238+
239+
nrx += nbytes_rx / rx_sample;
240+
ntx += nbytes_tx / tx_sample;
241+
info("\tRX %8.2f MSmp, TX %8.2f MSmp\n", nrx / 1e6, ntx / 1e6);
242+
}
243+
}
244+
245+
int main(void)
246+
{
247+
struct iio_device *tx;
248+
struct iio_device *rx;
249+
ssize_t tx_sample_sz, rx_sample_sz;
250+
int ret;
251+
252+
if (register_signals() < 0)
253+
return EXIT_FAILURE;
254+
255+
ctx = iio_create_default_context();
256+
if (!ctx) {
257+
error("Could not create IIO context\n");
258+
return EXIT_FAILURE;
259+
}
260+
261+
ret = configure_tx_lo();
262+
if (ret)
263+
goto clean;
264+
265+
tx = iio_context_find_device(ctx, "axi-adrv9002-tx-lpc");
266+
if (!tx) {
267+
ret = EXIT_FAILURE;
268+
goto clean;
269+
}
270+
271+
rx = iio_context_find_device(ctx, "axi-adrv9002-rx-lpc");
272+
if (!rx) {
273+
ret = EXIT_FAILURE;
274+
goto clean;
275+
}
276+
277+
ret = stream_channels_get_enable(rx, rx_chan, false);
278+
if (ret)
279+
goto clean;
280+
281+
ret = stream_channels_get_enable(tx, tx_chan, true);
282+
if (ret)
283+
goto clean;
284+
285+
info("* Creating non-cyclic IIO buffers with 1 MiS\n");
286+
rxbuf = iio_device_create_buffer(rx, 1024 * 1024, false);
287+
if (!rxbuf) {
288+
error("Could not create RX buffer: %s\n", strerror(errno));
289+
ret = EXIT_FAILURE;
290+
goto clean;
291+
}
292+
293+
txbuf = iio_device_create_buffer(tx, 1024 * 1024, false);
294+
if (!txbuf) {
295+
error("Could not create TX buffer: %s\n", strerror(errno));
296+
ret = EXIT_FAILURE;
297+
goto clean;
298+
}
299+
300+
tx_sample_sz = iio_device_get_sample_size(tx);
301+
rx_sample_sz = iio_device_get_sample_size(rx);
302+
303+
stream(rx_sample_sz, tx_sample_sz);
304+
305+
clean:
306+
cleanup();
307+
return ret;
308+
}

0 commit comments

Comments
 (0)