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