blob: fb5dca3e961efe05ed2ead2268b7cb32754b6340 [file] [log] [blame]
/*
* Copyright (c) 2023 Rodrigo Peixoto <rodrigopex@gmail.com>
* SPDX-License-Identifier: Apache-2.0
*/
#include "messages.h"
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/zbus/zbus.h>
#include <zephyr/ztest.h>
LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL);
#define STACK_SIZE (CONFIG_MAIN_STACK_SIZE + CONFIG_TEST_EXTRA_STACK_SIZE)
static struct k_thread pub_thread;
static K_THREAD_STACK_DEFINE(pub_thread_sz, STACK_SIZE);
static struct k_thread s1_thread;
static K_THREAD_STACK_DEFINE(s1_thread_sz, STACK_SIZE);
static struct k_thread ms1_thread;
static K_THREAD_STACK_DEFINE(ms1_thread_sz, STACK_SIZE);
struct msg_testing_01 {
int seq;
bool must_detach;
};
ZBUS_CHAN_DEFINE(chan_testing_01, /* Name */
struct msg_testing_01, /* Message type */
NULL, /* Validator */
NULL, /* User data */
ZBUS_OBSERVERS(lis1, sub1, msub1), /* observers */
ZBUS_MSG_INIT(0) /* Initial value major 0, minor 1, build 1023 */
);
static void consumer_sub_thread(void *ptr1, void *ptr2, void *ptr3)
{
ARG_UNUSED(ptr3);
zbus_obs_attach_to_thread(ptr1);
char *name = ptr2;
struct zbus_observer *sub = ptr1;
const struct zbus_channel *chan;
struct msg_testing_01 msg;
while (1) {
if (zbus_sub_wait(sub, &chan, K_FOREVER) != 0) {
k_oops();
}
zbus_chan_read(chan, &msg, K_FOREVER);
printk("%s level: %d\n", name, msg.seq);
if (msg.must_detach) {
zbus_obs_detach_from_thread(sub);
}
}
}
ZBUS_SUBSCRIBER_DEFINE(sub1, 4);
static void consumer_msg_sub_thread(void *ptr1, void *ptr2, void *ptr3)
{
ARG_UNUSED(ptr3);
zbus_obs_attach_to_thread(ptr1);
char *name = ptr2;
struct zbus_observer *msub = ptr1;
const struct zbus_channel *chan;
struct msg_testing_01 msg;
while (1) {
if (zbus_sub_wait_msg(msub, &chan, &msg, K_FOREVER) != 0) {
k_oops();
}
printk("%s level: %d\n", name, msg.seq);
if (msg.must_detach) {
zbus_obs_detach_from_thread(msub);
}
}
}
ZBUS_MSG_SUBSCRIBER_DEFINE(msub1);
static K_SEM_DEFINE(sync_sem, 1, 1);
static K_SEM_DEFINE(done_sem, 0, 1);
static struct msg_testing_01 msg = {.seq = 0};
static void publisher_thread(void *ptr1, void *ptr2, void *ptr3)
{
ARG_UNUSED(ptr1);
ARG_UNUSED(ptr2);
ARG_UNUSED(ptr3);
while (1) {
k_sem_take(&sync_sem, K_FOREVER);
zbus_chan_pub(&chan_testing_01, &msg, K_FOREVER);
k_msleep(100);
k_sem_give(&done_sem);
}
}
static inline void _pub_and_sync(void)
{
k_sem_give(&sync_sem);
k_sem_take(&done_sem, K_FOREVER);
}
static k_tid_t pub_thread_id;
static int prio;
static void listener_callback(const struct zbus_channel *chan)
{
prio = k_thread_priority_get(pub_thread_id);
}
ZBUS_LISTENER_DEFINE(lis1, listener_callback);
ZTEST(hlp_priority_boost, test_priority_elevation)
{
pub_thread_id = k_thread_create(&pub_thread, pub_thread_sz, STACK_SIZE, publisher_thread,
NULL, NULL, NULL, K_PRIO_PREEMPT(8), 0, K_NO_WAIT);
(void)k_thread_create(&s1_thread, s1_thread_sz, STACK_SIZE, consumer_sub_thread, &sub1,
"sub1", NULL, K_PRIO_PREEMPT(3), 0, K_NO_WAIT);
(void)k_thread_create(&ms1_thread, ms1_thread_sz, STACK_SIZE, consumer_msg_sub_thread,
&msub1, "msub1", NULL, K_PRIO_PREEMPT(2), 0, K_NO_WAIT);
_pub_and_sync();
zassert_true(prio == 1, "The priority must be 1, but it is %d", prio);
++msg.seq;
zbus_obs_set_enable(&msub1, false);
_pub_and_sync();
zassert_true(prio == 2, "The priority must be 2, but it is %d", prio);
zbus_obs_set_enable(&msub1, true);
++msg.seq;
_pub_and_sync();
zassert_true(prio == 1, "The priority must be 1, but it is %d", prio);
++msg.seq;
zbus_obs_set_chan_notification_mask(&msub1, &chan_testing_01, true);
bool is_masked;
zbus_obs_is_chan_notification_masked(&msub1, &chan_testing_01, &is_masked);
zassert_true(is_masked, NULL);
_pub_and_sync();
zassert_true(prio == 2, "The priority must be 2, but it is %d", prio);
zbus_obs_set_chan_notification_mask(&msub1, &chan_testing_01, false);
++msg.seq;
zbus_obs_set_enable(&msub1, false);
zbus_obs_set_enable(&sub1, false);
_pub_and_sync();
zassert_true(prio == 8, "The priority must be 8, but it is %d", prio);
zbus_obs_set_chan_notification_mask(&msub1, &chan_testing_01, false);
zbus_obs_set_enable(&msub1, true);
zbus_obs_set_enable(&sub1, true);
++msg.seq;
msg.must_detach = true;
_pub_and_sync();
zassert_true(prio == 1, "The priority must be 1, but it is %d", prio);
++msg.seq;
/* Checking if the detach command took effect on both observers */
_pub_and_sync();
zassert_true(prio == 8, "The priority must be 8, but it is %d", prio);
}
ZTEST_SUITE(hlp_priority_boost, NULL, NULL, NULL, NULL, NULL);