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 (1024)
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 REMOTE [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 ret = ipc_service_register_endpoint(ipc0_instance, &ipc0A_ept, &ipc0A_ept_cfg);
77 if (ret < 0) {
78 printf("ipc_service_register_endpoint() failure\n");
79 return;
80 }
81
82 k_sem_take(&ipc0A_bound_sem, K_FOREVER);
83
84 while (message < 99) {
85 k_sem_take(&ipc0A_data_sem, K_FOREVER);
86 message = ipc0A_received_data;
87
88 printk("REMOTE [0A]: %d\n", message);
89
90 message++;
91
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
99 printk("IPC-service REMOTE [INST 0 - ENDP A] demo ended.\n");
100 }
101 K_THREAD_DEFINE(ipc0A_thread_id, STACKSIZE, ipc0A_entry, NULL, NULL, NULL, PRIORITY, 0, 0);
102
103 /*
104 * ==> THREAD 0B (IPC instance 0 - endpoint B) <==
105 */
106
ipc0B_ept_bound(void * priv)107 static void ipc0B_ept_bound(void *priv)
108 {
109 k_sem_give(&ipc0B_bound_sem);
110 }
111
ipc0B_ept_recv(const void * data,size_t len,void * priv)112 static void ipc0B_ept_recv(const void *data, size_t len, void *priv)
113 {
114 ipc0B_received_data = *((uint8_t *) data);
115
116 k_sem_give(&ipc0B_data_sem);
117 }
118
119 static struct ipc_ept_cfg ipc0B_ept_cfg = {
120 .name = "ipc0B",
121 .cb = {
122 .bound = ipc0B_ept_bound,
123 .received = ipc0B_ept_recv,
124 },
125 };
126
ipc0B_entry(void * dummy0,void * dummy1,void * dummy2)127 static void ipc0B_entry(void *dummy0, void *dummy1, void *dummy2)
128 {
129 ARG_UNUSED(dummy0);
130 ARG_UNUSED(dummy1);
131 ARG_UNUSED(dummy2);
132
133 const struct device *ipc0_instance;
134 unsigned char message = 0;
135 struct ipc_ept ipc0B_ept;
136 int ret;
137
138 printk("IPC-service REMOTE [INST 0 - ENDP B] demo started\n");
139
140 ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
141
142 ret = ipc_service_open_instance(ipc0_instance);
143 if (ret < 0 && ret != -EALREADY) {
144 printk("ipc_service_open_instance() failure\n");
145 return;
146 }
147
148 /*
149 * Wait 2 sec to give the opportunity to the PRIMARY core to register
150 * the endpoint first
151 */
152
153 k_sleep(K_MSEC(2000));
154
155 ret = ipc_service_register_endpoint(ipc0_instance, &ipc0B_ept, &ipc0B_ept_cfg);
156 if (ret < 0) {
157 printf("ipc_service_register_endpoint() failure\n");
158 return;
159 }
160
161 k_sem_take(&ipc0B_bound_sem, K_FOREVER);
162
163 while (message < 99) {
164 k_sem_take(&ipc0B_data_sem, K_FOREVER);
165 message = ipc0B_received_data;
166
167 printk("REMOTE [0B]: %d\n", message);
168
169 message++;
170
171 ret = ipc_service_send(&ipc0B_ept, &message, sizeof(message));
172 if (ret < 0) {
173 printk("send_message(%d) failed with ret %d\n", message, ret);
174 break;
175 }
176 }
177
178 printk("IPC-service REMOTE [INST 0 - ENDP B] demo ended.\n");
179 }
180 K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIORITY, 0, 0);
181
182 /*
183 * ==> THREAD 1 (IPC instance 1) <==
184 *
185 * NOTE: This instance is using the NOCOPY copability of the backend.
186 */
187
188 static struct ipc_ept ipc1_ept;
189 static void *recv_data;
190
ipc1_ept_bound(void * priv)191 static void ipc1_ept_bound(void *priv)
192 {
193 k_sem_give(&ipc1_bound_sem);
194 }
195
ipc1_ept_recv(const void * data,size_t len,void * priv)196 static void ipc1_ept_recv(const void *data, size_t len, void *priv)
197 {
198 int ret;
199
200 ret = ipc_service_hold_rx_buffer(&ipc1_ept, (void *) data);
201 if (ret < 0) {
202 printk("ipc_service_hold_rx_buffer failed with ret %d\n", ret);
203 }
204
205 /*
206 * This will only support a synchronous request-answer mechanism. For
207 * asynchronous cases a chain list should be implemented.
208 */
209 recv_data = (void *) data;
210
211 k_sem_give(&ipc1_data_sem);
212 }
213
214 static struct ipc_ept_cfg ipc1_ept_cfg = {
215 .name = "ipc1",
216 .cb = {
217 .bound = ipc1_ept_bound,
218 .received = ipc1_ept_recv,
219 },
220 };
221
ipc1_entry(void * dummy0,void * dummy1,void * dummy2)222 static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2)
223 {
224 ARG_UNUSED(dummy0);
225 ARG_UNUSED(dummy1);
226 ARG_UNUSED(dummy2);
227
228 const struct device *ipc1_instance;
229 unsigned char message = 0;
230 int ret;
231
232 printk("IPC-service REMOTE [INST 1] demo started\n");
233
234 ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1));
235
236 ret = ipc_service_open_instance(ipc1_instance);
237 if (ret < 0 && ret != -EALREADY) {
238 printk("ipc_service_open_instance() failure\n");
239 return;
240 }
241
242 ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg);
243 if (ret < 0) {
244 printf("ipc_service_register_endpoint() failure\n");
245 return;
246 }
247
248 k_sem_take(&ipc1_bound_sem, K_FOREVER);
249
250 while (message < 50) {
251 uint32_t len = sizeof(message);
252 void *data;
253
254 k_sem_take(&ipc1_data_sem, K_FOREVER);
255
256 printk("REMOTE [1]: %d\n", *((unsigned char *) recv_data));
257
258 ret = ipc_service_get_tx_buffer(&ipc1_ept, &data, &len, K_FOREVER);
259 if (ret < 0) {
260 printk("ipc_service_get_tx_buffer failed with ret %d\n", ret);
261 break;
262 }
263
264 *((unsigned char *) data) = *((unsigned char *) recv_data) + 1;
265
266 ret = ipc_service_release_rx_buffer(&ipc1_ept, recv_data);
267 if (ret < 0) {
268 printk("ipc_service_release_rx_buffer failed with ret %d\n", ret);
269 break;
270 }
271
272 ret = ipc_service_send_nocopy(&ipc1_ept, data, sizeof(unsigned char));
273 if (ret < 0) {
274 printk("send_message(%d) failed with ret %d\n", message, ret);
275 break;
276 }
277
278 message++;
279 }
280
281 printk("IPC-service REMOTE [INST 1] demo ended.\n");
282 }
283 K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0);
284