Morse Micro IoT SDK  2.10.4
iperf.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2023 Morse Micro
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
24#include <string.h>
25#include "mmosal.h"
26#include "mmwlan.h"
27#include "mmconfig.h"
28#include "mmiperf.h"
29
30#include "mmipal.h"
31#include "mm_app_common.h"
32
33/* ------------------------ Configuration options ------------------------ */
34
37{
42};
43
44#ifndef IPERF_TYPE
46#define IPERF_TYPE IPERF_UDP_SERVER
47#endif
48
49#ifndef IPERF_TIME_AMOUNT
55#define IPERF_TIME_AMOUNT -10
56#endif
57#ifndef IPERF_SERVER_PORT
59#define IPERF_SERVER_PORT 5001
60#endif
61
62/* ------------------------ End of configuration options ------------------------ */
63
65static const char units[] = { ' ', 'K', 'M', 'G', 'T' };
66
79static uint32_t format_bytes(uint64_t bytes, uint8_t *unit_index)
80{
81 MMOSAL_ASSERT(unit_index != NULL);
82 *unit_index = 0;
83
84 while (bytes >= 1000 && *unit_index < 4)
85 {
86 bytes /= 1000;
87 (*unit_index)++;
88 }
89
90 return bytes;
91}
92
100static void iperf_report_handler(const struct mmiperf_report *report,
101 void *arg,
102 mmiperf_handle_t handle)
103{
104 (void)arg;
105 (void)handle;
106
107 uint8_t bytes_transferred_unit_index = 0;
108 uint32_t bytes_transferred_formatted =
109 format_bytes(report->bytes_transferred, &bytes_transferred_unit_index);
110
111 printf("\nIperf Report\n");
112 printf(" Remote Address: %s:%d\n", report->remote_addr, report->remote_port);
113 printf(" Local Address: %s:%d\n", report->local_addr, report->local_port);
114 printf(" Transferred: %lu %cBytes, duration: %lu ms, bandwidth: %lu kbps\n",
115 bytes_transferred_formatted,
116 units[bytes_transferred_unit_index],
117 report->duration_ms,
118 report->bandwidth_kbitpsec);
119 printf("\n");
120
121 if ((report->report_type == MMIPERF_UDP_DONE_SERVER) ||
123 {
124 printf("Waiting for client to connect...\n");
125 }
126}
127
129static void start_tcp_client(void)
130{
131 uint32_t server_port = 0;
133
134 /* Get the Server IP */
136 enum mmipal_status status = mmipal_get_ip_config(&ip_config);
137 if (status == MMIPAL_SUCCESS)
138 {
139 memcpy(args.server_addr, ip_config.gateway_addr, sizeof(ip_config.gateway_addr));
140 }
141 else
142 {
143 printf("Failed to retrieve IP config\n");
144 }
145 /* If iperf.server is set, we use it as an override */
146 (void)mmconfig_read_string("iperf.server", args.server_addr, sizeof(args.server_addr));
147
148 mmconfig_read_uint32("iperf.port", &server_port);
149 MMOSAL_ASSERT(server_port <= UINT16_MAX);
150 args.server_port = server_port;
151
152 printf("Attempting to connect to %s:%d over TCP\n",
153 args.server_addr,
154 args.server_port == 0 ? MMIPERF_DEFAULT_PORT : args.server_port);
155
156 int amount = IPERF_TIME_AMOUNT;
157 (void)mmconfig_read_int("iperf.amount", &amount);
158 args.amount = amount;
159 if (args.amount < 0)
160 {
161 args.amount *= 100;
162 }
164
166 printf("\nIperf TCP client started, waiting for completion...\n");
167}
168
170static void start_udp_client(void)
171{
172 uint32_t server_port = 0;
174
175 /* Get the Server IP */
177 enum mmipal_status status = mmipal_get_ip_config(&ip_config);
178 if (status == MMIPAL_SUCCESS)
179 {
180 memcpy(args.server_addr, ip_config.gateway_addr, sizeof(ip_config.gateway_addr));
181 }
182 else
183 {
184 printf("Failed to retrieve IP config\n");
185 }
186 /* If iperf.server is set, we use it as an override */
187 (void)mmconfig_read_string("iperf.server", args.server_addr, sizeof(args.server_addr));
188
189 mmconfig_read_uint32("iperf.port", &server_port);
190 MMOSAL_ASSERT(server_port <= UINT16_MAX);
191 args.server_port = server_port;
192
193 printf("Attempting to connect to %s:%d over UDP\n",
194 args.server_addr,
195 args.server_port == 0 ? MMIPERF_DEFAULT_PORT : args.server_port);
196
197 int amount = IPERF_TIME_AMOUNT;
198 (void)mmconfig_read_int("iperf.amount", &amount);
199 args.amount = amount;
200 if (args.amount < 0)
201 {
202 args.amount *= 100;
203 }
205
207 printf("\nIperf UDP client started, waiting for completion...\n");
208}
209
211static void start_tcp_server(void)
212{
214
215 uint32_t local_port = IPERF_SERVER_PORT;
216 mmconfig_read_uint32("iperf.port", &local_port);
217 args.local_port = (uint16_t)local_port;
218
220
221 mmiperf_handle_t iperf_handle = mmiperf_start_tcp_server(&args);
222 if (iperf_handle == NULL)
223 {
224 printf("Failed to get local address\n");
225 return;
226 }
227 printf("\nIperf TCP server started, waiting for client to connect...\n");
228 struct mmipal_ip_config ip_config;
229 enum mmipal_status status;
230 status = mmipal_get_ip_config(&ip_config);
231 if (status == MMIPAL_SUCCESS)
232 {
233 printf("Execute cmd on AP 'iperf -c %s -p %u -i 1' for IPv4\n",
234 ip_config.ip_addr,
235 args.local_port);
236 }
237
238 struct mmipal_ip6_config ip6_config;
239 status = mmipal_get_ip6_config(&ip6_config);
240 if (status == MMIPAL_SUCCESS)
241 {
242 printf("Execute cmd on AP 'iperf -c %s%%wlan0 -p %u -i 1 -V' for IPv6\n",
243 ip6_config.ip6_addr[0],
244 args.local_port);
245 }
246}
247
249static void start_udp_server(void)
250{
252
253 uint32_t local_port = IPERF_SERVER_PORT;
254 mmconfig_read_uint32("iperf.port", &local_port);
255 args.local_port = (uint16_t)local_port;
256
258
259 mmiperf_handle_t iperf_handle = mmiperf_start_udp_server(&args);
260 if (iperf_handle == NULL)
261 {
262 printf("Failed to start iperf server\n");
263 return;
264 }
265
266 printf("\nIperf UDP server started, waiting for client to connect...\n");
267 struct mmipal_ip_config ip_config;
268 enum mmipal_status status;
269 status = mmipal_get_ip_config(&ip_config);
270 if (status == MMIPAL_SUCCESS)
271 {
272 printf("Execute cmd on AP 'iperf -c %s -p %u -i 1 -u -b 20M' for IPv4\n",
273 ip_config.ip_addr,
274 args.local_port);
275 }
276
277 struct mmipal_ip6_config ip6_config;
278 status = mmipal_get_ip6_config(&ip6_config);
279 if (status == MMIPAL_SUCCESS)
280 {
281 printf("Execute cmd on AP 'iperf -c %s%%wlan0 -p %u -i 1 -V -u -b 20M' for IPv6\n",
282 ip6_config.ip6_addr[0],
283 args.local_port);
284 }
285}
286
291void app_init(void)
292{
293 printf("\n\nMorse Iperf Demo (Built " __DATE__ " " __TIME__ ")\n\n");
294
295 /* Initialize and connect to Wi-Fi, blocks till connected */
298
299 enum iperf_type iperf_mode = IPERF_TYPE;
300 char iperf_mode_str[32];
301 if (mmconfig_read_string("iperf.mode", iperf_mode_str, sizeof(iperf_mode_str)) > 0)
302 {
303 if (strncmp(iperf_mode_str, "udp_server", sizeof(iperf_mode_str)) == 0)
304 {
305 iperf_mode = IPERF_UDP_SERVER;
306 }
307 else if (strncmp(iperf_mode_str, "tcp_server", sizeof(iperf_mode_str)) == 0)
308 {
309 iperf_mode = IPERF_TCP_SERVER;
310 }
311 else if (strncmp(iperf_mode_str, "tcp_client", sizeof(iperf_mode_str)) == 0)
312 {
313 iperf_mode = IPERF_TCP_CLIENT;
314 }
315 else if (strncmp(iperf_mode_str, "udp_client", sizeof(iperf_mode_str)) == 0)
316 {
317 iperf_mode = IPERF_UDP_CLIENT;
318 }
319 else
320 {
321 printf("Unsupported iperf mode: %s\n", iperf_mode_str);
322 return;
323 }
324 }
325
326 switch (iperf_mode)
327 {
328 case IPERF_TCP_SERVER:
330 break;
331
332 case IPERF_UDP_SERVER:
334 break;
335
336 case IPERF_UDP_CLIENT:
338 break;
339
340 case IPERF_TCP_CLIENT:
342 break;
343 }
344}
int mmconfig_read_string(const char *key, char *buffer, int bufsize)
Returns the persistent store string value identified by the key.
int mmconfig_read_int(const char *key, int *value)
Returns the integer stored in persistent store identified by the key.
int mmconfig_read_uint32(const char *key, uint32_t *value)
Returns the unsigned integer stored in persistent store identified by the key.
enum mmipal_status mmipal_get_ip6_config(struct mmipal_ip6_config *config)
Get the IP configurations.
#define MMIPAL_IP_CONFIG_DEFAULT
Initializer for mmipal_ip_config.
Definition: mmipal.h:109
mmipal_status
Enumeration of status codes returned by MMIPAL functions.
Definition: mmipal.h:43
enum mmipal_status mmipal_get_ip_config(struct mmipal_ip_config *config)
Get the IP configurations.
@ MMIPAL_SUCCESS
Completed successfully.
Definition: mmipal.h:45
mmiperf_handle_t mmiperf_start_tcp_client(const struct mmiperf_client_args *args)
Start a TCP iperf client.
#define MMIPERF_CLIENT_ARGS_DEFAULT
Initializer for mmiperf_client_args.
Definition: mmiperf.h:182
mmiperf_handle_t mmiperf_start_udp_client(const struct mmiperf_client_args *args)
Start a UDP iperf client.
mmiperf_handle_t mmiperf_start_udp_server(const struct mmiperf_server_args *args)
Start a UDP iperf server.
#define MMIPERF_DEFAULT_PORT
Default port for TCP and UDP iperf.
Definition: mmiperf.h:34
#define MMIPERF_SERVER_ARGS_DEFAULT
Initializer for mmiperf_server_args.
Definition: mmiperf.h:213
struct mmiperf_state * mmiperf_handle_t
Iperf client/server handle.
Definition: mmiperf.h:97
mmiperf_handle_t mmiperf_start_tcp_server(const struct mmiperf_server_args *args)
Start a TCP iperf server.
@ MMIPERF_UDP_DONE_SERVER
The server side test is done.
Definition: mmiperf.h:69
@ MMIPERF_TCP_DONE_SERVER
The server side test is done.
Definition: mmiperf.h:57
#define MMOSAL_ASSERT(expr)
Assert that the given expression evaluates to true and abort execution if not.
Definition: mmosal.h:934
static void start_tcp_client(void)
Start iperf as a TCP client.
Definition: iperf.c:129
static const char units[]
Array of power of 10 unit specifiers.
Definition: iperf.c:65
static void start_udp_client(void)
Start iperf as a UDP client.
Definition: iperf.c:170
static void start_tcp_server(void)
Start iperf as a TCP server.
Definition: iperf.c:211
iperf_type
Iperf configurations.
Definition: iperf.c:37
@ IPERF_TCP_SERVER
TCP server (RX)
Definition: iperf.c:38
@ IPERF_TCP_CLIENT
TCP client (TX)
Definition: iperf.c:40
@ IPERF_UDP_CLIENT
UDP client (TX)
Definition: iperf.c:41
@ IPERF_UDP_SERVER
UDP server (RX)
Definition: iperf.c:39
static void iperf_report_handler(const struct mmiperf_report *report, void *arg, mmiperf_handle_t handle)
Handle a report at the end of an iperf transfer.
Definition: iperf.c:100
#define IPERF_SERVER_PORT
Specifies the port to listen on in server mode.
Definition: iperf.c:59
static uint32_t format_bytes(uint64_t bytes, uint8_t *unit_index)
Function to format a given number of bytes into an appropriate SI base.
Definition: iperf.c:79
static void start_udp_server(void)
Start iperf as a UDP server.
Definition: iperf.c:249
#define IPERF_TIME_AMOUNT
Duration for client transfers specified either in seconds or bytes.
Definition: iperf.c:55
#define IPERF_TYPE
Type of iperf instance to start.
Definition: iperf.c:46
void app_init(void)
Main entry point to the application.
Definition: iperf.c:291
Morse Micro application helper routines for initializing/de-initializing the Wireless LAN interface a...
void app_wlan_init(void)
Initializes the WLAN interface (and dependencies) using settings specified in the config store.
void app_wlan_start(void)
Starts the WLAN interface and connects to Wi-Fi using settings specified in the config store.
IPv6 configuration structure.
Definition: mmipal.h:143
mmipal_ip_addr_t ip6_addr[MMIPAL_MAX_IPV6_ADDRESSES]
Array of IPv6 addresses.
Definition: mmipal.h:147
IPv4 configuration structure.
Definition: mmipal.h:97
mmipal_ip_addr_t gateway_addr
Gateway address.
Definition: mmipal.h:105
mmipal_ip_addr_t ip_addr
local IP address
Definition: mmipal.h:101
Iperf client arguments data structure.
Definition: mmiperf.h:158
char server_addr[MMIPERF_IPADDR_MAXLEN]
IP address of iperf server to communicate with (as a string).
Definition: mmiperf.h:160
mmiperf_report_fn report_fn
Report callback function to invoke on completion/abort.
Definition: mmiperf.h:174
int32_t amount
If positive specifies how many bytes to transfer; if negative the absolute value specifies the durati...
Definition: mmiperf.h:172
uint16_t server_port
Port on iperf server to communicate with.
Definition: mmiperf.h:162
Report data structure.
Definition: mmiperf.h:101
enum mmiperf_report_type report_type
Type of report.
Definition: mmiperf.h:103
char local_addr[MMIPERF_IPADDR_MAXLEN]
Local address (as string).
Definition: mmiperf.h:105
uint16_t local_port
Local port.
Definition: mmiperf.h:107
uint16_t remote_port
Remote port.
Definition: mmiperf.h:111
uint32_t bandwidth_kbitpsec
Average throughput in kbps.
Definition: mmiperf.h:117
char remote_addr[MMIPERF_IPADDR_MAXLEN]
Remote address (as string).
Definition: mmiperf.h:109
uint64_t bytes_transferred
Number of bytes of data transferred during test.
Definition: mmiperf.h:113
uint32_t duration_ms
Duration of the test in milliseconds.
Definition: mmiperf.h:115
Iperf server arguments data structure.
Definition: mmiperf.h:199
mmiperf_report_fn report_fn
Report callback function to invoke on completion/abort.
Definition: mmiperf.h:205
uint16_t local_port
Local port to listen on.
Definition: mmiperf.h:203