net: lwm2m: Refactor RD client to be tickless

Call RD client service only when there is state transitioning.
Remove periodic 500 ms timer.

Signed-off-by: Seppo Takalo <seppo.takalo@nordicsemi.no>
This commit is contained in:
Seppo Takalo 2023-07-27 16:35:05 +03:00 committed by Carles Cufí
commit 518bbc1303
4 changed files with 75 additions and 47 deletions

View file

@ -64,18 +64,16 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include "lwm2m_util.h"
#define LWM2M_RD_CLIENT_URI "rd"
#define SECONDS_TO_UPDATE_EARLY CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY
#define STATE_MACHINE_UPDATE_INTERVAL_MS 500
#define CLIENT_EP_LEN CONFIG_LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH
#define CLIENT_BINDING_LEN sizeof("UQ")
#define CLIENT_QUEUE_LEN sizeof("Q")
static void sm_handle_registration_update_failure(void);
static int sm_send_registration_msg(void);
static bool sm_is_suspended(void);
static void lwm2m_rd_client_service(struct k_work *work);
static int64_t calc_next_event(void);
/* The states for the RD client state machine */
/*
@ -117,6 +115,7 @@ struct lwm2m_rd_client_info {
int64_t last_update;
int64_t last_tx;
int64_t next_event;
char ep_name[CLIENT_EP_LEN];
char server_ep[CLIENT_EP_LEN];
@ -167,6 +166,11 @@ void engine_update_tx_time(void)
client.last_tx = k_uptime_get();
}
static void next_event_at(int64_t timestamp)
{
(void)lwm2m_engine_call_at(lwm2m_rd_client_service, timestamp);
}
static void set_sm_state(uint8_t sm_state)
{
k_mutex_lock(&client.mutex, K_FOREVER);
@ -228,6 +232,7 @@ static void set_sm_state(uint8_t sm_state)
lwm2m_close_socket(client.ctx);
}
}
next_event_at(0);
k_mutex_unlock(&client.mutex);
}
@ -453,6 +458,7 @@ int engine_trigger_bootstrap(void)
client.use_bootstrap = true;
client.trigger_update = false;
client.engine_state = ENGINE_INIT;
next_event_at(0);
k_mutex_unlock(&client.mutex);
return 0;
#else
@ -1000,6 +1006,7 @@ static void sm_handle_registration_update_failure(void)
client.engine_state = ENGINE_SEND_REGISTRATION;
lwm2m_engine_context_close(client.ctx);
k_mutex_unlock(&client.mutex);
next_event_at(0);
}
static int sm_send_registration_msg(void)
@ -1079,28 +1086,49 @@ static int sm_do_registration(void)
return ret;
}
static int sm_registration_done(void)
static int64_t next_update(void)
{
k_mutex_lock(&client.mutex, K_FOREVER);
int ret = 0;
/*
* check for lifetime seconds - SECONDS_TO_UPDATE_EARLY
* so that we can update early and avoid lifetime timeout
*/
return client.last_update + (client.lifetime - SECONDS_TO_UPDATE_EARLY) * 1000;
}
static int64_t next_rx_off(void)
{
if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
return client.last_tx + CONFIG_LWM2M_QUEUE_MODE_UPTIME * 1000;
} else {
return next_update();
}
}
/** Return timestamp to next even whether it is RX_OFF or update event */
static int64_t calc_next_event(void)
{
return Z_MIN(next_update(), next_rx_off());
}
static void sm_registration_done(void)
{
k_mutex_lock(&client.mutex, K_FOREVER);
int64_t now = k_uptime_get();
if (sm_is_registered() &&
(client.trigger_update ||
((client.lifetime - SECONDS_TO_UPDATE_EARLY) <=
(k_uptime_get() - client.last_update) / 1000))) {
now >= next_update())) {
set_sm_state(ENGINE_UPDATE_REGISTRATION);
} else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) &&
(client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) &&
(((k_uptime_get() - client.last_tx) / 1000) >=
CONFIG_LWM2M_QUEUE_MODE_UPTIME)) {
(now >= next_rx_off())) {
set_sm_state(ENGINE_REGISTRATION_DONE_RX_OFF);
next_event_at(next_update());
} else {
next_event_at(calc_next_event());
}
k_mutex_unlock(&client.mutex);
return ret;
}
static int update_registration(void)
@ -1214,7 +1242,9 @@ static void sm_do_network_error(void)
{
int err;
if (--client.retry_delay > 0) {
if (client.retry_delay) {
client.retry_delay = 0;
next_event_at(k_uptime_get() + client.retry_delay * 1000);
return;
}
@ -1252,6 +1282,7 @@ static void lwm2m_rd_client_service(struct k_work *work)
k_mutex_lock(&client.mutex, K_FOREVER);
if (client.ctx) {
LOG_DBG("State: %d", get_sm_state());
switch (get_sm_state()) {
case ENGINE_IDLE:
if (client.ctx->sock_fd > -1) {
@ -1374,7 +1405,10 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name,
client.ep_name[CLIENT_EP_LEN - 1] = '\0';
LOG_INF("Start LWM2M Client: %s", client.ep_name);
next_event_at(0);
k_mutex_unlock(&client.mutex);
return 0;
}
@ -1402,12 +1436,14 @@ int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx,
k_mutex_unlock(&client.mutex);
return 0;
}
int lwm2m_rd_client_pause(void)
{
enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED;
LOG_DBG("lwm2m_rd_client_pause()");
k_mutex_lock(&client.mutex, K_FOREVER);
@ -1482,6 +1518,7 @@ int lwm2m_rd_client_resume(void)
}
}
next_event_at(0);
k_mutex_unlock(&client.mutex);
return 0;
@ -1490,6 +1527,7 @@ int lwm2m_rd_client_resume(void)
void lwm2m_rd_client_update(void)
{
engine_trigger_update(false);
next_event_at(0);
}
struct lwm2m_ctx *lwm2m_rd_client_ctx(void)
@ -1520,6 +1558,7 @@ int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx)
client.engine_state = ENGINE_DO_REGISTRATION;
}
}
next_event_at(0);
return 0;
}
@ -1536,6 +1575,7 @@ int lwm2m_rd_client_timeout(struct lwm2m_ctx *client_ctx)
k_mutex_lock(&client.mutex, K_FOREVER);
LOG_WRN("Confirmable Timeout -> Re-connect and register");
client.engine_state = ENGINE_DO_REGISTRATION;
next_event_at(0);
k_mutex_unlock(&client.mutex);
return 0;
}
@ -1565,9 +1605,7 @@ int lwm2m_rd_client_init(void)
client.engine_state = ENGINE_IDLE;
k_mutex_init(&client.mutex);
return lwm2m_engine_add_service(lwm2m_rd_client_service,
STATE_MACHINE_UPDATE_INTERVAL_MS);
return 0;
}
static int sys_lwm2m_rd_client_init(void)

