ipc: Added IPC Service to support different transport backends

IPC Service allow plugging in different transport backends.
Specifies a generic API that is implemented by the backend.

Signed-off-by: Marcin Jeliński <marcin.jelinski@nordicsemi.no>
This commit is contained in:
Marcin Jeliński 2021-06-09 15:22:38 +02:00 committed by Christopher Friedt
parent 14272c2726
commit 3fcd8d1003
7 changed files with 275 additions and 0 deletions

107
include/ipc/ipc_service.h Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_IPC_SERVICE_IPC_SERVICE_H_
#define ZEPHYR_INCLUDE_IPC_SERVICE_IPC_SERVICE_H_
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief IPC Service API
* @defgroup ipc_service_api IPC service APIs
* @{
*/
/** @brief Event callback structure.
*
* It is registered during endpoint registration.
* This structure is part of the endpoint configuration.
*/
struct ipc_service_cb {
/** @brief Bind was successful.
*
* @param priv Private user data.
*/
void (*bound)(void *priv);
/** @brief New packet arrived.
*
* @param data Pointer to data buffer.
* @param len Length of @a data.
* @param priv Private user data.
*/
void (*received)(const void *data, size_t len, void *priv);
/** @brief An error occurred.
*
* @param message Error message.
* @param priv Private user data.
*/
void (*error)(const char *message, void *priv);
};
/** @brief Endpoint instance.
*
* Content is not important for user of the API.
* It is implemented in a specific backend.
*/
struct ipc_ept;
/** @brief Endpoint configuration structure. */
struct ipc_ept_cfg {
/** Name of the endpoint. */
const char *name;
/** Endpoint priority. If the backend supports priorities. */
int prio;
/** Event callback structure. */
struct ipc_service_cb cb;
/** Private user data. */
void *priv;
};
/** @brief Register IPC endpoint.
*
* Registers IPC endpoint to enable communication with a remote device.
*
* The same function registers endpoints for both master and slave devices.
*
* @param ept Endpoint object.
* @param cfg Endpoint configuration.
*
* @retval -EIO when no backend is registered.
* @retval -EINVAL when pointer to an endpoint or endpoint configuration is invalid.
* @retval Other errno codes depending on the implementation of the backend.
*/
int ipc_service_register_endpoint(struct ipc_ept **ept, const struct ipc_ept_cfg *cfg);
/** @brief Send data using given IPC endpoint.
*
* @param ept Registered endpoint by @ref ipc_service_register_endpoint.
* @param data Pointer to the buffer to send.
* @param len Number of bytes to send.
*
* @retval -EIO when no backend is registered.
* @retval Other errno codes depending on the implementation of the backend.
*/
int ipc_service_send(struct ipc_ept *ept, const void *data, size_t len);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_IPC_SERVICE_IPC_SERVICE_H_ */

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_IPC_SERVICE_IPC_SERVICE_BACKEND_H_
#define ZEPHYR_INCLUDE_IPC_SERVICE_IPC_SERVICE_BACKEND_H_
#include <ipc/ipc_service.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief IPC Service backend
* @ingroup ipc_service_api
* @{
*/
/** @brief IPC backend configuration structure.
*
* This structure is used for configuration backend during registration.
*/
struct ipc_service_backend {
/** @brief Name of the IPC backend. */
const char *name;
/** @brief Pointer to the function that will be used to send data to the endpoint.
*
* @param ept Registered endpoint.
* @param data Pointer to the buffer to send.
* @param len Number of bytes to send.
*
* @retval Status code.
*/
int (*send)(struct ipc_ept *ept, const void *data, size_t len);
/** @brief Pointer to the function that will be used to register endpoints.
*
* @param ept Endpoint object.
* @param cfg Endpoint configuration.
*
* @retval Status code.
*/
int (*register_endpoint)(struct ipc_ept **ept, const struct ipc_ept_cfg *cfg);
};
/** @brief IPC backend registration.
*
* Registration must be done before using IPC Service.
*
* @param backend Configuration of the backend.
*
* @retval -EALREADY The backend is already registered.
* @retval -EINVAL The backend configuration is incorrect.
* @retval Zero on success.
*
*/
int ipc_service_register_backend(const struct ipc_service_backend *backend);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_IPC_SERVICE_IPC_SERVICE_BACKEND_H_ */

View file

@ -2,3 +2,4 @@
add_subdirectory_ifdef(CONFIG_RPMSG_SERVICE rpmsg_service)
add_subdirectory_ifdef(CONFIG_RPMSG_MULTI_INSTANCE rpmsg_multi_instance)
add_subdirectory_ifdef(CONFIG_IPC_SERVICE ipc_service)

View file

@ -7,5 +7,6 @@ menu "Inter Processor Communication"
source "subsys/ipc/rpmsg_service/Kconfig"
source "subsys/ipc/rpmsg_multi_instance/Kconfig"
source "subsys/ipc/ipc_service/Kconfig"
endmenu

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_sources(ipc_service.c)

View file

@ -0,0 +1,32 @@
# Copyright (c) -2021 Nordic Semiconductor (ASA)
# SPDX-License-Identifier: Apache-2.0
menuconfig IPC_SERVICE
bool "IPC service support multiple backends"
help
Enables support for a service that can be shared by multiple
users. Ability to work in different backends. The backend
should be registered before application starts using
the IPC Service.
if IPC_SERVICE
choice IPC_SERVICE_BACKEND
prompt "IPC Service backend"
config IPC_SERVICE_BACKEND_XYZ
bool "Example backend"
endchoice
config IPC_SERVICE_BACKEND_REG_PRIORITY
int "Initialization priority of modules registering IPC backend"
default 46
help
The backend must be registered before the endpoint register.
module = IPC_SERVICE
module-str = IPC service and backend
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
endif # IPC_SERVICE

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ipc/ipc_service.h>
#include <ipc/ipc_service_backend.h>
#include <logging/log.h>
#include <zephyr.h>
#include <device.h>
#define LOG_MODULE_NAME ipc_service
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_IPC_SERVICE_LOG_LEVEL);
const static struct ipc_service_backend *backend;
int ipc_service_register_backend(const struct ipc_service_backend *bkd)
{
if (backend) {
return -EALREADY;
}
if (!bkd || !bkd->register_endpoint || !bkd->send) {
return -EINVAL;
}
backend = bkd;
LOG_DBG("Registered: %s", backend->name ? backend->name : "");
return 0;
}
int ipc_service_register_endpoint(struct ipc_ept **ept, const struct ipc_ept_cfg *cfg)
{
LOG_DBG("Register endpoint %s", cfg->name ? cfg->name : "");
if (!backend || !backend->register_endpoint) {
LOG_ERR("Backend not registered");
return -EIO;
}
if (!ept || !cfg) {
LOG_ERR("Invalid endpoint or configuration");
return -EINVAL;
}
return backend->register_endpoint(ept, cfg);
}
int ipc_service_send(struct ipc_ept *ept, const void *data, size_t len)
{
if (!backend || !backend->send) {
LOG_ERR("Backend not registered");
return -EIO;
}
return backend->send(ept, data, len);
}