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