View file

@ -167,7 +167,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -198,10 +197,8 @@ ZTEST(lwm2m_rd_client, test_timeout_resume_registration)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_default;
lwm2m_sprint_ip_addr_fake.custom_fake = lwm2m_sprint_ip_addr_fake_default;
@ -228,7 +225,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_timeout)
test_prepare_pending_message_cb(&message_reply_timeout_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -250,7 +246,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_fail)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -272,7 +267,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -300,7 +294,6 @@ ZTEST(lwm2m_rd_client, test_rx_off)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -329,7 +322,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -359,7 +351,6 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -376,12 +367,12 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout)
test_prepare_pending_message_cb(&message_reply_timeout_cb_default);
lwm2m_rd_client_update();
zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 2));
zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT, 3),
zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 1));
zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT, 2),
NULL);
test_prepare_pending_message_cb(&message_reply_cb_default);
zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 4),
zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 3),
NULL);
}
@ -393,7 +384,6 @@ ZTEST(lwm2m_rd_client, test_deregistration_timeout)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -421,7 +411,6 @@ ZTEST(lwm2m_rd_client, test_error_on_registration_update)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -448,7 +437,6 @@ ZTEST(lwm2m_rd_client, test_network_error_on_registration)
(void)memset(&ctx, 0x0, sizeof(ctx));
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -461,6 +449,8 @@ ZTEST(lwm2m_rd_client, test_network_error_on_registration)
coap_packet_append_option_fake.custom_fake = coap_packet_append_option_fake_err;
zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0,
NULL);
wait_for_service(100);
zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR, 0), NULL);
}
@ -472,7 +462,6 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);
@ -506,7 +495,6 @@ ZTEST(lwm2m_rd_client, test_socket_error)
test_prepare_pending_message_cb(&message_reply_cb_default);
lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default;
lwm2m_rd_client_init();
test_lwm2m_engine_start_service();
wait_for_service(1);

