Linux Audio

Check our new training course

Loading...
/*
 * Copyright (c) 2018 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/*
 * @file
 * @brief Use fifo API's in different scenarios
 *
 * This module tests following three basic scenarios:
 *
 * Scenario #1
 * Test Thread enters items into a fifo, starts the Child Thread
 * and waits for a semaphore. Child thread extracts all items from
 * the fifo and enters some items back into the fifo.  Child Thread
 * gives the semaphore for Test Thread to continue.  Once the control
 * is returned back to Test Thread, it extracts all items from the fifo.
 *
 * Scenario #2
 * Test Thread enters an item into fifo2, starts a Child Thread and
 * extract an item from fifo1 once the item is there.  The Child Thread
 * will extract an item from fifo2 once the item is there and and enter
 * an item to fifo1.  The flow of control goes from Test Thread to
 * Child Thread and so forth.
 *
 * Scenario #3
 * Tests the ISR interfaces. Test thread puts items into fifo2 and gives
 * control to the Child thread. Child thread gets items from fifo2 and then
 * puts items into fifo1. Child thread gives back control to the Test thread
 * and Test thread gets the items from fifo1.
 * All the Push and Pop operations happen in ISR Context.
 */

#include <ztest.h>
#include <irq_offload.h>

#define STACK_SIZE	1024
#define LIST_LEN	4

struct fdata_t {
	sys_snode_t snode;
	u32_t data;
};

static K_FIFO_DEFINE(fifo1);
static K_FIFO_DEFINE(fifo2);

/* Data to put into FIFO */
static struct fdata_t data1[LIST_LEN];
static struct fdata_t data2[LIST_LEN];
static struct fdata_t data_isr[LIST_LEN];

static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
static struct k_thread tdata;
static struct k_sem end_sema;

/*entry of contexts*/
static void tIsr_entry_put(void *p)
{
	u32_t i;

	/* Put items into fifo */
	for (i = 0U; i < LIST_LEN; i++) {
		k_fifo_put((struct k_fifo *)p, (void *)&data_isr[i]);
	}
	zassert_false(k_fifo_is_empty((struct k_fifo *)p), NULL);
}

static void tIsr_entry_get(void *p)
{
	void *rx_data;
	u32_t i;

	/* Get items from fifo */
	for (i = 0U; i < LIST_LEN; i++) {
		rx_data = k_fifo_get((struct k_fifo *)p, K_NO_WAIT);
		zassert_equal(rx_data, (void *)&data_isr[i], NULL);
	}
	zassert_true(k_fifo_is_empty((struct k_fifo *)p), NULL);
}

static void thread_entry_fn_single(void *p1, void *p2, void *p3)
{
	void *rx_data;
	u32_t i;

	/* Get items from fifo */
	for (i = 0U; i < LIST_LEN; i++) {
		rx_data = k_fifo_get((struct k_fifo *)p1, K_NO_WAIT);
		zassert_equal(rx_data, (void *)&data1[i], NULL);
	}

	/* Put items into fifo */
	for (i = 0U; i < LIST_LEN; i++) {
		k_fifo_put((struct k_fifo *)p1, (void *)&data2[i]);
	}

	/* Give control back to Test thread */
	k_sem_give(&end_sema);
}

static void thread_entry_fn_dual(void *p1, void *p2, void *p3)
{
	void *rx_data;
	u32_t i;

	for (i = 0U; i < LIST_LEN; i++) {
		/* Get items from fifo2 */
		rx_data = k_fifo_get((struct k_fifo *)p2, K_FOREVER);
		zassert_equal(rx_data, (void *)&data2[i], NULL);

		/* Put items into fifo1 */
		k_fifo_put((struct k_fifo *)p1, (void *)&data1[i]);
	}
}

static void thread_entry_fn_isr(void *p1, void *p2, void *p3)
{
	/* Get items from fifo2 */
	irq_offload(tIsr_entry_get, p2);

	/* Put items into fifo1 */
	irq_offload(tIsr_entry_put, p1);

	/* Give control back to Test thread */
	k_sem_give(&end_sema);
}

/**
 * @addtogroup kernel_fifo_tests
 * @{
 */

