1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
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
ipc1_ept_bound(void * priv)184 static void ipc1_ept_bound(void *priv)
185 {
186 k_sem_give(&ipc1_bound_sem);
187 }
188
ipc1_ept_recv(const void * data,size_t len,void * priv)189 static void ipc1_ept_recv(const void *data, size_t len, void *priv)
190 {
191 ipc1_received_data = *((uint8_t *) data);
192
193 k_sem_give(&ipc1_data_sem);
194 }
195
196 static struct ipc_ept_cfg ipc1_ept_cfg = {
197 .name = "ipc1",
198 .cb = {
199 .bound = ipc1_ept_bound,
200 .received = ipc1_ept_recv,
201 },
202 };
203
ipc1_entry(void * dummy0,void * dummy1,void * dummy2)204 static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2)
205 {
206 ARG_UNUSED(dummy0);
207 ARG_UNUSED(dummy1);
208 ARG_UNUSED(dummy2);
209
210 const struct device *ipc1_instance;
211 unsigned char message = 0;
212 struct ipc_ept ipc1_ept;
213 int ret;
214
215 printk("IPC-service HOST [INST 1] demo started\n");
216
217 ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1));
218
219 ret = ipc_service_open_instance(ipc1_instance);
220 if (ret < 0 && ret != -EALREADY) {
221 printk("ipc_service_open_instance() failure\n");
222 return;
223 }
224
225 ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg);
226 if (ret < 0) {
227 printf("ipc_service_register_endpoint() failure\n");
228 return;
229 }
230
231 k_sem_take(&ipc1_bound_sem, K_FOREVER);
232
233 /*
234 * Wait 1 sec to start sending simultaneously with other threads
235 * the endpoint first
236 */
237
238 k_sleep(K_MSEC(1000));
239
240 while (message < 100) {
241 ret = ipc_service_send(&ipc1_ept, &message, sizeof(message));
242 if (ret < 0) {
243 printk("send_message(%d) failed with ret %d\n", message, ret);
244 break;
245 }
246
247 k_sem_take(&ipc1_data_sem, K_FOREVER);
248 message = ipc1_received_data;
249
250 printk("HOST [1]: %d\n", message);
251 message++;
252 }
253
254 printk("IPC-service HOST [INST 1] demo ended.\n");
255 }
256 K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0);
257