1 /*
2 * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9
10 #include <zephyr/ipc/ipc_service.h>
11
12 #define STACKSIZE (4096)
13 #define PRIORITY K_PRIO_PREEMPT(2)
14
15 K_THREAD_STACK_DEFINE(ipc0A_stack, STACKSIZE);
16 K_THREAD_STACK_DEFINE(ipc0B_stack, STACKSIZE);
17 K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE);
18
19 static volatile uint8_t ipc0A_received_data;
20 static volatile uint8_t ipc0B_received_data;
21 static volatile uint8_t ipc1_received_data;
22
23 static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1);
24 static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1);
25 static K_SEM_DEFINE(ipc1_bound_sem, 0, 1);
26
27 static K_SEM_DEFINE(ipc0A_data_sem, 0, 1);
28 static K_SEM_DEFINE(ipc0B_data_sem, 0, 1);
29 static K_SEM_DEFINE(ipc1_data_sem, 0, 1);
30
31 /*
32 * ==> THREAD 0A (IPC instance 0 - endpoint A) <==
33 */
34
ipc0A_ept_bound(void * priv)35 static void ipc0A_ept_bound(void *priv)
36 {
37 k_sem_give(&ipc0A_bound_sem);
38 }
39
ipc0A_ept_recv(const void * data,size_t len,void * priv)40 static void ipc0A_ept_recv(const void *data, size_t len, void *priv)
41 {
42 ipc0A_received_data = *((uint8_t *) data);
43
44 k_sem_give(&ipc0A_data_sem);
45 }
46
47 static struct ipc_ept_cfg ipc0A_ept_cfg = {
48 .name = "ipc0A",
49 .cb = {
50 .bound = ipc0A_ept_bound,
51 .received = ipc0A_ept_recv,
52 },
53 };
54
ipc0A_entry(void * dummy0,void * dummy1,void * dummy2)55 static void ipc0A_entry(void *dummy0, void *dummy1, void *dummy2)
56 {
57 ARG_UNUSED(dummy0);
58 ARG_UNUSED(dummy1);
59 ARG_UNUSED(dummy2);
60
61 const struct device *ipc0_instance;
62 unsigned char message = 0;
63 struct ipc_ept ipc0A_ept;
64 int ret;
65
66 printk("IPC-service HOST [INST 0 - ENDP A] demo started\n");
67
68 ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
69
70 ret = ipc_service_open_instance(ipc0_instance);
71 if (ret < 0 && ret != -EALREADY) {
72 printk("ipc_service_open_instance() failure\n");
73 return;
74 }
75
76 /*
77 * Wait 1 sec to give the opportunity to the SECONDARY core to register
78 * the endpoint first
79 */
80
81 k_sleep(K_MSEC(1000));
82
83 ret = ipc_service_register_endpoint(ipc0_instance, &ipc0A_ept, &ipc0A_ept_cfg);
84 if (ret < 0) {
85 printf("ipc_service_register_endpoint() failure\n");
86 return;
87 }
88
89 k_sem_take(&ipc0A_bound_sem, K_FOREVER);
90
91 while (message < 100) {
92 ret = ipc_service_send(&ipc0A_ept, &message, sizeof(message));
93 if (ret < 0) {
94 printk("send_message(%d) failed with ret %d\n", message, ret);
95 break;
96 }
97
98 k_sem_take(&ipc0A_data_sem, K_FOREVER);
99 message = ipc0A_received_data;
100
101 printk("HOST [0A]: %d\n", message);
102 message++;
103 }
104
105 printk("IPC-service HOST [INST 0 - ENDP A] demo ended.\n");
106 }
107 K_THREAD_DEFINE(ipc0A_thread_id, STACKSIZE, ipc0A_entry, NULL, NULL, NULL, PRIORITY, 0, 0);
108
109 /*
110 * ==> THREAD 0B (IPC instance 0 - endpoint B) <==
111 */
112
ipc0B_ept_bound(void * priv)113 static void ipc0B_ept_bound(void *priv)
114 {
115 k_sem_give(&ipc0B_bound_sem);
116 }
117
ipc0B_ept_recv(const void * data,size_t len,void * priv)118 static void ipc0B_ept_recv(const void *data, size_t len, void *priv)
119 {
120 ipc0B_received_data = *((uint8_t *) data);
121
122 k_sem_give(&ipc0B_data_sem);
123 }
124
125 static struct ipc_ept_cfg ipc0B_ept_cfg = {
126 .name = "ipc0B",
127 .cb = {
128 .bound = ipc0B_ept_bound,
129 .received = ipc0B_ept_recv,
130 },
131 };
132
ipc0B_entry(void * dummy0,void * dummy1,void * dummy2)133 static void ipc0B_entry(void *dummy0, void *dummy1, void *dummy2)
134 {
135 ARG_UNUSED(dummy0);
136 ARG_UNUSED(dummy1);
137 ARG_UNUSED(dummy2);
138
139 const struct device *ipc0_instance;
140 unsigned char message = 0;
141 struct ipc_ept ipc0B_ept;
142 int ret;
143
144 printk("IPC-service HOST [INST 0 - ENDP B] demo started\n");
145
146 ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
147
148 ret = ipc_service_open_instance(ipc0_instance);
149 if (ret < 0 && ret != -EALREADY) {
150 printk("ipc_service_open_instance() failure\n");
151 return;
152 }
153
154 ret = ipc_service_register_endpoint(ipc0_instance, &ipc0B_ept, &ipc0B_ept_cfg);
155 if (ret < 0) {
156 printf("ipc_service_register_endpoint() failure\n");
157 return;
158 }
159
160 k_sem_take(&ipc0B_bound_sem, K_FOREVER);
161
162 while (message < 100) {
163 ret = ipc_service_send(&ipc0B_ept, &message, sizeof(message));
164 if (ret < 0) {
165 printk("send_message(%d) failed with ret %d\n", message, ret);
166 break;
167 }
168
169 k_sem_take(&ipc0B_data_sem, K_FOREVER);
170 message = ipc0B_received_data;
171
172 printk("HOST [0B]: %d\n", message);
173 message++;
174 }
175
176 printk("IPC-service HOST [INST 0 - ENDP B] demo ended.\n");
177 }
178 K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIORITY, 0, 0);
179
180 /*
181 * ==> THREAD 1 (IPC instance 1) <==
182 *
183 * NOTE: This instance is using the NOCOPY copability of the backend.
184 */
185
186 static struct ipc_ept ipc1_ept;
187 static void *recv_data;
188
ipc1_ept_bound(void * priv)189 static void ipc1_ept_bound(void *priv)
190 {
191 k_sem_give(&ipc1_bound_sem);
192 }
193
ipc1_ept_recv(const void * data,size_t len,void * priv)194 static void ipc1_ept_recv(const void *data, size_t len, void *priv)
195 {
196 int ret;
197
198 ret = ipc_service_hold_rx_buffer(&ipc1_ept, (void *) data);
199 if (ret < 0) {
200 printk("ipc_service_hold_rx_buffer failed with ret %d\n", ret);
201 }
202
203 /*
204 * This will only support a synchronous request-answer mechanism. For
205 * asynchronous cases a chain list should be implemented.
206 */
207 recv_data = (void *) data;
208
209 k_sem_give(&ipc1_data_sem);
210 }
211
212 static struct ipc_ept_cfg ipc1_ept_cfg = {
213 .name = "ipc1",
214 .cb = {
215 .bound = ipc1_ept_bound,
216 .received = ipc1_ept_recv,
217 },
218 };
219
ipc1_entry(void * dummy0,void * dummy1,void * dummy2)220 static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2)
221 {
222 ARG_UNUSED(dummy0);
223 ARG_UNUSED(dummy1);
224 ARG_UNUSED(dummy2);
225
226 const struct device *ipc1_instance;
227 unsigned char message = 0;
228 int ret;
229
230 printk("IPC-service HOST [INST 1] demo started\n");
231
232 ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1));
233
234 ret = ipc_service_open_instance(ipc1_instance);
235 if (ret < 0 && ret != -EALREADY) {
236 printk("ipc_service_open_instance() failure\n");
237 return;
238 }
239
240 ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg);
241 if (ret < 0) {
242 printf("ipc_service_register_endpoint() failure\n");
243 return;
244 }
245
246 k_sem_take(&ipc1_bound_sem, K_FOREVER);
247
248 while (message < 50) {
249 uint32_t len = 0;
250 void *data;
251
252 ret = ipc_service_get_tx_buffer(&ipc1_ept, &data, &len, K_FOREVER);
253 if (ret < 0) {
254 printk("ipc_service_get_tx_buffer failed with ret %d\n", ret);
255 break;
256 }
257
258 if (message != 0) {
259 *((unsigned char *) data) = *((unsigned char *) recv_data) + 1;
260
261 ret = ipc_service_release_rx_buffer(&ipc1_ept, recv_data);
262 if (ret < 0) {
263 printk("ipc_service_release_rx_buffer failed with ret %d\n", ret);
264 break;
265 }
266 } else {
267 *((unsigned char *) data) = 0;
268 }
269
270 ret = ipc_service_send_nocopy(&ipc1_ept, data, sizeof(unsigned char));
271 if (ret < 0) {
272 printk("send_message(%d) failed with ret %d\n", message, ret);
273 break;
274 }
275
276 k_sem_take(&ipc1_data_sem, K_FOREVER);
277
278 printk("HOST [1]: %d\n", *((unsigned char *) recv_data));
279
280 message++;
281 }
282
283 printk("IPC-service HOST [INST 1] demo ended.\n");
284 }
285 K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0);
286