Linux Audio

Check our new training course

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

#include <zephyr/ztest.h>
#include <zephyr/kernel.h>

#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
#define MAIL_LEN 64
#define HIGH_PRIO 1
#define LOW_PRIO  8

static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
static K_THREAD_STACK_DEFINE(high_stack, STACK_SIZE);
static K_THREAD_STACK_DEFINE(low_stack, STACK_SIZE);

static struct k_thread tdata, high_tdata, low_tdata;
static struct k_mbox mbox, multi_tmbox;
static struct k_sem sync_sema;
static k_tid_t tid1, receiver_tid;
static char msg_data[2][MAIL_LEN] = {
	"send to high prio",
	"send to low prio"};

static enum mmsg_type {
	PUT_GET_NULL = 0,
	TARGET_SOURCE
} info_type;

static void msg_sender(struct k_mbox *pmbox, k_timeout_t timeout)
{
	static struct k_mbox_msg mmsg;

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

	switch (info_type) {
	case PUT_GET_NULL:
		/* mbox sync put empty message */
		mmsg.info = PUT_GET_NULL;
		mmsg.size = 0;
		mmsg.tx_data = NULL;
		if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
			k_mbox_put(pmbox, &mmsg, K_FOREVER);
		} else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
			k_mbox_put(pmbox, &mmsg, K_NO_WAIT);
		} else {
			k_mbox_put(pmbox, &mmsg, timeout);
		}
		break;
	default:
		break;
	}
}

static void msg_receiver(struct k_mbox *pmbox, k_tid_t thd_id,
			 k_timeout_t timeout)
{
	static struct k_mbox_msg mmsg;
	static char rxdata[MAIL_LEN];

	switch (info_type) {
	case PUT_GET_NULL:
		mmsg.size = sizeof(rxdata);
		mmsg.rx_source_thread = thd_id;
		if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
			zassert_true(k_mbox_get(pmbox, &mmsg,
				     rxdata, K_FOREVER) == 0, NULL);
		} else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
			zassert_false(k_mbox_get(pmbox, &mmsg,
				      rxdata, K_NO_WAIT) == 0, NULL);
		} else {
			zassert_true(k_mbox_get(pmbox, &mmsg,
				     rxdata, timeout) == 0, NULL);
		}
		break;
	default:
		break;
	}
}

static void test_mbox_init(void)
{
	k_mbox_init(&mbox);
	k_mbox_init(&multi_tmbox);

	k_sem_init(&sync_sema, 0, 2);
}

static void test_send(void *p1, void *p2, void *p3)
{
	msg_sender((struct k_mbox *)p1, K_NO_WAIT);
}

/* Receive message from any thread with no wait */
ZTEST(mbox_usage, test_msg_receiver)
{
	static k_tid_t tid;

	info_type = PUT_GET_NULL;
	msg_receiver(&mbox, K_ANY, K_NO_WAIT);

	tid = k_thread_create(&tdata, tstack, STACK_SIZE,
			      test_send, &mbox, NULL, NULL,
			      K_PRIO_PREEMPT(0), 0, K_NO_WAIT);

	msg_receiver(&mbox, K_ANY, K_MSEC(2));
	k_thread_abort(tid);
}

static void test_send_un(void *p1, void *p2, void *p3)
{
	TC_PRINT("Sender UNLIMITED\n");
	msg_sender((struct k_mbox *)p1, K_FOREVER);
}

/* Receive message from thread tid1 */
ZTEST(mbox_usage, test_msg_receiver_unlimited)
{
	info_type = PUT_GET_NULL;

	receiver_tid = k_current_get();
	tid1 = k_thread_create(&tdata, tstack, STACK_SIZE,
			      test_send_un, &mbox, NULL, NULL,
			      K_PRIO_PREEMPT(0), 0, K_NO_WAIT);

	msg_receiver(&mbox, tid1, K_FOREVER);
	k_thread_abort(tid1);
}

static void thread_low_prio(void *p1, void *p2, void *p3)
{
	static struct k_mbox_msg mmsg = {0};
	static char rxdata[MAIL_LEN];
	int ret;

	mmsg.rx_source_thread = K_ANY;
	mmsg.size = sizeof(rxdata);
	ret = k_mbox_get(&multi_tmbox, &mmsg, rxdata, K_FOREVER);

	zassert_equal(ret, 0, "low prio get msg failed");
	zassert_equal(memcmp(rxdata, msg_data[1], MAIL_LEN), 0,
		      "low prio data error");

	k_sem_give(&sync_sema);
}

static void thread_high_prio(void *p1, void *p2, void *p3)
{
	static struct k_mbox_msg mmsg = {0};
	static char rxdata[MAIL_LEN];
	int ret;

	mmsg.rx_source_thread = K_ANY;
	mmsg.size = sizeof(rxdata);
	ret = k_mbox_get(&multi_tmbox, &mmsg, rxdata, K_FOREVER);

	zassert_equal(ret, 0, "high prio get msg failed");
	zassert_equal(memcmp(rxdata, msg_data[0], MAIL_LEN), 0,
		      "high prio data error");

	k_sem_give(&sync_sema);
}

ZTEST_USER(mbox_usage_1cpu, test_multi_thread_send_get)
{
	static k_tid_t low_prio, high_prio;
	struct k_mbox_msg mmsg = {0};

	k_sem_reset(&sync_sema);
	/* Create diff priority thread to receive msg with same mbox */
	low_prio = k_thread_create(&low_tdata, low_stack, STACK_SIZE,
				  thread_low_prio, &multi_tmbox, NULL, NULL,
				  LOW_PRIO, 0, K_NO_WAIT);

	high_prio = k_thread_create(&high_tdata, high_stack, STACK_SIZE,
				    thread_high_prio, &multi_tmbox, NULL, NULL,
				    HIGH_PRIO, 0, K_NO_WAIT);

	k_sleep(K_MSEC(20));
	mmsg.size = sizeof(msg_data[0]);
	mmsg.tx_data = msg_data[0];
	mmsg.tx_target_thread = K_ANY;
	k_mbox_put(&multi_tmbox, &mmsg, K_FOREVER);

	mmsg.size = sizeof(msg_data[1]);
	mmsg.tx_data = msg_data[1];
	mmsg.tx_target_thread = K_ANY;
	k_mbox_put(&multi_tmbox, &mmsg, K_FOREVER);

	/* Sync with threads to ensure process end */
	k_sem_take(&sync_sema, K_FOREVER);
	k_sem_take(&sync_sema, K_FOREVER);

	k_thread_abort(low_prio);
	k_thread_abort(high_prio);
}

void *setup_mbox_usage(void)
{
	test_mbox_init();

	return NULL;
}

ZTEST_SUITE(mbox_usage, NULL, setup_mbox_usage, NULL, NULL, NULL);

ZTEST_SUITE(mbox_usage_1cpu, NULL, setup_mbox_usage,
	ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);