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