Linux Audio

Check our new training course

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

/**
 * @addtogroup t_mbox
 * @{
 * @defgroup t_mbox_api test_mbox_api
 * @brief TestPurpose: verify data passing via mailbox APIs
 * - API coverage
 *   -# K_MBOX_DEFINE
 *   -# k_mbox_init
 *   -# k_mbox_put
 *   -# k_mbox_async_put
 *   -# k_mbox_get
 *   -# k_mbox_data_get
 *   -# k_mbox_data_block_get
 * @}
 */

#include <ztest.h>

#define TIMEOUT 100
#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
#define MAIL_LEN 64


/**TESTPOINT: init via K_MBOX_DEFINE*/
K_MBOX_DEFINE(kmbox);
K_MEM_POOL_DEFINE(mpooltx, 8, MAIL_LEN, 1, 4);
K_MEM_POOL_DEFINE(mpoolrx, 8, MAIL_LEN, 1, 4);

static struct k_mbox mbox;

static k_tid_t sender_tid, receiver_tid;

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

static struct k_sem end_sema, sync_sema;

static enum mmsg_type {
	PUT_GET_NULL = 0,
	PUT_GET_BUFFER,
	ASYNC_PUT_GET_BUFFER,
	ASYNC_PUT_GET_BLOCK,
	TARGET_SOURCE_THREAD_BUFFER,
	TARGET_SOURCE_THREAD_BLOCK,
	MAX_INFO_TYPE
} info_type;

static char data[MAX_INFO_TYPE][MAIL_LEN] = {
	"send/recv an empty message",
	"send/recv msg using a buffer",
	"async send/recv msg using a buffer",
	"async send/recv msg using a memory block",
	"specify target/source thread, using a buffer",
	"specify target/source thread, using a memory block"
};

static void tmbox_put(struct k_mbox *pmbox)
{
	struct k_mbox_msg mmsg;

	memset(&mmsg, 0, sizeof(mmsg));

	switch (info_type) {
	case PUT_GET_NULL:
		/**TESTPOINT: mbox sync put empty message*/
		mmsg.info = PUT_GET_NULL;
		mmsg.size = 0;
		mmsg.tx_data = NULL;
		mmsg.tx_target_thread = K_ANY;
		k_mbox_put(pmbox, &mmsg, K_FOREVER);
		break;
	case PUT_GET_BUFFER:
	/*fall through*/
	case TARGET_SOURCE_THREAD_BUFFER:
		/**TESTPOINT: mbox sync put buffer*/
		mmsg.info = PUT_GET_BUFFER;
		mmsg.size = sizeof(data[info_type]);
		mmsg.tx_data = data[info_type];
		if (info_type == TARGET_SOURCE_THREAD_BUFFER) {
			mmsg.tx_target_thread = receiver_tid;
		} else {
			mmsg.tx_target_thread = K_ANY;
		}
		k_mbox_put(pmbox, &mmsg, K_FOREVER);
		break;
	case ASYNC_PUT_GET_BUFFER:
		/**TESTPOINT: mbox async put buffer*/
		mmsg.info = ASYNC_PUT_GET_BUFFER;
		mmsg.size = sizeof(data[info_type]);
		mmsg.tx_data = data[info_type];
		mmsg.tx_target_thread = K_ANY;
		k_mbox_async_put(pmbox, &mmsg, &sync_sema);
		/*wait for msg being taken*/
		k_sem_take(&sync_sema, K_FOREVER);
		break;
	case ASYNC_PUT_GET_BLOCK:
	/*fall through*/
	case TARGET_SOURCE_THREAD_BLOCK:
		/**TESTPOINT: mbox async put mem block*/
		mmsg.info = ASYNC_PUT_GET_BLOCK;
		mmsg.size = MAIL_LEN;
		mmsg.tx_data = NULL;
		zassert_equal(k_mem_pool_alloc(&mpooltx, &mmsg.tx_block,
					       MAIL_LEN, K_NO_WAIT), 0, NULL);
		memcpy(mmsg.tx_block.data, data[info_type], MAIL_LEN);
		if (info_type == TARGET_SOURCE_THREAD_BLOCK) {
			mmsg.tx_target_thread = receiver_tid;
		} else {
			mmsg.tx_target_thread = K_ANY;
		}
		k_mbox_async_put(pmbox, &mmsg, &sync_sema);
		/*wait for msg being taken*/
		k_sem_take(&sync_sema, K_FOREVER);
		break;
	default:
		break;
	}
}

