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 #if defined(CONFIG_SOC_NRF5340_CPUAPP)
12 #include <nrf53_cpunet_mgmt.h>
13 #endif
14 #include <string.h>
15 
16 #include "common.h"
17 
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(host, LOG_LEVEL_INF);
20 
21 #if defined(CONFIG_MULTITHREADING)
22 K_SEM_DEFINE(bound_sem, 0, 1);
23 #else
24 volatile uint32_t bound_sem = 1;
25 volatile uint32_t recv_sem = 1;
26 #endif
27 
28 static unsigned char expected_message = 'A';
29 static size_t expected_len = PACKET_SIZE_START;
30 static size_t received;
31 
ep_bound(void * priv)32 static void ep_bound(void *priv)
33 {
34 	received = 0;
35 #if defined(CONFIG_MULTITHREADING)
36 	k_sem_give(&bound_sem);
37 #else
38 	bound_sem = 0;
39 #endif
40 	LOG_INF("Ep bounded");
41 }
42 
ep_unbound(void * priv)43 static void ep_unbound(void *priv)
44 {
45 	LOG_INF("Ep unbounded");
46 }
47 
ep_recv(const void * data,size_t len,void * priv)48 static void ep_recv(const void *data, size_t len, void *priv)
49 {
50 #if defined(CONFIG_ASSERT)
51 	struct data_packet *packet = (struct data_packet *)data;
52 
53 	__ASSERT(packet->data[0] == expected_message, "Unexpected message. Expected %c, got %c",
54 		expected_message, packet->data[0]);
55 	__ASSERT(len == expected_len, "Unexpected length. Expected %zu, got %zu",
56 		expected_len, len);
57 #endif
58 
59 #ifndef CONFIG_MULTITHREADING
60 	recv_sem = 0;
61 #endif
62 
63 	received += len;
64 	expected_message++;
65 	expected_len++;
66 
67 	if (expected_message > 'Z') {
68 		expected_message = 'A';
69 	}
70 
71 	if (expected_len > sizeof(struct data_packet)) {
72 		expected_len = PACKET_SIZE_START;
73 	}
74 }
75 
ep_error(const char * message,void * priv)76 static void ep_error(const char *message, void *priv)
77 {
78 	LOG_ERR("ICMsg error: %s", message);
79 }
80 
send_for_time(struct ipc_ept * ep,const int64_t sending_time_ms)81 static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms)
82 {
83 	struct data_packet msg = {.data[0] = 'a'};
84 	size_t mlen = PACKET_SIZE_START;
85 	size_t bytes_sent = 0;
86 	int ret = 0;
87 
88 	LOG_INF("Perform sends for %lld [ms]", sending_time_ms);
89 
90 	int64_t start = k_uptime_get();
91 
92 	while ((k_uptime_get() - start) < sending_time_ms) {
93 		ret = ipc_service_send(ep, &msg, mlen);
94 		if (ret == -ENOMEM) {
95 			/* No space in the buffer. Retry. */
96 			ret = 0;
97 			continue;
98 		} else if (ret < 0) {
99 			LOG_ERR("Failed to send (%c) failed with ret %d", msg.data[0], ret);
100 			break;
101 		}
102 #if !defined(CONFIG_MULTITHREADING)
103 		else {
104 			recv_sem = 1;
105 		}
106 #endif
107 
108 		msg.data[0]++;
109 		if (msg.data[0] > 'z') {
110 			msg.data[0] = 'a';
111 		}
112 
113 		bytes_sent += mlen;
114 		mlen++;
115 
116 		if (mlen > sizeof(struct data_packet)) {
117 			mlen = PACKET_SIZE_START;
118 		}
119 
120 #if defined(CONFIG_MULTITHREADING)
121 		k_usleep(1);
122 #else
123 		while ((recv_sem != 0) && ((k_uptime_get() - start) < sending_time_ms)) {
124 		};
125 #endif
126 	}
127 
128 	LOG_INF("Sent %zu [Bytes] over %lld [ms]", bytes_sent, sending_time_ms);
129 
130 	return ret;
131 }
132 
133 static struct ipc_ept_cfg ep_cfg = {
134 	.cb = {
135 		.bound    = ep_bound,
136 		.unbound  = ep_unbound,
137 		.received = ep_recv,
138 		.error    = ep_error,
139 	},
140 };
141 
main(void)142 int main(void)
143 {
144 	const struct device *ipc0_instance;
145 	struct ipc_ept ep;
146 	int ret;
147 
148 	LOG_INF("IPC-service HOST demo started");
149 
150 #if defined(CONFIG_SOC_NRF5340_CPUAPP)
151 	LOG_INF("Run network core");
152 	nrf53_cpunet_enable(true);
153 #endif
154 
155 	ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
156 
157 	ret = ipc_service_open_instance(ipc0_instance);
158 	if ((ret < 0) && (ret != -EALREADY)) {
159 		LOG_ERR("ipc_service_open_instance() failure");
160 		return ret;
161 	}
162 
163 	ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
164 	if (ret < 0) {
165 		LOG_ERR("ipc_service_register_endpoint() failure");
166 		return ret;
167 	}
168 
169 #if defined(CONFIG_MULTITHREADING)
170 	k_sem_take(&bound_sem, K_FOREVER);
171 #else
172 	while (bound_sem != 0) {
173 	};
174 #endif
175 
176 	ret = send_for_time(&ep, SENDING_TIME_MS);
177 	if (ret < 0) {
178 		LOG_ERR("send_for_time() failure");
179 		return ret;
180 	}
181 
182 	LOG_INF("Wait 500ms. Let remote core finish its sends");
183 #if defined(CONFIG_MULTITHREADING)
184 	k_msleep(500);
185 #else
186 	k_busy_wait(500000);
187 #endif
188 
189 	LOG_INF("Received %zu [Bytes] in total", received);
190 
191 #if defined(CONFIG_SOC_NRF5340_CPUAPP)
192 	LOG_INF("Stop network core");
193 	nrf53_cpunet_enable(false);
194 
195 	LOG_INF("Reset IPC service");
196 
197 	ret = ipc_service_deregister_endpoint(&ep);
198 	if (ret != 0) {
199 		LOG_ERR("ipc_service_register_endpoint() failure");
200 		return ret;
201 	}
202 
203 	/* Reset message and expected message value and len. */
204 	expected_message = 'A';
205 	expected_len = PACKET_SIZE_START;
206 
207 	/* Reset bound sem. */
208 	ret = k_sem_init(&bound_sem, 0, 1);
209 	if (ret != 0) {
210 		LOG_ERR("k_sem_init() failure");
211 		return ret;
212 	}
213 
214 	ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
215 	if (ret != 0) {
216 		LOG_INF("ipc_service_register_endpoint() failure");
217 		return ret;
218 	}
219 
220 	LOG_INF("Run network core");
221 	nrf53_cpunet_enable(true);
222 
223 	k_sem_take(&bound_sem, K_FOREVER);
224 
225 	ret = send_for_time(&ep, SENDING_TIME_MS);
226 	if (ret < 0) {
227 		LOG_ERR("send_for_time() failure");
228 		return ret;
229 	}
230 #endif /* CONFIG_SOC_NRF5340_CPUAPP */
231 
232 	LOG_INF("IPC-service HOST demo ended");
233 
234 	return 0;
235 }
236