Skip to content

Commit

Permalink
Add C based hardware tests for AD9361 buffers
Browse files Browse the repository at this point in the history
Signed-off-by: Travis F. Collins <travis.collins@analog.com>
  • Loading branch information
tfcollins committed Dec 15, 2023
1 parent 7a2dd7e commit 9902e76
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 0 deletions.
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
add_definitions(-UNDEBUG)
if(TESTS_DEBUG)
add_definitions(-DTESTS_DEBUG)
endif()
add_subdirectory(standalone)
add_subdirectory(hardware)
6 changes: 6 additions & 0 deletions tests/hardware/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_executable(TestBufferAD9361 test_ad9364.c)
target_link_libraries(TestBufferAD9361 LINK_PRIVATE iio)
add_test(
NAME TestBufferAD9361
COMMAND TestBufferAD9361
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
220 changes: 220 additions & 0 deletions tests/hardware/test_ad9364.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// This test is designed to verify data from transmit to receive buffers by
// using a ramp signal. The ramp signal is generated on the TX side and then
// received on the RX side. The RX side then checks to make sure the ramp is
// continuous within the buffer but not across buffers. However, every buffer is
// checked to make sure the ramp is continuous.

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "iio/iio.h"

#ifndef TESTS_DEBUG
#define TESTS_DEBUG 0
#endif

// Use (void) to silence unused warnings.
#define assertm(exp, msg) assert(((void)msg, exp))

#define dprintf(fmt, ...) \
do { \
if (TESTS_DEBUG>0) \
fprintf(stderr, fmt, ##__VA_ARGS__); \
} while (0)

// User Set
#define N_TX_SAMPLES 128
#define RX_OVERSAMPLE 4
#define SUCCESSIVE_BUFFER_TO_CHECK 31
#define N_RX_BLOCKS 4

// Calculated/Constant
#define N_RX_SAMPLES N_TX_SAMPLES *RX_OVERSAMPLE
#define N_CHANNELS 2
#define BYTES_PER_SAMPLE 2

struct iio_context *ctx;
struct iio_device *phy, *rx, *tx;
const struct iio_attr *attr;
struct iio_channel *chn;
struct iio_channels_mask *txmask, *rxmask;
struct iio_buffer *txbuf, *rxbuf;
struct iio_block *txblock;
const struct iio_block *rxblock;
struct iio_stream *rxstream;

int main() {

int err;

const char *uri = getenv("URI_AD9361");
if (uri == NULL)
exit(0); // Cant find anything don't run tests

Check failure on line 54 in tests/hardware/test_ad9364.c

View workflow job for this annotation

GitHub Actions / Check for spelling errors

Cant ==> Can't
ctx = iio_create_context(NULL, uri);

phy = iio_context_find_device(ctx, "ad9361-phy");
assertm(phy, "Unable to find AD9361-phy device");
rx = iio_context_find_device(ctx, "cf-ad9361-lpc");
assertm(rx, "Unable to find RX device");
tx = iio_context_find_device(ctx, "cf-ad9361-dds-core-lpc");
assertm(tx, "Unable to find TX device");

// Configure device into loopback mode
attr = iio_device_find_debug_attr(phy, "loopback");
assertm(attr, "Unable to find loopback attribute");
iio_attr_write_string(attr, "1");

// TX Side
txmask = iio_create_channels_mask(iio_device_get_channels_count(tx));
assertm(txmask, "Unable to create TX mask");

chn = iio_device_find_channel(tx, "voltage0", true);
assertm(chn, "Unable to find TX channel");
iio_channel_enable(chn, txmask);
chn = iio_device_find_channel(tx, "voltage1", true);
assertm(chn, "Unable to find TX channel");
iio_channel_enable(chn, txmask);

txbuf = iio_device_create_buffer(tx, 0, txmask);
assertm(txbuf, "Unable to create TX buffer");

txblock = iio_buffer_create_block(txbuf, N_TX_SAMPLES * BYTES_PER_SAMPLE *
N_CHANNELS);
assertm(txblock, "Unable to create TX block");

// Generate ramp signal on both I and Q channels
int16_t *p_dat, *p_end;
ptrdiff_t p_inc;
int16_t idx = 0;

p_end = iio_block_end(txblock);
p_inc = iio_device_get_sample_size(tx, txmask);
chn = iio_device_find_channel(tx, "voltage0", true);

for (p_dat = iio_block_first(txblock, chn); p_dat < p_end;
p_dat += p_inc / sizeof(*p_dat)) {
// Bitshift 4 bits up. During loopback hardware will shift back 4 bits
p_dat[0] = idx << 4;
p_dat[1] = idx << 4;
idx++;
}
iio_block_enqueue(txblock, 0, true);
iio_buffer_enable(txbuf);
sleep(2);

// RX Side
rxmask = iio_create_channels_mask(iio_device_get_channels_count(rx));
assertm(rxmask, "Unable to create RX mask");

chn = iio_device_find_channel(rx, "voltage0", false);
assertm(chn, "Unable to find RX channel voltage0");
iio_channel_enable(chn, rxmask);
chn = iio_device_find_channel(rx, "voltage1", false);
assertm(chn, "Unable to find RX channel voltage1");
iio_channel_enable(chn, rxmask);

rxbuf = iio_device_create_buffer(rx, 0, rxmask);
assertm(rxbuf, "Unable to create RX buffer");

rxstream = iio_buffer_create_stream(rxbuf, N_RX_BLOCKS, N_RX_SAMPLES);
assertm(rxstream, "Unable to create RX stream");

p_inc = iio_device_get_sample_size(rx, rxmask);
chn = iio_device_find_channel(rx, "voltage0", false);

bool found_start = false;
int16_t ramp_indx = 0;

// Create check vector
bool ramp_found_check_vector[SUCCESSIVE_BUFFER_TO_CHECK];
bool continuous_check_vector[SUCCESSIVE_BUFFER_TO_CHECK];

// Remove first few blocks as they might be old
for (int i = 0; i < 30; i++) {
rxblock = iio_stream_get_next_block(rxstream);
dprintf("Removing block %d\n", i);
}

// Check several buffers to make sure no glitches occurred
for (int i = 0; i < SUCCESSIVE_BUFFER_TO_CHECK; i++) {

dprintf("Checking buffer %d of %d\n", i + 1, SUCCESSIVE_BUFFER_TO_CHECK);

rxblock = iio_stream_get_next_block(rxstream);
p_end = iio_block_end(rxblock);

// Within a block data should be continuous but not necessarily across
// blocks
found_start = false;
continuous_check_vector[i] = true; // assume good
ramp_indx = 0;

for (p_dat = iio_block_first(rxblock, chn); p_dat < p_end;
p_dat += p_inc / sizeof(*p_dat)) {

// Locate top of ramp
if (p_dat[0] == (N_TX_SAMPLES - 1) && p_dat[1] == (N_TX_SAMPLES - 1) &&
!found_start) {
found_start = true;
continue; // Wrap to ramp restarts on next sample
}

// Make sure ramp is continuous
if (found_start) {
dprintf("Expected: %d\n", ramp_indx);
dprintf("Actual: %d, %d (I, Q)\n\n", p_dat[0], p_dat[1]);
if (p_dat[0] != ramp_indx && p_dat[1] != ramp_indx) {
dprintf("--->Expected: %d (Buffer %d)\n", ramp_indx, i);
dprintf("--->Actual: %d, %d (I, Q) [Buffer %d]\n\n", p_dat[0],
p_dat[1], i);
dprintf("\n\n");
continuous_check_vector[i] = false;
}
if (ramp_indx == (N_TX_SAMPLES - 1)) {
ramp_indx = 0;
} else
ramp_indx++;
}
}

ramp_found_check_vector[i] = found_start;
if (!found_start)
continuous_check_vector[i] = false;
}

// Examine check vector
bool failed_c1 = false;
bool failed_c2 = false;
dprintf("1 == Check Passed, 0 == Failed\n");
dprintf("Ramp Check, Contiguous Check (Buffer #)\n");

for (int i = 0; i < SUCCESSIVE_BUFFER_TO_CHECK; i++) {
dprintf("%d, %d (%d)\n", ramp_found_check_vector[i],
continuous_check_vector[i], i);
if (!ramp_found_check_vector[i])
failed_c1 = true;
if (!continuous_check_vector[i])
failed_c2 = true;
}
dprintf("\n");

assertm(!failed_c1, "Ramp was not found in all buffers");
assertm(!failed_c2, "Ramp was not contiguous in all buffers");

iio_stream_destroy(rxstream);
iio_buffer_destroy(rxbuf);

// // Manual check RX (disable asserts above first)
// printf("Open up the time scope to see data. Should be a ramp from
// 0->%d\n",
// idx - 1);
// sleep(40);

// Cleanup
iio_block_destroy(txblock);
iio_buffer_destroy(txbuf);

return 0;
}
1 change: 1 addition & 0 deletions tests/standalone/test_version.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "iio/iio.h"

Expand Down

0 comments on commit 9902e76

Please sign in to comment.