/**
 * @brief Tests single fifo get and put operation in thread context
 * @details Test Thread enters items into a fifo, starts the Child Thread
 * and waits for a semaphore. Child thread extracts all items from
 * the fifo and enters some items back into the fifo.  Child Thread
 * gives the semaphore for Test Thread to continue.  Once the control
 * is returned back to Test Thread, it extracts all items from the fifo.
 * @see k_fifo_get(), k_fifo_is_empty(), k_fifo_put(), #K_FIFO_DEFINE(x)
 */
static void test_single_fifo_play(void)
{
	void *rx_data;
	u32_t i;

	/* Init kernel objects */
	k_sem_init(&end_sema, 0, 1);

	/* Put items into fifo */
	for (i = 0U; i < LIST_LEN; i++) {
		k_fifo_put(&fifo1, (void *)&data1[i]);
	}

	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
				thread_entry_fn_single, &fifo1, NULL, NULL,
				K_PRIO_PREEMPT(0), K_INHERIT_PERMS, 0);

	/* Let the child thread run */
	k_sem_take(&end_sema, K_FOREVER);

	/* Get items from fifo */
	for (i = 0U; i < LIST_LEN; i++) {
		rx_data = k_fifo_get(&fifo1, K_NO_WAIT);
		zassert_equal(rx_data, (void *)&data2[i], NULL);
	}

	/* Clear the spawn thread to avoid side effect */
	k_thread_abort(tid);
}

/**
 * @brief Tests dual fifo get and put operation in thread context
 * @details test Thread enters an item into fifo2, starts a Child Thread and
 * extract an item from fifo1 once the item is there.  The Child Thread
 * will extract an item from fifo2 once the item is there and and enter
 * an item to fifo1.  The flow of control goes from Test Thread to
 * Child Thread and so forth.
 * @see k_fifo_get(), k_fifo_is_empty(), k_fifo_put(), #K_FIFO_DEFINE(x)
 */
static void test_dual_fifo_play(void)
{
	void *rx_data;
	u32_t i;

	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
				thread_entry_fn_dual, &fifo1, &fifo2, NULL,
				K_PRIO_PREEMPT(0), K_INHERIT_PERMS, 0);

	for (i = 0U; i < LIST_LEN; i++) {
		/* Put item into fifo */
		k_fifo_put(&fifo2, (void *)&data2[i]);

		/* Get item from fifo */
		rx_data = k_fifo_get(&fifo1, K_FOREVER);
		zassert_equal(rx_data, (void *)&data1[i], NULL);
	}

	/* Clear the spawn thread to avoid side effect */
	k_thread_abort(tid);

}

/**
 * @brief Tests fifo put and get operation in interrupt context
 * @details Tests the ISR interfaces. Test thread puts items into fifo2
 * and gives control to the Child thread. Child thread gets items from
 * fifo2 and then puts items into fifo1. Child thread gives back control
 * to the Test thread and Test thread gets the items from fifo1.
 * All the Push and Pop operations happen in ISR Context.
 * @see k_fifo_get(), k_fifo_is_empty(), k_fifo_put(), #K_FIFO_DEFINE(x)
 */
static void test_isr_fifo_play(void)
{
	/* Init kernel objects */
	k_sem_init(&end_sema, 0, 1);

	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
				thread_entry_fn_isr, &fifo1, &fifo2, NULL,
				K_PRIO_PREEMPT(0), K_INHERIT_PERMS, 0);


	/* Put item into fifo */
	irq_offload(tIsr_entry_put, &fifo2);

	/* Let the child thread run */
	k_sem_take(&end_sema, K_FOREVER);

	/* Get item from fifo */
	irq_offload(tIsr_entry_get, &fifo1);

	/* Clear the spawn thread to avoid side effect */
	k_thread_abort(tid);
}

/**
 * @}
 */

/*test case main entry*/
void test_main(void)
{
	ztest_test_suite(test_fifo_usage,
			 ztest_unit_test(test_single_fifo_play),
			 ztest_unit_test(test_dual_fifo_play),
			 ztest_unit_test(test_isr_fifo_play));
	ztest_run_test_suite(test_fifo_usage);
}