static void tmbox_get(struct k_mbox *pmbox)
{
	struct k_mbox_msg mmsg;
	char rxdata[MAIL_LEN];
	struct k_mem_block rxblock;

	switch (info_type) {
	case PUT_GET_NULL:
		/**TESTPOINT: mbox sync get buffer*/
		mmsg.size = sizeof(rxdata);
		mmsg.rx_source_thread = K_ANY;
		/*verify return value*/
		zassert_true(k_mbox_get(pmbox, &mmsg, rxdata, K_FOREVER) == 0,
			     NULL);
		/*verify .info*/
		zassert_equal(mmsg.info, PUT_GET_NULL, NULL);
		/*verify .size*/
		zassert_equal(mmsg.size, 0, NULL);
		break;
	case PUT_GET_BUFFER:
	/*fall through*/
	case TARGET_SOURCE_THREAD_BUFFER:
		/**TESTPOINT: mbox sync get buffer*/
		mmsg.size = sizeof(rxdata);
		if (info_type == TARGET_SOURCE_THREAD_BUFFER) {
			mmsg.rx_source_thread = sender_tid;
		} else {
			mmsg.rx_source_thread = K_ANY;
		}
		zassert_true(k_mbox_get(pmbox, &mmsg, rxdata, K_FOREVER) == 0,
			     NULL);
		zassert_equal(mmsg.info, PUT_GET_BUFFER, NULL);
		zassert_equal(mmsg.size, sizeof(data[info_type]), NULL);
		/*verify rxdata*/
		zassert_true(memcmp(rxdata, data[info_type], MAIL_LEN) == 0,
			     NULL);
		break;
	case ASYNC_PUT_GET_BUFFER:
		/**TESTPOINT: mbox async get buffer*/
		mmsg.size = sizeof(rxdata);
		mmsg.rx_source_thread = K_ANY;
		zassert_true(k_mbox_get(pmbox, &mmsg, NULL, K_FOREVER) == 0,
			     NULL);
		zassert_equal(mmsg.info, ASYNC_PUT_GET_BUFFER, NULL);
		zassert_equal(mmsg.size, sizeof(data[info_type]), NULL);
		k_mbox_data_get(&mmsg, rxdata);
		zassert_true(memcmp(rxdata, data[info_type], MAIL_LEN) == 0,
			     NULL);
		break;
	case ASYNC_PUT_GET_BLOCK:
	/*fall through*/
	case TARGET_SOURCE_THREAD_BLOCK:
		/**TESTPOINT: mbox async get mem block*/
		mmsg.size = MAIL_LEN;
		if (info_type == TARGET_SOURCE_THREAD_BLOCK) {
			mmsg.rx_source_thread = sender_tid;
		} else {
			mmsg.rx_source_thread = K_ANY;
		}
		zassert_true(k_mbox_get(pmbox, &mmsg, NULL, K_FOREVER) == 0,
			     NULL);
		zassert_true(k_mbox_data_block_get
				     (&mmsg, &mpoolrx, &rxblock, K_FOREVER) == 0, NULL);
		zassert_equal(mmsg.info, ASYNC_PUT_GET_BLOCK, NULL);
		zassert_equal(mmsg.size, MAIL_LEN, NULL);
		/*verify rxblock*/
		zassert_true(memcmp(rxblock.data, data[info_type], MAIL_LEN)
			     == 0, NULL);
		k_mem_pool_free(&rxblock);
		break;
	default:
		break;
	}
}

/*entry of contexts*/
static void tmbox_entry(void *p1, void *p2, void *p3)
{
	tmbox_get((struct k_mbox *)p1);
	k_sem_give(&end_sema);
}

static void tmbox(struct k_mbox *pmbox)
{
	/*test case setup*/
	k_sem_reset(&end_sema);
	k_sem_reset(&sync_sema);

	/**TESTPOINT: thread-thread data passing via mbox*/
	sender_tid = k_current_get();
	receiver_tid = k_thread_create(&tdata, tstack, STACK_SIZE,
				       tmbox_entry, pmbox, NULL, NULL,
				       K_PRIO_PREEMPT(0), 0, 0);
	tmbox_put(pmbox);
	k_sem_take(&end_sema, K_FOREVER);

	/*test case teardown*/
	k_thread_abort(receiver_tid);
}

/*test cases*/
void test_mbox_kinit(void)
{
	/**TESTPOINT: init via k_mbox_init*/
	k_mbox_init(&mbox);
	k_sem_init(&end_sema, 0, 1);
	k_sem_init(&sync_sema, 0, 1);
}

void test_mbox_kdefine(void)
{
	info_type = PUT_GET_NULL;
	tmbox(&kmbox);
}

void test_mbox_put_get_null(void)
{
	info_type = PUT_GET_NULL;
	tmbox(&mbox);
}

void test_mbox_put_get_buffer(void)
{
	info_type = PUT_GET_BUFFER;
	tmbox(&mbox);
}

void test_mbox_async_put_get_buffer(void)
{
	info_type = ASYNC_PUT_GET_BUFFER;
	tmbox(&mbox);
}

void test_mbox_async_put_get_block(void)
{
	info_type = ASYNC_PUT_GET_BLOCK;
	tmbox(&mbox);
}

void test_mbox_target_source_thread_buffer(void)
{
	info_type = TARGET_SOURCE_THREAD_BUFFER;
	tmbox(&mbox);
}

void test_mbox_target_source_thread_block(void)
{
	info_type = TARGET_SOURCE_THREAD_BLOCK;
	tmbox(&mbox);
}