From be56440eaa9be9505faeb964d2a2d9f2a783ea6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Thu, 23 Jan 2025 14:41:55 +0100 Subject: [PATCH 1/2] Bluetooth: Mesh: fix NO_ACTIONS scheduling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the Scheduler Setup Server receives a Scheduler Action Set message setting the next scheduled task to NO_ACTIONS, it will schedule the next task in line. Previously, the "canceled" task would be executed if it was first in line. Signed-off-by: Håvard Reierstad --- subsys/bluetooth/mesh/scheduler_srv.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/subsys/bluetooth/mesh/scheduler_srv.c b/subsys/bluetooth/mesh/scheduler_srv.c index ffd0c65eacd5..da31af8d7294 100644 --- a/subsys/bluetooth/mesh/scheduler_srv.c +++ b/subsys/bluetooth/mesh/scheduler_srv.c @@ -399,6 +399,7 @@ static void run_scheduler(struct bt_mesh_scheduler_srv *srv) uint8_t planned_idx = get_least_time_index(srv); if (planned_idx == BT_MESH_SCHEDULER_ACTION_ENTRY_COUNT) { + k_work_cancel_delayable(&srv->delayed_work); return; } @@ -639,6 +640,23 @@ static int action_set(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx run_scheduler(srv); } + if ((srv->sch_reg[idx].action == BT_MESH_SCHEDULER_NO_ACTIONS) && + (srv->active_bitmap & BIT(idx))) { + WRITE_BIT(srv->active_bitmap, idx, 0); + + bool reschedule = srv->idx == idx; + + if (srv->active_bitmap == 0) { + srv->idx = BT_MESH_SCHEDULER_ACTION_ENTRY_COUNT; + srv->last_idx = BT_MESH_SCHEDULER_ACTION_ENTRY_COUNT; + } + + /* If the current action is set to NO_ACTIONS, schedule the next in line, if any */ + if (reschedule) { + run_scheduler(srv); + } + } + if (srv->action_set_cb) { srv->action_set_cb(srv, ctx, idx, &srv->sch_reg[idx]); } From fe3772dc0061534852893881aab190e6966cf830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Mon, 27 Jan 2025 09:17:37 +0100 Subject: [PATCH 2/2] tests: Bluetooth: Mesh: scheduler cancel test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a unit test for the scheduler model to verify that setting the entry for the scheduled action to "NO_ACTIONS" will cancel the action. Signed-off-by: Håvard Reierstad --- .../action_planning/src/main.c | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/subsys/bluetooth/mesh/scheduler_model/action_planning/src/main.c b/tests/subsys/bluetooth/mesh/scheduler_model/action_planning/src/main.c index 9b8237095f03..545192166e32 100644 --- a/tests/subsys/bluetooth/mesh/scheduler_model/action_planning/src/main.c +++ b/tests/subsys/bluetooth/mesh/scheduler_model/action_planning/src/main.c @@ -655,4 +655,56 @@ ZTEST(scheduler_action_planning, test_second_sched_turn_off_recurring) expected_tm_check(fired_tm, expected, 8); } +ZTEST(scheduler_action_planning, test_sched_cancel_imminent_action) +{ + /** Send a TURN_ON action to the sched srv in + * element 1 of the mocked composition data. + * Cancel the action before it is triggered by + * sending a new action with the same parameters + * but with the action set to NO_ACTIONS. + * + * Expect no events to be triggered. + */ + + const struct bt_mesh_schedule_entry test_action = { + .year = BT_MESH_SCHEDULER_ANY_YEAR, + .month = ANY_MONTH, + .day = BT_MESH_SCHEDULER_ANY_DAY, + .hour = 0, + .minute = BT_MESH_SCHEDULER_ANY_MINUTE, + .second = BT_MESH_SCHEDULER_EVERY_15_SECONDS, + .day_of_week = ANY_DAY_OF_WEEK, + .action = BT_MESH_SCHEDULER_TURN_ON, + .transition_time = model_transition_encode(2500), + .scene_number = 1 + }; + + struct sched_evt evt_list[] = { + { .elem_idx = 0, .evt = BT_MESH_SCHEDULER_TURN_ON, .transition_time = 2500 }, + { .elem_idx = 1, .evt = BT_MESH_SCHEDULER_TURN_ON, .transition_time = 2500 }, + { .elem_idx = 2, .evt = BT_MESH_SCHEDULER_TURN_ON, .transition_time = 2500 }, + }; + + sched_evt_ctx_init(evt_list, ARRAY_SIZE(evt_list)); + action_put(&test_action, sched_mod_elem1); + k_sleep(K_SECONDS(1)); + + const struct bt_mesh_schedule_entry test_action_inactive = { + .year = BT_MESH_SCHEDULER_ANY_YEAR, + .month = ANY_MONTH, + .day = BT_MESH_SCHEDULER_ANY_DAY, + .hour = 0, + .minute = BT_MESH_SCHEDULER_ANY_MINUTE, + .second = BT_MESH_SCHEDULER_EVERY_15_SECONDS, + .day_of_week = ANY_DAY_OF_WEEK, + .action = BT_MESH_SCHEDULER_NO_ACTIONS, + .transition_time = model_transition_encode(2500), + .scene_number = 1 + }; + + action_put(&test_action_inactive, sched_mod_elem1); + zassert_equal(k_sem_take(&action_fired, K_SECONDS(60)), -EAGAIN, + "Unexpected event was triggered"); +} + ZTEST_SUITE(scheduler_action_planning, NULL, NULL, tc_setup, tc_teardown, NULL);