1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_IPC_ICMSG_ME_H_
8 #define ZEPHYR_INCLUDE_IPC_ICMSG_ME_H_
9 
10 #include <stdint.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/ipc/icmsg.h>
13 #include <zephyr/ipc/ipc_service.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /**
20  * @brief Multi-endpoint extension of icmsg IPC library
21  * @defgroup ipc_icmsg_me_api Icmsg multi-endpoint IPC library API
22  * @ingroup ipc
23  * @{
24  */
25 
26 
27 /* If more bytes than 1 was used for endpoint id, endianness should be
28  * considered.
29  */
30 typedef uint8_t icmsg_me_ept_id_t;
31 
32 struct icmsg_me_data_t {
33 	struct icmsg_data_t icmsg_data;
34 	struct ipc_ept_cfg ept_cfg;
35 
36 	struct k_event event;
37 
38 	struct k_mutex send_mutex;
39 	const struct ipc_ept_cfg *epts[CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NUM_EP];
40 
41 	uint8_t send_buffer[CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_SEND_BUF_SIZE] __aligned(4);
42 };
43 
44 
45 /** @brief Initialize an icmsg_me instance
46  *
47  *  This function is intended to be called during system initialization.
48  *  It initializes the underlying icmsg instance as one of the initialization
49  *  steps.
50  *
51  *  @param[in] conf Structure containing configuration parameters for the
52  *                  underlying icmsg instance being created.
53  *  @param[inout] data Structure containing run-time data used by the icmsg_me
54  *                     instance. The structure shall be filled with zeros
55  *                     when calling this function. The content of this
56  *                     structure must be preserved while the icmsg_me instance
57  *                     is active.
58  *
59  *  @retval 0 on success.
60  *  @retval other errno codes from dependent modules.
61  */
62 int icmsg_me_init(const struct icmsg_config_t *conf,
63 		  struct icmsg_me_data_t *data);
64 
65 /** @brief Open an icmsg_me instance
66  *
67  *  Open an icmsg_me instance to be able to send and receive messages to a
68  *  remote instance.
69  *  This function is blocking until the handshake with the remote instance is
70  *  completed.
71  *  This function is intended to be called late in the initialization process,
72  *  possibly from a thread which can be safely blocked while handshake with the
73  *  remote instance is being pefromed.
74  *
75  *  @param[in] conf Structure containing configuration parameters for the
76  *                  underlying icmsg instance.
77  *  @param[inout] data Structure containing run-time data used by the icmsg_me
78  *                     instance. The structure is initialized with
79  *                     @ref icmsg_me_init and its content must be preserved
80  *                     while the icmsg_me instance is active.
81  *  @param[in] cb Structure containing callback functions to be called on
82  *                events generated by this icmsg_me instance. The pointed memory
83  *                must be preserved while the icmsg_me instance is active.
84  *  @param[in] ctx Pointer to context passed as an argument to callbacks.
85  *
86  *
87  *  @retval 0 on success.
88  *  @retval other errno codes from dependent modules.
89  */
90 int icmsg_me_open(const struct icmsg_config_t *conf,
91 		  struct icmsg_me_data_t *data,
92 		  const struct ipc_service_cb *cb,
93 		  void *ctx);
94 
95 /** @brief Wait until the underlying icmsg instance calls bound callback
96  *
97  *  This function blocks calling thread until the underlying icmsg connection
98  *  is bound. If the connection was bound before this function is called, the
99  *  function ends immediately without any delay.
100  *
101  *  This function is intended to be used in the endpoints handshake procedure
102  *  to make sure that handshake is not performed until the icmsg channel is
103  *  ready to pass handshake messages.
104  *
105  *  @param[inout] data Structure containing run-time data used by the icmsg_me
106  *                     instance. The structure is initialized with
107  *                     @ref icmsg_me_init and its content must be preserved
108  *                     while the icmsg_me instance is active.
109  */
110 void icmsg_me_wait_for_icmsg_bind(struct icmsg_me_data_t *data);
111 
112 /** @brief Notify the icmsg_me instance that the underlying icmsg was bound
113  *
114  *  The icmsg_me API users are responsible to implement the callback functions
115  *  called by the underlying icmsg instance. One of the actions of the bound
116  *  callback must be calling this function.
117  *
118  *  @param[inout] data Structure containing run-time data used by the icmsg_me
119  *                     instance. The structure is initialized with
120  *                     @ref icmsg_me_init and its content must be preserved
121  *                     while the icmsg_me instance is active.
122  */
123 void icmsg_me_icmsg_bound(struct icmsg_me_data_t *data);
124 
125 /** @brief Notify the icmsg_me instance that data for an endpoint was received
126  *
127  *  The icmsg_me API users are responsible to implement the callback functions
128  *  called by the underlying icmsg instance. If the data received by the icmsg
129  *  instance contains data frame destined to one of the endpoints, this
130  *  function must be called.
131  *
132  *  @param[inout] data Structure containing run-time data used by the icmsg_me
133  *                     instance. The structure is initialized with
134  *                     @ref icmsg_me_init and its content must be preserved
135  *                     while the icmsg_me instance is active.
136  *  @param[in] id The value identifyig the endpoint.
137  *  @param[in] msg Data frame received from the peer, stripped of the
138  *                 multi-endpoint header.
139  *  @param[in] len Size of the data pointed by @p msg.
140  */
141 void icmsg_me_received_data(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
142 			    const void *msg, size_t len);
143 
144 /** @brief Set endpoint configuration in an empty endpoint slot
145  *
146  *  During endpoint handshake the handshake initiator must select an id number
147  *  and store endpoint metadata required to finalize handshake and maintain
148  *  the connection. This function is a helper which stores the configuration
149  *  in an empty configuration slot and provides the unique id value associated
150  *  with the selected slot.
151  *
152  *  @note This function is not reentrant for a single icmsg_me instance.
153  *        It must be protected by the caller using mutex, critical section,
154  *        spinlock, or similar solution.
155  *        This function is reentrant for different icmsg_me instances. The
156  *        protection scope might be limited to a single instance.
157  *
158  *  @param[inout] data Structure containing run-time data used by the icmsg_me
159  *                     instance. The structure is initialized with
160  *                     @ref icmsg_me_init and its content must be preserved
161  *                     while the icmsg_me instance is active.
162  *  @param[in] ept_cfg Configuration data of the endpoint for which the
163  *                     handshake procedure is being initiated.
164  *  @param[out] id The value uniquely identifyig this endpoint.
165  *
166  *  @retval 0 on success.
167  *  @retval -ENOMEM when there are no more empty endpoint configuration slots.
168  */
169 int icmsg_me_set_empty_ept_cfg_slot(struct icmsg_me_data_t *data,
170 				    const struct ipc_ept_cfg *ept_cfg,
171 				    icmsg_me_ept_id_t *id);
172 
173 /** @brief Set endpoint configuration in a selected endpoint slot
174  *
175  *  During endpoint handshake the handshake follower must store endpoint id and
176  *  metadata required to finalize handshake and maintain the connection. This
177  *  function is a helper which stores the configuration in a configuration slot
178  *  associated with the id of the endpoint.
179  *
180  *  @param[inout] data Structure containing run-time data used by the icmsg_me
181  *                     instance. The structure is initialized with
182  *                     @ref icmsg_me_init and its content must be preserved
183  *                     while the icmsg_me instance is active.
184  *  @param[in] id The value uniquely identifyig this endpoint.
185  *  @param[in] ept_cfg Configuration data of the endpoint for which the
186  *                     handshake procedure is ongoing.
187  *
188  *  @retval 0 on success.
189  *  @retval -ENOENT when @p id is out of range of available slots.
190  */
191 int icmsg_me_set_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
192 			 const struct ipc_ept_cfg *ept_cfg);
193 
194 /** @brief Get endpoint configuration from a selected endpoint slot
195  *
196  *  When the icmsg_me instance receives data from a remote endpoint, it must
197  *  get the endpoint configuration based on the id of the endpoint. This
198  *  function is designed for this purpose.
199  *
200  *  If retrieved endpoint configuration is not set, @p ept_cfg points to NULL.
201  *
202  *  @param[inout] data Structure containing run-time data used by the icmsg_me
203  *                     instance. The structure is initialized with
204  *                     @ref icmsg_me_init and its content must be preserved
205  *                     while the icmsg_me instance is active.
206  *  @param[in] id The value uniquely identifyig endpoint.
207  *  @param[in] ept_cfg Configuration data of the endpoint with given id.
208  *
209  *  @retval 0 on success.
210  *  @retval -ENOENT when @p id is out of range of available slots.
211  */
212 int icmsg_me_get_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
213 			 const struct ipc_ept_cfg **ept_cfg);
214 
215 /** @brief Reset endpoint configuration in a selected endpoint slot.
216  *
217  *  If handshake fails or an endpoint is disconnected, then configuration
218  *  slot for given endpoint should be vacated. This function is intended to
219  *  be used for this purpose.
220  *
221  *  @param[inout] data Structure containing run-time data used by the icmsg_me
222  *                     instance. The structure is initialized with
223  *                     @ref icmsg_me_init and its content must be preserved
224  *                     while the icmsg_me instance is active.
225  *  @param[in] id The value uniquely identifyig endpoint.
226  */
227 void icmsg_me_reset_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id);
228 
229 /** @brief Send a message to the remote icmsg_me endpoint.
230  *
231  *  @param[in] conf Structure containing configuration parameters for the
232  *                  underlying icmsg instance.
233  *  @param[inout] data Structure containing run-time data used by the icmsg_me
234  *                     instance. The structure is initialized with
235  *                     @ref icmsg_me_init and its content must be preserved
236  *                     while the icmsg_me instance is active.
237  *  @param[in] id Id of the endpoint to use.
238  *  @param[in] msg Pointer to a buffer containing data to send.
239  *  @param[in] len Size of data in the @p msg buffer.
240  *
241  *
242  *  @retval 0 on success.
243  *  @retval -EBADMSG when the requested data to send is too big.
244  *  @retval other errno codes from dependent modules.
245  */
246 int icmsg_me_send(const struct icmsg_config_t *conf,
247 		  struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
248 		  const void *msg, size_t len);
249 
250 /**
251  * @}
252  */
253 
254 #ifdef __cplusplus
255 }
256 #endif
257 
258 #endif /* ZEPHYR_INCLUDE_IPC_ICMSG_ME_H_ */
259