View file

@ -80,14 +80,14 @@ char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr)
DEFINE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t);
DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int);
DEFINE_FAKE_VALUE_FUNC(int, lwm2m_engine_add_service, k_work_handler_t, uint32_t);
k_work_handler_t lwm2m_engine_add_service_service;
uint32_t lwm2m_engine_add_service_period_ms = 20;
int lwm2m_engine_add_service_fake_default(k_work_handler_t service, uint32_t period_ms)
k_work_handler_t service;
int64_t next;
int lwm2m_engine_call_at(k_work_handler_t work, int64_t timestamp)
{
lwm2m_engine_add_service_service = service;
lwm2m_engine_add_service_period_ms = period_ms;
service = work;
next = timestamp ? timestamp : 1;
return 0;
}
@ -97,18 +97,23 @@ void *(*pending_message_cb)();
static void service_work_fn(struct k_work *work)
{
while (lwm2m_engine_add_service_service != NULL) {
while (true) {
if (pending_message != NULL && pending_message_cb != NULL) {
pending_message_cb(pending_message);
pending_message = NULL;
}
lwm2m_engine_add_service_service(work);
k_sleep(K_MSEC(lwm2m_engine_add_service_period_ms));
if (next && next < k_uptime_get()) {
printk("Event!\n");
next = 0;
service(NULL);
}
k_sleep(K_MSEC(10));
counter--;
/* avoid endless loop if rd client is stuck somewhere */
if (counter == 0) {
printk("Counter!\n");
break;
}
}
@ -119,7 +124,7 @@ void wait_for_service(uint16_t cycles)
uint16_t end = counter - cycles;
while (counter > end) {
k_sleep(K_MSEC(1));
k_sleep(K_MSEC(10));
}
}

View file

@ -61,8 +61,6 @@ DECLARE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *);
char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr);
DECLARE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t);
DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int);
DECLARE_FAKE_VALUE_FUNC(int, lwm2m_engine_add_service, k_work_handler_t, uint32_t);
int lwm2m_engine_add_service_fake_default(k_work_handler_t service, uint32_t period_ms);
void wait_for_service(uint16_t cycles);
void test_lwm2m_engine_start_service(void);
void test_lwm2m_engine_stop_service(void);
@ -107,7 +105,6 @@ DECLARE_FAKE_VALUE_FUNC(int, do_register_op_link_format, struct lwm2m_message *)
FUNC(lwm2m_sprint_ip_addr) \
FUNC(lwm2m_server_short_id_to_inst) \
FUNC(lwm2m_security_index_to_inst_id) \
FUNC(lwm2m_engine_add_service) \
FUNC(lwm2m_init_message) \
FUNC(lwm2m_reset_message) \
FUNC(lwm2m_send_message_async) \