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 #include <hal/nrf_reset.h>
12 #include <string.h>
13 
14 #include "common.h"
15 
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(host, LOG_LEVEL_INF);
18 
19 
20 K_SEM_DEFINE(bound_sem, 0, 1);
21 static unsigned char expected_message = 'A';
22 static size_t expected_len = PACKET_SIZE_START;
23 
ep_bound(void * priv)24 static void ep_bound(void *priv)
25 {
26 	k_sem_give(&bound_sem);
27 	LOG_INF("Ep bounded");
28 }
29 
ep_recv(const void * data,size_t len,void * priv)30 static void ep_recv(const void *data, size_t len, void *priv)
31 {
32 	struct data_packet *packet = (struct data_packet *)data;
33 
34 	__ASSERT(packet->data[0] == expected_message, "Unexpected message. Expected %c, got %c",
35 		expected_message, packet->data[0]);
36 	__ASSERT(len == expected_len, "Unexpected length. Expected %zu, got %zu",
37 		expected_len, len);
38 
39 	expected_message++;
40 	expected_len++;
41 
42 	if (expected_message > 'Z') {
43 		expected_message = 'A';
44 	}
45 
46 	if (expected_len > sizeof(struct data_packet)) {
47 		expected_len = PACKET_SIZE_START;
48 	}
49 }
50 
send_for_time(struct ipc_ept * ep,const int64_t sending_time_ms)51 static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms)
52 {
53 	struct data_packet msg = {.data[0] = 'a'};
54 	size_t mlen = PACKET_SIZE_START;
55 	size_t bytes_sent = 0;
56 	int ret = 0;
57 
58 	LOG_INF("Perform sends for %lld [ms]", sending_time_ms);
59 
60 	int64_t start = k_uptime_get();
61 
62 	while ((k_uptime_get() - start) < sending_time_ms) {
63 		ret = ipc_service_send(ep, &msg, mlen);
64 		if (ret == -ENOMEM) {
65 			/* No space in the buffer. Retry. */
66 			continue;
67 		} else if (ret < 0) {
68 			LOG_ERR("Failed to send (%c) failed with ret %d", msg.data[0], ret);
69 			break;
70 		}
71 
72 		msg.data[0]++;
73 		if (msg.data[0] > 'z') {
74 			msg.data[0] = 'a';
75 		}
76 
77 		bytes_sent += mlen;
78 		mlen++;
79 
80 		if (mlen > sizeof(struct data_packet)) {
81 			mlen = PACKET_SIZE_START;
82 		}
83 
84 		k_usleep(1);
85 	}
86 
87 	LOG_INF("Sent %zu [Bytes] over %lld [ms]", bytes_sent, sending_time_ms);
88 
89 	return ret;
90 }
91 
92 static struct ipc_ept_cfg ep_cfg = {
93 	.cb = {
94 		.bound    = ep_bound,
95 		.received = ep_recv,
96 	},
97 };
98 
main(void)99 int main(void)
100 {
101 	const struct device *ipc0_instance;
102 	struct ipc_ept ep;
103 	int ret;
104 
105 	LOG_INF("IPC-service HOST demo started");
106 
107 	ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
108 
109 	ret = ipc_service_open_instance(ipc0_instance);
110 	if ((ret < 0) && (ret != -EALREADY)) {
111 		LOG_ERR("ipc_service_open_instance() failure");
112 		return ret;
113 	}
114 
115 	ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
116 	if (ret < 0) {
117 		LOG_ERR("ipc_service_register_endpoint() failure");
118 		return ret;
119 	}
120 
121 	k_sem_take(&bound_sem, K_FOREVER);
122 
123 	ret = send_for_time(&ep, SENDING_TIME_MS);
124 	if (ret < 0) {
125 		LOG_ERR("send_for_time() failure");
126 		return ret;
127 	}
128 
129 	LOG_INF("Wait 500ms. Let net core finish its sends");
130 	k_msleep(500);
131 
132 	LOG_INF("Stop network core");
133 	nrf_reset_network_force_off(NRF_RESET, true);
134 
135 	LOG_INF("Reset IPC service");
136 
137 	ret = ipc_service_deregister_endpoint(&ep);
138 	if (ret != 0) {
139 		LOG_ERR("ipc_service_register_endpoint() failure");
140 		return ret;
141 	}
142 
143 	/* Reset message and expected message value and len. */
144 	expected_message = 'A';
145 	expected_len = PACKET_SIZE_START;
146 
147 	/* Reset bound sem. */
148 	ret = k_sem_init(&bound_sem, 0, 1);
149 	if (ret != 0) {
150 		LOG_ERR("k_sem_init() failure");
151 		return ret;
152 	}
153 
154 	ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
155 	if (ret != 0) {
156 		LOG_INF("ipc_service_register_endpoint() failure");
157 		return ret;
158 	}
159 
160 	LOG_INF("Run network core");
161 	nrf_reset_network_force_off(NRF_RESET, false);
162 
163 	k_sem_take(&bound_sem, K_FOREVER);
164 
165 	ret = send_for_time(&ep, SENDING_TIME_MS);
166 	if (ret < 0) {
167 		LOG_ERR("send_for_time() failure");
168 		return ret;
169 	}
170 
171 	LOG_INF("IPC-service HOST demo ended");
172 
173 	return 0;
174 }
175