diff --git a/components/app_console/app_console.c b/components/app_console/app_console.c index b3c7661..4fd7f63 100644 --- a/components/app_console/app_console.c +++ b/components/app_console/app_console.c @@ -27,12 +27,13 @@ static int cmd_iperf(int argc, char **argv) { if (strcmp(argv[1], "start") == 0) { iperf_cfg_t cfg = { .time = 0 }; // Infinite iperf_start(&cfg); - printf("IPERF_STARTED\n"); + // iperf_start already logs "IPERF_STARTED" via printf in iperf.c, + // but keeping it here is fine/redundant. + // To be safe and clean, we rely on iperf.c's output or just return success. return 0; } else if (strcmp(argv[1], "stop") == 0) { iperf_stop(); - printf("IPERF_STOPPED\n"); return 0; } else if (strcmp(argv[1], "pps") == 0) { @@ -47,12 +48,12 @@ static int cmd_iperf(int argc, char **argv) { return 1; } iperf_set_pps((uint32_t)pps); - printf("IPERF_PPS_UPDATED: %d\n", pps); + // iperf_set_pps prints "IPERF_PPS_UPDATED: ..." return 0; } else if (strcmp(argv[1], "status") == 0) { - uint32_t pps = iperf_get_pps(); - printf("IPERF_STATUS: PPS=%lu\n", (unsigned long)pps); + // [FIXED] Use the new API to print detailed stats + iperf_print_status(); return 0; } diff --git a/components/iperf/iperf.c b/components/iperf/iperf.c index 31abc82..76ccfd6 100644 --- a/components/iperf/iperf.c +++ b/components/iperf/iperf.c @@ -6,6 +6,7 @@ #include #include #include +#include // Added for clock_gettime #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" @@ -83,6 +84,7 @@ static void iperf_network_event_handler(void* arg, esp_event_base_t event_base, static bool iperf_wait_for_ip(void) { if (!s_iperf_event_group) s_iperf_event_group = xEventGroupCreate(); + // Check if we already have IP esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); if (netif) { esp_netif_ip_info_t ip_info; @@ -94,11 +96,18 @@ static bool iperf_wait_for_ip(void) { ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &iperf_network_event_handler, NULL, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &iperf_network_event_handler, NULL, &instance_got_ip)); + ESP_LOGI(TAG, "Waiting for IP..."); EventBits_t bits = xEventGroupWaitBits(s_iperf_event_group, IPERF_IP_READY_BIT | IPERF_STOP_REQ_BIT, pdFALSE, pdFALSE, portMAX_DELAY); esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id); esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip); - return !(bits & IPERF_STOP_REQ_BIT); + + if (bits & IPERF_STOP_REQ_BIT) { + ESP_LOGW(TAG, "Stop requested while waiting for IP"); + return false; + } + ESP_LOGI(TAG, "IP Ready. Starting traffic."); + return true; } static void trim_whitespace(char *str) { @@ -169,25 +178,32 @@ static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) { addr.sin_port = htons(ctrl->cfg.dport > 0 ? ctrl->cfg.dport : 5001); addr.sin_addr.s_addr = ctrl->cfg.dip; + // Log destination for debugging + char ip_str[32]; + inet_ntop(AF_INET, &addr.sin_addr, ip_str, sizeof(ip_str)); + ESP_LOGI(TAG, "Client sending to %s:%d", ip_str, ntohs(addr.sin_port)); + int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sockfd < 0) { status_led_set_state(LED_STATE_FAILED); + ESP_LOGE(TAG, "Socket creation failed: %d", errno); return ESP_FAIL; } - // Indicate Running status_led_set_state(LED_STATE_TRANSMITTING_SLOW); s_stats.running = true; printf("IPERF_STARTED\n"); + // Fix: Ensure we have a default time if 0 (infinite) int64_t next_send_time = esp_timer_get_time(); int64_t end_time = (ctrl->cfg.time == 0) ? INT64_MAX : esp_timer_get_time() + (int64_t)ctrl->cfg.time * 1000000LL; int64_t last_rate_check = esp_timer_get_time(); uint32_t packets_since_check = 0; - int32_t packet_id = 0; + struct timespec ts; + while (!ctrl->finish && esp_timer_get_time() < end_time) { int64_t now = esp_timer_get_time(); int64_t wait = next_send_time - now; @@ -198,22 +214,21 @@ static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) { for (int k = 0; k < ctrl->cfg.burst_count; k++) { udp_datagram *hdr = (udp_datagram *)ctrl->buffer; - // 1. Sequence ID hdr->id = htonl(packet_id++); - // 2. Timestamp - struct timeval tv; - gettimeofday(&tv, NULL); - hdr->tv_sec = htonl(tv.tv_sec); - hdr->tv_usec = htonl(tv.tv_usec); + // CHANGED: gettimeofday -> clock_gettime + clock_gettime(CLOCK_REALTIME, &ts); + hdr->tv_sec = htonl(ts.tv_sec); + hdr->tv_usec = htonl(ts.tv_nsec / 1000); // Nanoseconds to Microseconds - // 3. ID2 (Required for some iperf parsers) hdr->id2 = hdr->id; - if (sendto(sockfd, ctrl->buffer, ctrl->cfg.send_len, 0, (struct sockaddr *)&addr, sizeof(addr)) > 0) { + int sent = sendto(sockfd, ctrl->buffer, ctrl->cfg.send_len, 0, (struct sockaddr *)&addr, sizeof(addr)); + + if (sent > 0) { packets_since_check++; } else { - if (errno != 12) { // Not ENOMEM + if (errno != 12) { ESP_LOGE(TAG, "Send failed: %d", errno); status_led_set_state(LED_STATE_FAILED); goto exit; @@ -222,15 +237,12 @@ static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) { } } - // --- Stats & LED Update --- now = esp_timer_get_time(); if (now - last_rate_check > RATE_CHECK_INTERVAL_US) { uint32_t interval_us = (uint32_t)(now - last_rate_check); - if (interval_us > 0) { s_stats.actual_pps = (uint32_t)((uint64_t)packets_since_check * 1000000 / interval_us); } - uint32_t config_pps = iperf_get_pps(); uint32_t threshold = (config_pps * 3) / 4; led_state_t target = (s_stats.actual_pps >= threshold) ? LED_STATE_TRANSMITTING : LED_STATE_TRANSMITTING_SLOW; @@ -239,27 +251,22 @@ static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) { last_rate_check = now; packets_since_check = 0; } - next_send_time += ctrl->cfg.pacing_period_us; } exit: - // --- SEND TERMINATION PACKETS --- - // Send a negative sequence ID to tell the server the session is done. - // This allows immediate restart without waiting for server timeout. + // Termination Packets { udp_datagram *hdr = (udp_datagram *)ctrl->buffer; - int32_t final_id = -(packet_id); // Negative ID signals End of Stream - + int32_t final_id = -packet_id; hdr->id = htonl(final_id); hdr->id2 = hdr->id; - struct timeval tv; - gettimeofday(&tv, NULL); - hdr->tv_sec = htonl(tv.tv_sec); - hdr->tv_usec = htonl(tv.tv_usec); + // CHANGED: gettimeofday -> clock_gettime + clock_gettime(CLOCK_REALTIME, &ts); + hdr->tv_sec = htonl(ts.tv_sec); + hdr->tv_usec = htonl(ts.tv_nsec / 1000); - // Send a burst of death packets to ensure delivery over UDP for(int i=0; i<10; i++) { sendto(sockfd, ctrl->buffer, ctrl->cfg.send_len, 0, (struct sockaddr *)&addr, sizeof(addr)); vTaskDelay(pdMS_TO_TICKS(2)); @@ -268,8 +275,6 @@ exit: } close(sockfd); - - // Cleanup State s_stats.running = false; s_stats.actual_pps = 0; status_led_set_state(LED_STATE_CONNECTED); @@ -279,11 +284,9 @@ exit: static void iperf_task(void *arg) { iperf_ctrl_t *ctrl = (iperf_ctrl_t *)arg; - if (ctrl->cfg.flag & IPERF_FLAG_UDP && ctrl->cfg.flag & IPERF_FLAG_CLIENT) { iperf_start_udp_client(ctrl); } - free(ctrl->buffer); s_iperf_task_handle = NULL; vTaskDelete(NULL);