diff --git a/nrf_rpc/Kconfig b/nrf_rpc/Kconfig index ccd91e73f7..780d080368 100644 --- a/nrf_rpc/Kconfig +++ b/nrf_rpc/Kconfig @@ -46,6 +46,21 @@ config NRF_RPC_GROUP_INIT_WAIT_TIME The number of milliseconds to wait for the remote cores to send group init packets with destination group IDs. Set to -1 to wait forever. +config NRF_RPC_GROUP_DEFAULT_INITIATOR + bool "Initiate group binding by default" + default y + help + For each group defined with NRF_RPC_GROUP_DEFINE macro, initiate the + group binding when calling nrf_rpc_init(). This is achieved by sending + an initialization packet to the peer. + +config NRF_RPC_GROUP_DEFAULT_WAIT_ON_INIT + bool "Wait for group binding by default" + default y + help + For each group defined with NRF_RPC_GROUP_DEFINE macro, wait until the + group is bound when calling nrf_rpc_init(). + config NRF_RPC_THREAD_POOL_SIZE int "Number of threads in local thread pool" default 3 diff --git a/nrf_rpc/include/nrf_rpc.h b/nrf_rpc/include/nrf_rpc.h index e52a2d484b..0362823f35 100644 --- a/nrf_rpc/include/nrf_rpc.h +++ b/nrf_rpc/include/nrf_rpc.h @@ -252,11 +252,11 @@ struct nrf_rpc_cleanup_handler * error occurred in context of this group. Can be NULL if * group does not want to receive error notifications. */ -#define NRF_RPC_GROUP_DEFINE(_name, _strid, _transport, _ack_handler, _ack_data, \ - _err_handler) \ - NRF_RPC_GROUP_DEFINE_INTERNAL__(_name, _strid, _transport, _ack_handler, \ - _ack_data, _err_handler, NULL, true, \ - true) \ +#define NRF_RPC_GROUP_DEFINE(_name, _strid, _transport, _ack_handler, _ack_data, _err_handler) \ + NRF_RPC_GROUP_DEFINE_INTERNAL__(_name, _strid, _transport, _ack_handler, _ack_data, \ + _err_handler, NULL, \ + IS_ENABLED(CONFIG_NRF_RPC_GROUP_DEFAULT_WAIT_ON_INIT), \ + IS_ENABLED(CONFIG_NRF_RPC_GROUP_DEFAULT_INITIATOR)) /** @brief Define a non-blocking group of commands and events. * @@ -363,6 +363,8 @@ struct nrf_rpc_cleanup_handler void nrf_rpc_set_bound_handler(nrf_rpc_group_bound_handler_t bound_handler); /** @brief Initialize the nRF RPC + * + * Calling this function is equivalent to calling both @ref nrf_rpc_setup and @ref nrf_rpc_bind. * * @param err_handler Error handler that will be called to report error in * nRF RPC. @@ -371,6 +373,52 @@ void nrf_rpc_set_bound_handler(nrf_rpc_group_bound_handler_t bound_handler); */ int nrf_rpc_init(nrf_rpc_err_handler_t err_handler); +/** @brief Initialize the nRF RPC internal state. + * + * Sets up all variables related to nRF RPC, including contexts, groups, and transports. + * It does not initiate any communication with the peer. + * + * @note This function can be invoked multiple times; however, only the first call has an effect. + * @note This function is not thread-safe and should not be called concurrently from multiple + * threads. + * + * @warning This function is experimental and subject to change or removal without prior notice. + * + * @param err_handler Error handler that will be called to report an error in the nRF RPC. + * @param bound_handler Bound handler that will be called when a group is bound with the peer. + * + * @return 0 on success or negative error code. + */ +int nrf_rpc_setup(nrf_rpc_err_handler_t err_handler, nrf_rpc_group_bound_handler_t bound_handler); + +/** @brief Binds the nRF RPC groups. + * + * Sends an initializaton packet to the peer for each group defined with the @ref + * NRF_RPC_FLAGS_INITIATOR flag. It then waits until all groups defined with the @ref + * NRF_RPC_FLAGS_WAIT_ON_INIT flag have been bound. + * + * A group is considered bound when an initialization packet for that group is received from the + * peer, indicating the numerical identifier assigned to the group by the peer. + * + * The function may time out if some groups are not bound within the duration specified by the + * CONFIG_NRF_RPC_GROUP_INIT_WAIT_TIME Kconfig option. + * + * @note This function is not thread-safe; should not be called concurrently from multiple threads. + * + * @warning This function is experimental and subject to change or removal without prior notice. + * + * @return 0 on success or negative error code. + */ +int nrf_rpc_bind(void); + +/** @brief Unbinds the nRF RPC groups. + * + * Resets the effect of @ref nrf_rpc_bind so that no groups are considered bound after returning + * from this function. + * + * @warning This function is experimental and subject to change or removal without prior notice. + */ +void nrf_rpc_unbind(void); /** @brief Registers the cleanup handler. * diff --git a/nrf_rpc/nrf_rpc.c b/nrf_rpc/nrf_rpc.c index a5ca66cf3b..7189eaa740 100644 --- a/nrf_rpc/nrf_rpc.c +++ b/nrf_rpc/nrf_rpc.c @@ -419,48 +419,6 @@ static void internal_tx_handler(void) } } -static int transport_init(nrf_rpc_tr_receive_handler_t receive_cb) -{ - int err = 0; - void *iter; - const struct nrf_rpc_group *group; - - for (NRF_RPC_AUTO_ARR_FOR(iter, group, &nrf_rpc_groups_array, - const struct nrf_rpc_group)) { - const struct nrf_rpc_tr *transport = group->transport; - struct nrf_rpc_group_data *data = group->data; - - err = transport->api->init(transport, receive_cb, NULL); - if (err) { - NRF_RPC_ERR("Failed to initialize transport, err: %d", err); - continue; - } - - group->data->transport_initialized = true; - - if (group->flags & NRF_RPC_FLAGS_INITIATOR) { - err = group_init_send(group); - if (err) { - NRF_RPC_ERR("Failed to send group init packet for group id: %d strid: %s err: %d", - data->src_group_id, group->strid, err); - continue; - } - } - } - - /* Group initialization errors are not propagated to the caller. */ - err = 0; - - if (waiting_group_count > 0) { - err = nrf_rpc_os_event_wait(&groups_init_event, CONFIG_NRF_RPC_GROUP_INIT_WAIT_TIME); - if (err) { - NRF_RPC_ERR("Not all groups are ready to use."); - } - } - - return err; -} - /* ======================== Receiving Packets ======================== */ /* Find in array and execute command or event handler */ @@ -1143,10 +1101,9 @@ void nrf_rpc_set_bound_handler(nrf_rpc_group_bound_handler_t bound_handler) global_bound_handler = bound_handler; } -int nrf_rpc_init(nrf_rpc_err_handler_t err_handler) +int nrf_rpc_setup(nrf_rpc_err_handler_t err_handler, nrf_rpc_group_bound_handler_t bound_handler) { int err; - int i; void *iter; const struct nrf_rpc_group *group; uint8_t group_id = 0; @@ -1161,6 +1118,7 @@ int nrf_rpc_init(nrf_rpc_err_handler_t err_handler) nrf_rpc_os_mutex_init(&cleanup_mutex); global_err_handler = err_handler; + global_bound_handler = bound_handler; for (NRF_RPC_AUTO_ARR_FOR(iter, group, &nrf_rpc_groups_array, const struct nrf_rpc_group)) { @@ -1194,8 +1152,6 @@ int nrf_rpc_init(nrf_rpc_err_handler_t err_handler) group_count = group_id; waiting_group_count = wait_count; - memset(&cmd_ctx_pool, 0, sizeof(cmd_ctx_pool)); - err = nrf_rpc_os_init(execute_packet); if (err < 0) { return err; @@ -1211,7 +1167,7 @@ int nrf_rpc_init(nrf_rpc_err_handler_t err_handler) return err; } - for (i = 0; i < CONFIG_NRF_RPC_CMD_CTX_POOL_SIZE; i++) { + for (int i = 0; i < CONFIG_NRF_RPC_CMD_CTX_POOL_SIZE; i++) { cmd_ctx_pool[i].id = i; err = nrf_rpc_os_mutex_init(&cmd_ctx_pool[i].mutex); if (err < 0) { @@ -1223,17 +1179,85 @@ int nrf_rpc_init(nrf_rpc_err_handler_t err_handler) } } - err = transport_init(receive_handler); - if (err < 0) { - return err; - } - is_initialized = true; NRF_RPC_DBG("Done initializing nRF RPC module"); return err; } +int nrf_rpc_bind(void) +{ + int err; + void *iter; + const struct nrf_rpc_group *group; + + for (NRF_RPC_AUTO_ARR_FOR(iter, group, &nrf_rpc_groups_array, const struct nrf_rpc_group)) { + const struct nrf_rpc_tr *transport = group->transport; + struct nrf_rpc_group_data *data = group->data; + + if (!group->data->transport_initialized) { + err = transport->api->init(transport, receive_handler, NULL); + if (err) { + NRF_RPC_ERR("Failed to initialize transport, err: %d", err); + continue; + } + + group->data->transport_initialized = true; + } + + if (group->flags & NRF_RPC_FLAGS_INITIATOR) { + err = group_init_send(group); + if (err) { + NRF_RPC_ERR("Failed to send group init packet for group id: %d " + "strid: %s err: %d", + data->src_group_id, group->strid, err); + continue; + } + } + } + + /* Group initialization errors are not propagated to the caller. */ + err = 0; + + if (waiting_group_count > 0) { + err = nrf_rpc_os_event_wait(&groups_init_event, + CONFIG_NRF_RPC_GROUP_INIT_WAIT_TIME); + if (err) { + NRF_RPC_ERR("Not all groups are ready to use."); + } + } + + return err; +} + +void nrf_rpc_unbind(void) +{ + void *iter; + const struct nrf_rpc_group *group; + + initialized_group_count = 0; + + for (NRF_RPC_AUTO_ARR_FOR(iter, group, &nrf_rpc_groups_array, const struct nrf_rpc_group)) { + group->data->dst_group_id = NRF_RPC_ID_UNKNOWN; + } +} + +int nrf_rpc_init(nrf_rpc_err_handler_t err_handler) +{ + int err; + + if (is_initialized) { + return 0; + } + + err = nrf_rpc_setup(err_handler, global_bound_handler); + if (err < 0) { + return err; + } + + return nrf_rpc_bind(); +} + void nrf_rpc_register_cleanup_handler(struct nrf_rpc_cleanup_handler *handler) { nrf_rpc_os_mutex_lock(&cleanup_mutex);