From 4f3ed25e54b03db0801eb008f4dcfb2b0713a5e4 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Thu, 31 Oct 2024 10:10:37 +0100 Subject: [PATCH] nrf_rpc: call bound_handler after init reply 1. Ensure that the group's bound_handler is called after sending the init reply. This is to make sure that the remote knows our group ID and is able to process incoming commands when the handler is called. 2. Similarly, signal groups_init_event after sending the init reply. Signed-off-by: Damian Krolik --- nrf_rpc/nrf_rpc.c | 56 +++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/nrf_rpc/nrf_rpc.c b/nrf_rpc/nrf_rpc.c index f0d1a380d2..23db8d8c8d 100644 --- a/nrf_rpc/nrf_rpc.c +++ b/nrf_rpc/nrf_rpc.c @@ -96,6 +96,8 @@ struct internal_task { union { struct { const struct nrf_rpc_group *group; + bool send_reply; + bool signal_groups_init_event; } group_init; struct { @@ -377,10 +379,19 @@ static void internal_tx_handler(void) case NRF_RPC_TASK_GROUP_INIT: { const struct nrf_rpc_group *group = task.group_init.group; - if (group_init_send(group)) { + if (task.group_init.send_reply && group_init_send(group)) { NRF_RPC_ERR("Failed to send group init packet for group id: %d strid: %s", group->data->src_group_id, group->strid); } + + if (group->bound_handler != NULL) { + group->bound_handler(group); + } + + if (task.group_init.signal_groups_init_event) { + nrf_rpc_os_event_set(&groups_init_event); + } + break; } case NRF_RPC_TASK_RECV_ERROR: @@ -633,7 +644,8 @@ static int init_packet_handle(struct header *hdr, const struct nrf_rpc_group **g struct init_packet_data init_data = {0}; struct nrf_rpc_group_data *group_data; bool first_init; - bool wait_on_init; + bool signal_groups_init_event = false; + bool send_reply; *group = NULL; @@ -663,32 +675,38 @@ static int init_packet_handle(struct header *hdr, const struct nrf_rpc_group **g group_data = (*group)->data; first_init = group_data->dst_group_id == NRF_RPC_ID_UNKNOWN; group_data->dst_group_id = hdr->src_group_id; - wait_on_init = (*group)->flags & NRF_RPC_FLAGS_WAIT_ON_INIT; - nrf_rpc_group_bound_handler_t bound_handler = (*group)->bound_handler; NRF_RPC_DBG("Found corresponding local group. Remote id: %d, Local id: %d", - hdr->src_group_id, group_data->src_group_id); - - if (bound_handler != NULL) { - bound_handler(*group); - } + group_data->dst_group_id, group_data->src_group_id); - if (first_init && wait_on_init) { + if (first_init && (*group)->flags & NRF_RPC_FLAGS_WAIT_ON_INIT) { ++initialized_group_count; - if (initialized_group_count == waiting_group_count) { - /* All groups are initialized. */ - nrf_rpc_os_event_set(&groups_init_event); - } - } - - if (hdr->dst_group_id == NRF_RPC_ID_UNKNOWN && (*group)->data->transport_initialized) { /* - * If remote processor does not know our group id, send an init packet back, - * since it might have missed our original init packet. + * If this is the last group that nrf_rpc_init() is waiting for, use the async task + * to signal the corresponding event and unblock the waiting thread. */ + signal_groups_init_event = (initialized_group_count == waiting_group_count); + } + + /* + * If the remote processor does not know our group id, send an init packet back as + * either we are not an initiator, which is indicated by NRF_RPC_FLAGS_INITIATOR + * flag, or the remote has missed our init packet. + */ + send_reply = (hdr->dst_group_id == NRF_RPC_ID_UNKNOWN) && group_data->transport_initialized; + + /* + * Spawn the async task only if necessary. The async task is used to avoid sending the init + * reply in the transport receive thread. The application is also notified about the group + * initialization from within the task to ensure that when this happens the init reply has + * already been sent and the remote is ready to receive nRF RPC commands. + */ + if (((*group)->bound_handler != NULL) || send_reply || signal_groups_init_event) { internal_task.type = NRF_RPC_TASK_GROUP_INIT; internal_task.group_init.group = *group; + internal_task.group_init.send_reply = send_reply; + internal_task.group_init.signal_groups_init_event = signal_groups_init_event; nrf_rpc_os_thread_pool_send((const uint8_t *)&internal_task, sizeof(internal_task)); nrf_rpc_os_event_wait(&internal_task_consumed, NRF_RPC_OS_WAIT_FOREVER); }