1 /*
2 * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "lwip_app_iperf.h"
17 #ifdef LWIP_APP_IPERF
18 #include <unistd.h>
19 #include <lwip/inet.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include "iperf_printf.h"
23 #include "lega_rtos.h"
24
25 #define IPERF_PORT 5001
26 #define IPERF_CLIENT_TIMEOUT_MS 0xFFFFFFFF
27
28 lega_semaphore_t iperf_Semaphore = NULL;
29 volatile IPERF_TCP_SERVER_STATUS iperf_tcp_server_status;
30 volatile IPERF_UDP_SERVER_STATUS iperf_udp_server_status;
31 volatile IPERF_TCP_CLINET_STATUS iperf_tcp_client_status;
32 volatile IPERF_UDP_CLIENT_STATUS iperf_udp_client_status;
33 char iperf_send_buf[SEND_BUFSIZE];
34 struct lwip_iperf_config_t iperf_config;
35 lega_timer_t iperf_output_timer;
36 struct lwip_iperf_outputInfo txperf_outinfo;
37 struct lwip_iperf_outputInfo rxperf_outinfo;
38 struct lwip_iperf_outputInfo utxperf_outinfo;
39 struct lwip_iperf_outputInfo urxperf_outinfo;
40
iperf_value_format(char * format_value,int format_value_len,u64_t value)41 void iperf_value_format(char *format_value, int format_value_len, u64_t value)
42 {
43 u64_t gv = value / (1000000000ULL);
44 u64_t mv = value / (1000000ULL);
45 u64_t kv = value / (1000ULL);
46
47 lega_rtos_declare_critical();
48 lega_rtos_enter_critical();
49
50 if (gv == 0) {
51 if (mv == 0) {
52 if (kv == 0) {
53 snprintf(format_value, format_value_len, "%llu", value);
54 } else {
55 snprintf(format_value, format_value_len, "%llu.%02uK", kv, (unsigned int)(value % 1000) / 10);
56 }
57 } else {
58 snprintf(format_value, format_value_len, "%llu.%02uM", mv, (unsigned int)(value % 1000000) / 10000);
59 }
60 } else {
61 snprintf(format_value, format_value_len, "%llu.%02uG", gv, (unsigned int)(value % 1000000000) / 10000000);
62 }
63
64 lega_rtos_exit_critical();
65 }
66
do_iperf_terminate_timer(char * mode,struct lwip_iperf_outputInfo * outputInfo)67 void do_iperf_terminate_timer(char *mode, struct lwip_iperf_outputInfo *outputInfo)
68 {
69 u64_t bytes = outputInfo->currentByte;
70 u64_t packets = outputInfo->currentPacketNum;
71 char byteFormat[24] = {0};
72 char bitFormat[24] = {0};
73 lega_rtos_stop_timer(&iperf_output_timer);
74 iperf_value_format(byteFormat, sizeof(byteFormat), bytes);
75 iperf_value_format(bitFormat, sizeof(bitFormat), (bytes * (8ULL)) / ((u64_t)outputInfo->seconds));
76 iperf_printf("%s:total %d sec %llu packets %s Bytes %s bits/sec\r\n", mode, outputInfo->seconds, packets,
77 byteFormat, bitFormat);
78 memset(outputInfo, 0, sizeof(struct lwip_iperf_outputInfo));
79 }
do_iperf_terminate(char * mode,struct lwip_iperf_outputInfo * outputInfo,discon_handle_t discon)80 void do_iperf_terminate(char *mode, struct lwip_iperf_outputInfo *outputInfo, discon_handle_t discon)
81 {
82 do_iperf_terminate_timer(mode, outputInfo);
83 discon();
84 }
85
lega_wifi_iperf_usage()86 static void lega_wifi_iperf_usage()
87 {
88 iperf_printf("usage: iperf -c host [-p port] [-u] [-t]\r\n\
89 aiperf -s [-p port] [-u] [-t]\r\n\
90 -c host :run as iperf client connect to host\r\n\
91 -s :run as iperf server\r\n\
92 -p port :client connect to/server port default 5001\r\n\
93 -u :use udp do iperf client/server\r\n\
94 If -u not enable, use tcp default\r\n\
95 -t :terminate iperf client/server/all\r\n\
96 -d :tx packets delay time(ms) default 10\r\n");
97 }
lega_wifi_iperf(int argc,char ** argv)98 void lega_wifi_iperf(int argc, char **argv)
99 {
100 int c = 0;
101 struct lwip_iperf_config_t temp_config = {0};
102
103 temp_config.port = IPERF_PORT;
104 temp_config.tx_delay_ms = 2;
105
106 for (c = 1; c < argc; c++) {
107 if (strcmp(argv[c], "-c") == 0) {
108 temp_config.mode = IPERF_MODE_CLIENT;
109 if (inet_aton(argv[++c], &(temp_config.ipaddr)) == 0) {
110 goto IPERF_PARSE_FAIL;
111 }
112 } else if (strcmp(argv[c], "-p") == 0) {
113 temp_config.port = strtoul(argv[++c], NULL, 10);
114 if (temp_config.port <= 0 || temp_config.port > 65536) {
115 goto IPERF_PARSE_FAIL;
116 }
117 } else if (strcmp(argv[c], "-s") == 0) {
118 temp_config.mode = IPERF_MODE_SERVER;
119 } else if (strcmp(argv[c], "-u") == 0) {
120 temp_config.protocol = IPERF_PROTOCOL_UDP;
121 } else if (strcmp(argv[c], "-t") == 0) {
122 temp_config.termFlag = 1;
123 } else if (strcmp(argv[c], "-d") == 0) {
124 temp_config.tx_delay_ms = atoi(argv[c + 1]);
125 c++;
126 } else {
127 goto IPERF_PARSE_FAIL;
128 }
129 }
130
131 if ((temp_config.termFlag == 0) && (iperf_config.termFlag == 0)) {
132 iperf_printf("please close your last iperf connection firstly!\n");
133 goto IPERF_PARSE_FAIL;
134 } else if ((temp_config.termFlag == 1) && (iperf_config.termFlag == 0)) {
135 iperf_config.termFlag = 1;
136 } else {
137 memcpy(&iperf_config, &temp_config, sizeof(iperf_config));
138 }
139
140 if ((iperf_config.mode == IPERF_MODE_UNINIT) && (iperf_config.termFlag != 1)) {
141 goto IPERF_PARSE_FAIL;
142 }
143 if ((iperf_config.mode == IPERF_MODE_CLIENT) && (iperf_Semaphore != NULL)) {
144 if (lega_rtos_set_semaphore(&iperf_Semaphore) == kNoErr) {
145 // iperf_printf("Begin to run iperf client:\n");
146 } else {
147 iperf_printf("Run iperf client fail for semaphore error\n");
148 }
149 return;
150 }
151 if (iperf_config.protocol == IPERF_PROTOCOL_TCP) {
152 if (iperf_config.mode == IPERF_MODE_SERVER) {
153 // tcp server
154 if (iperf_config.termFlag == 1) {
155 // iperf_printf("Terminate iperf tcp server");
156 // terminate_rxperf();
157 do_iperf_terminate("tcp server", &rxperf_outinfo, clear_rxperf);
158 } else {
159 if (iperf_tcp_server_status <= IPERF_TCP_SERVER_INIT) {
160 rxperf_init();
161 start_rxperf_application(iperf_config.port);
162 } else {
163 iperf_printf("iperf tcp server already running status:%d,please terminate it before run again!\r\n",
164 iperf_tcp_server_status);
165 }
166 }
167 }
168 } else {
169 if (iperf_config.mode == IPERF_MODE_SERVER) {
170 // udp server
171 if (iperf_config.termFlag == 1) {
172
173 do_iperf_terminate("udp server", &urxperf_outinfo, clear_urxperf);
174 } else {
175 if (iperf_udp_server_status <= IPERF_UDP_SERVER_INIT) {
176 iperf_udp_server_status = IPERF_UDP_SERVER_INIT;
177 urxperf_init();
178 start_urxperf_application(iperf_config.port);
179 } else {
180 iperf_printf("iperf udp server already running status:%d,please terminate it before run again!\r\n",
181 iperf_udp_server_status);
182 }
183 }
184 }
185 }
186 return;
187 IPERF_PARSE_FAIL:
188 lega_wifi_iperf_usage();
189 return;
190 }
191
do_iperf_output(char * mode,struct lwip_iperf_outputInfo * outputInfo)192 void do_iperf_output(char *mode, struct lwip_iperf_outputInfo *outputInfo)
193 {
194 u64_t bytes = outputInfo->currentByte - outputInfo->lastByte;
195 u64_t packets = outputInfo->currentPacketNum - outputInfo->lastPacketNum;
196 char byteFormat[24] = {0};
197 char bitFormat[24] = {0};
198 iperf_value_format(byteFormat, sizeof(byteFormat), bytes);
199 iperf_value_format(bitFormat, sizeof(bitFormat), bytes * (8ULL));
200 outputInfo->seconds++;
201 if (bytes != 0) {
202 iperf_printf("%s:%d-%d sec %llu packets %s Bytes %s bits/sec\r\n", mode, outputInfo->seconds - 1,
203 outputInfo->seconds, packets, byteFormat, bitFormat);
204 }
205 outputInfo->lastByte = outputInfo->currentByte;
206 outputInfo->lastPacketNum = outputInfo->currentPacketNum;
207 }
208
iperf_output(void * args)209 void iperf_output(void *args)
210 {
211 printf("\nlalala %s\n", __func__);
212 if (iperf_tcp_client_status == IPERF_TCP_CLIENT_TXRUNNING) {
213 do_iperf_output("tcp client", &txperf_outinfo);
214 }
215 if (iperf_tcp_server_status == IPERF_TCP_SERVER_RXRUNNING) {
216 do_iperf_output("tcp server", &rxperf_outinfo);
217 }
218 if (iperf_udp_client_status == IPERF_UDP_CLIENT_TXRUNNING) {
219 do_iperf_output("udp client", &utxperf_outinfo);
220 }
221 if (iperf_udp_server_status == IPERF_UDP_SERVER_RXRUNNING) {
222 do_iperf_output("udp server", &urxperf_outinfo);
223 }
224
225 }
lega_wifi_iperf_client_start()226 void lega_wifi_iperf_client_start()
227 {
228 int count = 0;
229 if (lega_rtos_init_timer(&iperf_output_timer, IPERF_OUTPUT_INTERVIEW * 1000, iperf_output, NULL) != kNoErr) {
230 iperf_printf("iperf timer fail!\r\n");
231 }
232 for (;;) {
233 if (lega_rtos_get_semaphore(&iperf_Semaphore, IPERF_CLIENT_TIMEOUT_MS) == kNoErr) {
234 // AT command set lwip_iperf_config over and begin to run
235
236 if (iperf_config.mode != IPERF_MODE_CLIENT) {
237 continue;
238 }
239 if (iperf_config.protocol == IPERF_PROTOCOL_TCP) {
240 if (iperf_config.termFlag == 1) {
241 do_iperf_terminate("tcp client", &txperf_outinfo, disconnect_txperf);
242 continue;
243 }
244
245 if (iperf_tcp_client_status != IPERF_TCP_CLIENT_TXRUNNING) {
246 if (iperf_tcp_client_status >= IPERF_TCP_CLIENT_CONNECTING) {
247 iperf_printf("iperf tcp client already running, please terminate it before run again!\r\n");
248 continue;
249 }
250 txperf_init();
251 if (start_txperf_application(&(iperf_config.ipaddr), iperf_config.port) != 0) {
252 iperf_printf("iperf tcp connect fail!\n");
253 continue;
254 }
255 count = 0;
256 if (iperf_tcp_client_status == IPERF_TCP_CLIENT_TXRUNNING) {
257 break;
258 }
259 while (iperf_tcp_client_status < IPERF_TCP_CLIENT_STARTING) { //wait for tcp connect
260 lega_rtos_delay_milliseconds(100);
261 if (++count > 100) {
262 iperf_printf("iperf connect to %s:%d fail!\n", ip4addr_ntoa((const ip4_addr_t *) & (iperf_config.ipaddr)),
263 iperf_config.port);
264 break;
265 }
266 }
267 if (count > 100) {
268 continue;
269 }
270 iperf_tcp_client_status = IPERF_TCP_CLIENT_TXRUNNING;
271 }
272
273 transfer_txperf_data();
274 } else if (iperf_config.protocol == IPERF_PROTOCOL_UDP) {
275 if (iperf_config.termFlag == 1) {
276 do_iperf_terminate("udp client", &utxperf_outinfo, disconnect_utxperf);
277 continue;
278 }
279 if (iperf_udp_client_status >= IPERF_UDP_CLIENT_START) {
280 iperf_printf("iperf udp client already running status:%d,please terminate it before run again!\r\n",
281 iperf_udp_client_status);
282 continue;
283 }
284 utxperf_init();
285 if (start_utxperf_application(&(iperf_config.ipaddr), iperf_config.port) != 0) {
286 continue;
287 }
288 while (transfer_utxperf_data() != -2) {
289 lega_rtos_delay_milliseconds(iperf_config.tx_delay_ms);
290 if (iperf_config.termFlag) {
291 break;
292 }
293 }
294 if (iperf_config.termFlag) {
295 continue;
296 }
297 }
298 }
299 }
300 }
301
302 lega_thread_t iper_handler = NULL;
303 #define IPERF_CLIENT_THREAD_NAME "iperf-client"
304 #define IPERF_CLIENT_PRIORITY (28)
305 #define IPERF_CLIENT_STACK_SIZE 4096
lega_wifi_iperf_init(void)306 void lega_wifi_iperf_init(void)
307 {
308 int i = 0;
309
310 rxperf_init();
311
312 urxperf_init();
313 utxperf_init();
314
315 if (iperf_Semaphore == NULL) {
316 lega_rtos_init_semaphore(&iperf_Semaphore, 0);
317 }
318
319 /* initialize data buffer being sent */
320 for (i = 0; i < SEND_BUFSIZE; i++) {
321 iperf_send_buf[i] = (i % 10) + '0';
322 }
323
324 memset(&iperf_config, 0, sizeof(iperf_config));
325 iperf_config.termFlag = 1;
326
327 lega_rtos_create_thread(&iper_handler, IPERF_CLIENT_PRIORITY, IPERF_CLIENT_THREAD_NAME, lega_wifi_iperf_client_start,
328 IPERF_CLIENT_STACK_SIZE, 0);
329 }
330 #endif
331