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