/*
* 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);