Morse Micro IoT SDK  2.9.7
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, void *arg,
101 mmiperf_handle_t handle)
102{
103 (void)arg;
104 (void)handle;
105
106 uint8_t bytes_transferred_unit_index = 0;
107 uint32_t bytes_transferred_formatted = format_bytes(report->bytes_transferred,
108 &bytes_transferred_unit_index);
109
110 printf("\nIperf Report\n");
111 printf(" Remote Address: %s:%d\n", report->remote_addr, report->remote_port);
112 printf(" Local Address: %s:%d\n", report->local_addr, report->local_port);
113 printf(" Transferred: %lu %cBytes, duration: %lu ms, bandwidth: %lu kbps\n",
114 bytes_transferred_formatted, units[bytes_transferred_unit_index],
115 report->duration_ms, report->bandwidth_kbitpsec);
116 printf("\n");
117
118 if ((report->report_type == MMIPERF_UDP_DONE_SERVER) ||
120 {
121 printf("Waiting for client to connect...\n");
122 }
123}
124
126static void start_tcp_client(void)
127{
128 uint32_t server_port = 0;
130
131 /* Get the Server IP */
133 enum mmipal_status status = mmipal_get_ip_config(&ip_config);
134 if (status == MMIPAL_SUCCESS)
135 {
136 memcpy(args.server_addr, ip_config.gateway_addr, sizeof(ip_config.gateway_addr));
137 }
138 else
139 {
140 printf("Failed to retrieve IP config\n");
141 }
142 /* If iperf.server is set, we use it as an override */
143 (void)mmconfig_read_string("iperf.server", args.server_addr, sizeof(args.server_addr));
144
145 mmconfig_read_uint32("iperf.port", &server_port);
146 MMOSAL_ASSERT(server_port <= UINT16_MAX);
147 args.server_port = server_port;
148
149 printf("Attempting to connect to %s:%d over TCP\n", args.server_addr,
150 args.server_port == 0 ? MMIPERF_DEFAULT_PORT : args.server_port);
151
152 int amount = IPERF_TIME_AMOUNT;
153 (void)mmconfig_read_int("iperf.amount", &amount);
154 args.amount = amount;
155 if (args.amount < 0)
156 {
157 args.amount *= 100;
158 }
160
162 printf("\nIperf TCP client started, waiting for completion...\n");
163}
164
166static void start_udp_client(void)
167{
168 uint32_t server_port = 0;
170
171 /* Get the Server IP */
173 enum mmipal_status status = mmipal_get_ip_config(&ip_config);
174 if (status == MMIPAL_SUCCESS)
175 {
176 memcpy(args.server_addr, ip_config.gateway_addr, sizeof(ip_config.gateway_addr));
177 }
178 else
179 {
180 printf("Failed to retrieve IP config\n");
181 }
182 /* If iperf.server is set, we use it as an override */
183 (void)mmconfig_read_string("iperf.server", args.server_addr, sizeof(args.server_addr));
184
185 mmconfig_read_uint32("iperf.port", &server_port);
186 MMOSAL_ASSERT(server_port <= UINT16_MAX);
187 args.server_port = server_port;
188
189 printf("Attempting to connect to %s:%d over UDP\n", args.server_addr,
190 args.server_port == 0 ? MMIPERF_DEFAULT_PORT : args.server_port);
191
192 int amount = IPERF_TIME_AMOUNT;
193 (void)mmconfig_read_int("iperf.amount", &amount);
194 args.amount = amount;
195 if (args.amount < 0)
196 {
197 args.amount *= 100;
198 }
200
202 printf("\nIperf UDP client started, waiting for completion...\n");
203}
204
206static void start_tcp_server(void)
207{
209
210 uint32_t local_port = IPERF_SERVER_PORT;
211 mmconfig_read_uint32("iperf.port", &local_port);
212 args.local_port = (uint16_t)local_port;
213
215
216 mmiperf_handle_t iperf_handle = mmiperf_start_tcp_server(&args);
217 if (iperf_handle == NULL)
218 {
219 printf("Failed to get local address\n");
220 return;
221 }
222 printf("\nIperf TCP server started, waiting for client to connect...\n");
223 struct mmipal_ip_config ip_config;
224 enum mmipal_status status;
225 status = mmipal_get_ip_config(&ip_config);
226 if (status == MMIPAL_SUCCESS)
227 {
228 printf("Execute cmd on AP 'iperf -c %s -p %u -i 1' for IPv4\n",
229 ip_config.ip_addr, args.local_port);
230 }
231
232 struct mmipal_ip6_config ip6_config;
233 status = mmipal_get_ip6_config(&ip6_config);
234 if (status == MMIPAL_SUCCESS)
235 {
236 printf("Execute cmd on AP 'iperf -c %s%%wlan0 -p %u -i 1 -V' for IPv6\n",
237 ip6_config.ip6_addr[0], args.local_port);
238 }
239}
240
242static void start_udp_server(void)
243{
245
246 uint32_t local_port = IPERF_SERVER_PORT;
247 mmconfig_read_uint32("iperf.port", &local_port);
248 args.local_port = (uint16_t)local_port;
249
251
252 mmiperf_handle_t iperf_handle = mmiperf_start_udp_server(&args);
253 if (iperf_handle == NULL)
254 {
255 printf("Failed to start iperf server\n");
256 return;
257 }
258
259 printf("\nIperf UDP server started, waiting for client to connect...\n");
260 struct mmipal_ip_config ip_config;
261 enum mmipal_status status;
262 status = mmipal_get_ip_config(&ip_config);
263 if (status == MMIPAL_SUCCESS)
264 {
265 printf("Execute cmd on AP 'iperf -c %s -p %u -i 1 -u -b 20M' for IPv4\n",
266 ip_config.ip_addr, args.local_port);
267 }
268
269 struct mmipal_ip6_config ip6_config;
270 status = mmipal_get_ip6_config(&ip6_config);
271 if (status == MMIPAL_SUCCESS)
272 {
273 printf("Execute cmd on AP 'iperf -c %s%%wlan0 -p %u -i 1 -V -u -b 20M' for IPv6\n",
274 ip6_config.ip6_addr[0], args.local_port);
275 }
276}
277
282void app_init(void)
283{
284 printf("\n\nMorse Iperf Demo (Built " __DATE__ " " __TIME__ ")\n\n");
285
286 /* Initialize and connect to Wi-Fi, blocks till connected */
289
290 enum iperf_type iperf_mode = IPERF_TYPE;
291 char iperf_mode_str[32];
292 if (mmconfig_read_string("iperf.mode", iperf_mode_str, sizeof(iperf_mode_str)) > 0)
293 {
294 if (strncmp(iperf_mode_str, "udp_server", sizeof(iperf_mode_str)) == 0)
295 {
296 iperf_mode = IPERF_UDP_SERVER;
297 }
298 else if (strncmp(iperf_mode_str, "tcp_server", sizeof(iperf_mode_str)) == 0)
299 {
300 iperf_mode = IPERF_TCP_SERVER;
301 }
302 else if (strncmp(iperf_mode_str, "tcp_client", sizeof(iperf_mode_str)) == 0)
303 {
304 iperf_mode = IPERF_TCP_CLIENT;
305 }
306 else if (strncmp(iperf_mode_str, "udp_client", sizeof(iperf_mode_str)) == 0)
307 {
308 iperf_mode = IPERF_UDP_CLIENT;
309 }
310 else
311 {
312 printf("Unsupported iperf mode: %s\n", iperf_mode_str);
313 return;
314 }
315 }
316
317 switch (iperf_mode)
318 {
319 case IPERF_TCP_SERVER:
321 break;
322
323 case IPERF_UDP_SERVER:
325 break;
326
327 case IPERF_UDP_CLIENT:
329 break;
330
331 case IPERF_TCP_CLIENT:
333 break;
334 }
335}
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:100
mmipal_status
Enumeration of status codes returned by MMIPAL functions.
Definition: mmipal.h:37
enum mmipal_status mmipal_get_ip_config(struct mmipal_ip_config *config)
Get the IP configurations.
@ MMIPAL_SUCCESS
Completed successfully.
Definition: mmipal.h:39
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:181
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:33
#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:96
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:68
@ MMIPERF_TCP_DONE_SERVER
The server side test is done.
Definition: mmiperf.h:56
#define MMOSAL_ASSERT(expr)
Assert that the given expression evaluates to true and abort execution if not.
Definition: mmosal.h:927
static void start_tcp_client(void)
Start iperf as a TCP client.
Definition: iperf.c:126
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:166
static void start_tcp_server(void)
Start iperf as a TCP server.
Definition: iperf.c:206
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:242
#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:282
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:128
mmipal_ip_addr_t ip6_addr[MMIPAL_MAX_IPV6_ADDRESSES]
Array of IPv6 addresses.
Definition: mmipal.h:132
IPv4 configuration structure.
Definition: mmipal.h:88
mmipal_ip_addr_t gateway_addr
Gateway address.
Definition: mmipal.h:96
mmipal_ip_addr_t ip_addr
local IP address
Definition: mmipal.h:92
Iperf client arguments data structure.
Definition: mmiperf.h:157
char server_addr[MMIPERF_IPADDR_MAXLEN]
IP address of iperf server to communicate with (as a string).
Definition: mmiperf.h:159
mmiperf_report_fn report_fn
Report callback function to invoke on completion/abort.
Definition: mmiperf.h:173
int32_t amount
If positive specifies how many bytes to transfer; if negative the absolute value specifies the durati...
Definition: mmiperf.h:171
uint16_t server_port
Port on iperf server to communicate with.
Definition: mmiperf.h:161
Report data structure.
Definition: mmiperf.h:100
enum mmiperf_report_type report_type
Type of report.
Definition: mmiperf.h:102
char local_addr[MMIPERF_IPADDR_MAXLEN]
Local address (as string).
Definition: mmiperf.h:104
uint16_t local_port
Local port.
Definition: mmiperf.h:106
uint16_t remote_port
Remote port.
Definition: mmiperf.h:110
uint32_t bandwidth_kbitpsec
Average throughput in kbps.
Definition: mmiperf.h:116
char remote_addr[MMIPERF_IPADDR_MAXLEN]
Remote address (as string).
Definition: mmiperf.h:108
uint64_t bytes_transferred
Number of bytes of data transferred during test.
Definition: mmiperf.h:112
uint32_t duration_ms
Duration of the test in milliseconds.
Definition: mmiperf.h:114
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