1.. _ipc_service:
2
3IPC service
4###########
5
6.. contents::
7    :local:
8    :depth: 2
9
10The IPC service API provides an interface to exchange data between two domains
11or CPUs.
12
13Overview
14========
15
16An IPC service communication channel consists of one instance and one or
17several endpoints associated with the instance.
18
19An instance is the external representation of a physical communication channel
20between two domains or CPUs. The actual implementation and internal
21representation of the instance is peculiar to each backend.
22
23An individual instance is not used to send data between domains/CPUs. To send
24and receive the data, the user must create (register) an endpoint in the
25instance. This allows for the connection of the two domains of interest.
26
27It is possible to have zero or multiple endpoints for one single instance,
28possibly with different priorities, and to use each to exchange data.
29Endpoint prioritization and multi-instance ability highly depend on the backend
30used.
31
32The endpoint is an entity the user must use to send and receive data between
33two domains (connected by the instance). An endpoint is always associated to an
34instance.
35
36The creation of the instances is left to the backend, usually at init time.
37The registration of the endpoints is left to the user, usually at run time.
38
39The API does not mandate a way for the backend to create instances but it is
40strongly recommended to use the devicetree to retrieve the configuration
41parameters for an instance. Currently, each backend defines its own
42DT-compatible configuration that is used to configure the interface at boot
43time.
44
45The following usage scenarios are supported:
46
47* Simple data exchange.
48* Data exchange using the no-copy API.
49
50Simple data exchange
51====================
52
53To send data between domains or CPUs, an endpoint must be registered onto
54an instance.
55
56See the following example:
57
58.. note::
59
60   Before registering an endpoint, the instance must be opened using the
61   :c:func:`ipc_service_open_instance` function.
62
63
64.. code-block:: c
65
66   #include <zephyr/ipc/ipc_service.h>
67
68   static void bound_cb(void *priv)
69   {
70      /* Endpoint bounded */
71   }
72
73   static void recv_cb(const void *data, size_t len, void *priv)
74   {
75      /* Data received */
76   }
77
78   static struct ipc_ept_cfg ept0_cfg = {
79      .name = "ept0",
80      .cb = {
81         .bound    = bound_cb,
82         .received = recv_cb,
83      },
84   };
85
86   int main(void)
87   {
88      const struct device *inst0;
89      struct ipc_ept ept0;
90      int ret;
91
92      inst0 = DEVICE_DT_GET(DT_NODELABEL(ipc0));
93      ret = ipc_service_open_instance(inst0);
94      ret = ipc_service_register_endpoint(inst0, &ept0, &ept0_cfg);
95
96      /* Wait for endpoint bound (bound_cb called) */
97
98      unsigned char message[] = "hello world";
99      ret = ipc_service_send(&ept0, &message, sizeof(message));
100   }
101
102Data exchange using the no-copy API
103===================================
104
105If the backend supports the no-copy API you can use it to directly write and
106read to and from shared memory regions.
107
108See the following example:
109
110.. code-block:: c
111
112   #include <zephyr/ipc/ipc_service.h>
113   #include <stdint.h>
114   #include <string.h>
115
116   static struct ipc_ept ept0;
117
118   static void bound_cb(void *priv)
119   {
120      /* Endpoint bounded */
121   }
122
123   static void recv_cb_nocopy(const void *data, size_t len, void *priv)
124   {
125      int ret;
126
127      ret = ipc_service_hold_rx_buffer(&ept0, (void *)data);
128      /* Process directly or put the buffer somewhere else and release. */
129      ret = ipc_service_release_rx_buffer(&ept0, (void *)data);
130   }
131
132   static struct ipc_ept_cfg ept0_cfg = {
133      .name = "ept0",
134      .cb = {
135         .bound    = bound_cb,
136         .received = recv_cb,
137      },
138   };
139
140   int main(void)
141   {
142      const struct device *inst0;
143      int ret;
144
145      inst0 = DEVICE_DT_GET(DT_NODELABEL(ipc0));
146      ret = ipc_service_open_instance(inst0);
147      ret = ipc_service_register_endpoint(inst0, &ept0, &ept0_cfg);
148
149      /* Wait for endpoint bound (bound_cb called) */
150      void *data;
151      unsigned char message[] = "hello world";
152      uint32_t len = sizeof(message);
153
154      ret = ipc_service_get_tx_buffer(&ept0, &data, &len, K_FOREVER);
155
156      memcpy(data, message, len);
157
158      ret = ipc_service_send_nocopy(&ept0, data, sizeof(message));
159   }
160
161Backends
162********
163
164The requirements needed for implementing backends give flexibility to the IPC
165service. These allow for the addition of dedicated backends having only a
166subsets of features for specific use cases.
167
168The backend must support at least the following:
169
170* The init-time creation of instances.
171* The run-time registration of an endpoint in an instance.
172
173Additionally, the backend can also support the following:
174
175* The run-time deregistration of an endpoint from the instance.
176* The run-time closing of an instance.
177* The no-copy API.
178
179Each backend can have its own limitations and features that make the backend
180unique and dedicated to a specific use case. The IPC service API can be used
181with multiple backends simultaneously, combining the pros and cons of each
182backend.
183
184.. toctree::
185   :maxdepth: 1
186
187   backends/ipc_service_icmsg.rst
188   backends/ipc_service_icbmsg.rst
189
190API Reference
191*************
192
193IPC service API
194===============
195
196.. doxygengroup:: ipc_service_api
197
198IPC service backend API
199=======================
200
201.. doxygengroup:: ipc_service_backend
202