udp with trip-times
This commit is contained in:
parent
969abb5ae4
commit
6c214e8e92
|
|
@ -30,8 +30,7 @@
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
/**
|
|
||||||
* @file iperf.c
|
* @file iperf.c
|
||||||
* @brief ESP32 iPerf Traffic Generator (UDP Client Only)
|
* @brief ESP32 iPerf Traffic Generator (UDP Client Only)
|
||||||
*
|
*
|
||||||
|
|
@ -42,8 +41,8 @@
|
||||||
* - Non-Volatile Storage (NVS) for persistent configuration.
|
* - Non-Volatile Storage (NVS) for persistent configuration.
|
||||||
* - Detailed error tracking (ENOMEM vs Route errors).
|
* - Detailed error tracking (ENOMEM vs Route errors).
|
||||||
* - GPS Timestamp integration for status reporting.
|
* - GPS Timestamp integration for status reporting.
|
||||||
|
* @brief ESP32 iPerf Traffic Generator (UDP Client Only) with Trip-Time Support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
@ -130,23 +129,22 @@ static uint32_t s_edge_stalled = 0;
|
||||||
static esp_event_handler_instance_t instance_any_id;
|
static esp_event_handler_instance_t instance_any_id;
|
||||||
static esp_event_handler_instance_t instance_got_ip;
|
static esp_event_handler_instance_t instance_got_ip;
|
||||||
|
|
||||||
// --- Packet Structures ---
|
// --- Packet Structures & Constants (Compatible with payloads.h) ---
|
||||||
typedef struct {
|
|
||||||
|
#define HEADER_EXTEND 0x80000000
|
||||||
|
#define HEADER_SEQNO64B 0x08000000
|
||||||
|
#define HEADER_TRIPTIME 0x00020000 // Use the small trip time flag
|
||||||
|
|
||||||
|
// UDP Datagram Header
|
||||||
|
struct udp_datagram {
|
||||||
int32_t id;
|
int32_t id;
|
||||||
uint32_t tv_sec;
|
uint32_t tv_sec;
|
||||||
uint32_t tv_usec;
|
uint32_t tv_usec;
|
||||||
int32_t id2;
|
int32_t id2;
|
||||||
} udp_datagram;
|
uint16_t flags;
|
||||||
|
uint32_t start_tv_sec;
|
||||||
typedef struct {
|
uint32_t start_tv_usec;
|
||||||
int32_t flags;
|
};
|
||||||
int32_t numThreads;
|
|
||||||
int32_t mPort;
|
|
||||||
int32_t mBufLen;
|
|
||||||
int32_t mWinBand;
|
|
||||||
int32_t mAmount;
|
|
||||||
} client_hdr_v1;
|
|
||||||
|
|
||||||
|
|
||||||
// --- Helper: Defaults ---
|
// --- Helper: Defaults ---
|
||||||
static void set_defaults(iperf_cfg_t *cfg) {
|
static void set_defaults(iperf_cfg_t *cfg) {
|
||||||
|
|
@ -326,12 +324,10 @@ void iperf_print_status(void) {
|
||||||
(double)s_time_slow_us/1000000.0, pct_slow, (unsigned long)s_edge_slow,
|
(double)s_time_slow_us/1000000.0, pct_slow, (unsigned long)s_edge_slow,
|
||||||
(double)s_time_stalled_us/1000000.0, pct_stalled, (unsigned long)s_edge_stalled);
|
(double)s_time_stalled_us/1000000.0, pct_stalled, (unsigned long)s_edge_stalled);
|
||||||
|
|
||||||
if (s_stats.err_mem > 0 || s_stats.err_route > 0 || s_stats.err_other > 0) {
|
|
||||||
printf("ERRORS: ENOMEM=%lu, EHOST=%lu, OTHER=%lu\n",
|
printf("ERRORS: ENOMEM=%lu, EHOST=%lu, OTHER=%lu\n",
|
||||||
(unsigned long)s_stats.err_mem,
|
(unsigned long)s_stats.err_mem,
|
||||||
(unsigned long)s_stats.err_route,
|
(unsigned long)s_stats.err_route,
|
||||||
(unsigned long)s_stats.err_other);
|
(unsigned long)s_stats.err_other);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Core Logic ---
|
// --- Core Logic ---
|
||||||
|
|
@ -340,9 +336,17 @@ static void iperf_pattern(uint8_t *buf, uint32_t len) {
|
||||||
for (uint32_t i = 0; i < len; i++) buf[i] = (i % 10) + '0';
|
for (uint32_t i = 0; i < len; i++) buf[i] = (i % 10) + '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iperf_generate_client_hdr(iperf_cfg_t *cfg, client_hdr_v1 *hdr) {
|
static void iperf_generate_headers(iperf_cfg_t *cfg, uint8_t *buffer, bool gps_synced, struct timespec *start_time) {
|
||||||
memset(hdr, 0, sizeof(client_hdr_v1));
|
struct udp_datagram *udp_hdr = (struct udp_datagram *)buffer;
|
||||||
hdr->flags = htonl(0x08000000); // HEADER_SEQNO64B
|
// Clear Header Area
|
||||||
|
memset(udp_hdr, 0, sizeof(struct udp_datagram));
|
||||||
|
if (gps_synced) {
|
||||||
|
udp_hdr->flags = htonl(HEADER_EXTEND | HEADER_SEQNO64B | HEADER_TRIPTIME);
|
||||||
|
udp_hdr->start_tv_sec = htonl(start_time->tv_sec);
|
||||||
|
udp_hdr->start_tv_usec = htonl(start_time->tv_nsec / 1000);
|
||||||
|
} else {
|
||||||
|
udp_hdr->flags = htonl(HEADER_EXTEND | HEADER_SEQNO64B);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iperf_network_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
static void iperf_network_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
||||||
|
|
@ -352,8 +356,6 @@ static void iperf_network_event_handler(void* arg, esp_event_base_t event_base,
|
||||||
}
|
}
|
||||||
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
xEventGroupClearBits(s_iperf_event_group, IPERF_IP_READY_BIT);
|
xEventGroupClearBits(s_iperf_event_group, IPERF_IP_READY_BIT);
|
||||||
|
|
||||||
// --- ADDED: Set Yellow on Disconnect ---
|
|
||||||
status_led_set_state(LED_STATE_NO_CONFIG);
|
status_led_set_state(LED_STATE_NO_CONFIG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -370,7 +372,6 @@ 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(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_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &iperf_network_event_handler, NULL, &instance_got_ip));
|
||||||
|
|
||||||
// --- ADDED: Set Blue Blink while waiting ---
|
|
||||||
status_led_set_state(LED_STATE_WAITING);
|
status_led_set_state(LED_STATE_WAITING);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Waiting for IP...");
|
ESP_LOGI(TAG, "Waiting for IP...");
|
||||||
|
|
@ -384,7 +385,6 @@ static bool iperf_wait_for_ip(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) {
|
static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) {
|
||||||
// Note: status_led_set_state(LED_STATE_WAITING) happens inside if needed
|
|
||||||
if (!iperf_wait_for_ip()) return ESP_OK;
|
if (!iperf_wait_for_ip()) return ESP_OK;
|
||||||
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
|
@ -395,16 +395,28 @@ static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) {
|
||||||
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
ESP_LOGE(TAG, "Socket failed: %d", errno);
|
ESP_LOGE(TAG, "Socket failed: %d", errno);
|
||||||
status_led_set_state(LED_STATE_FAILED); // Red Blink on Error
|
status_led_set_state(LED_STATE_FAILED);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Set Purple Slow Pulse (Starting) ---
|
|
||||||
status_led_set_state(LED_STATE_TRANSMITTING_SLOW);
|
status_led_set_state(LED_STATE_TRANSMITTING_SLOW);
|
||||||
|
|
||||||
udp_datagram *udp_hdr = (udp_datagram *)ctrl->buffer;
|
// --- CHECK GPS SYNC ---
|
||||||
client_hdr_v1 *client_hdr = (client_hdr_v1 *)(ctrl->buffer + sizeof(udp_datagram));
|
gps_timestamp_t gps = gps_get_timestamp();
|
||||||
iperf_generate_client_hdr(&ctrl->cfg, client_hdr);
|
bool gps_synced = gps.synced;
|
||||||
|
struct timespec start_ts = {0};
|
||||||
|
|
||||||
|
if (gps_synced) {
|
||||||
|
ESP_LOGI(TAG, "GPS Synced. Enabling Trip-Times (OWD).");
|
||||||
|
// Capture START TIME for session
|
||||||
|
clock_gettime(CLOCK_REALTIME, &start_ts);
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "GPS NOT Synced. Trip-Times disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GENERATE HEADERS ---
|
||||||
|
// We pass the start_ts so it can be written into the start_fq header
|
||||||
|
iperf_generate_headers(&ctrl->cfg, ctrl->buffer, gps_synced, &start_ts);
|
||||||
|
|
||||||
s_stats.running = true;
|
s_stats.running = true;
|
||||||
s_stats.err_mem = 0; s_stats.err_route = 0; s_stats.err_other = 0;
|
s_stats.err_mem = 0; s_stats.err_route = 0; s_stats.err_other = 0;
|
||||||
|
|
@ -439,6 +451,7 @@ static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) {
|
||||||
for (int k = 0; k < ctrl->cfg.burst_count; k++) {
|
for (int k = 0; k < ctrl->cfg.burst_count; k++) {
|
||||||
int64_t current_id = packet_id++;
|
int64_t current_id = packet_id++;
|
||||||
|
|
||||||
|
struct udp_datagram *udp_hdr = (struct udp_datagram *)ctrl->buffer;
|
||||||
udp_hdr->id = htonl((uint32_t)(current_id & 0xFFFFFFFF));
|
udp_hdr->id = htonl((uint32_t)(current_id & 0xFFFFFFFF));
|
||||||
udp_hdr->id2 = htonl((uint32_t)((current_id >> 32) & 0xFFFFFFFF));
|
udp_hdr->id2 = htonl((uint32_t)((current_id >> 32) & 0xFFFFFFFF));
|
||||||
|
|
||||||
|
|
@ -503,6 +516,7 @@ static esp_err_t iperf_start_udp_client(iperf_ctrl_t *ctrl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t final_id = -packet_id;
|
int64_t final_id = -packet_id;
|
||||||
|
struct udp_datagram *udp_hdr = (struct udp_datagram *)ctrl->buffer;
|
||||||
udp_hdr->id = htonl((uint32_t)(final_id & 0xFFFFFFFF));
|
udp_hdr->id = htonl((uint32_t)(final_id & 0xFFFFFFFF));
|
||||||
udp_hdr->id2 = htonl((uint32_t)((final_id >> 32) & 0xFFFFFFFF));
|
udp_hdr->id2 = htonl((uint32_t)((final_id >> 32) & 0xFFFFFFFF));
|
||||||
clock_gettime(CLOCK_REALTIME, &ts);
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue