udp with trip-times

This commit is contained in:
Robert McMahon 2025-12-20 18:35:06 -08:00
parent 969abb5ae4
commit 6c214e8e92
1 changed files with 59 additions and 45 deletions

View File

@ -30,7 +30,6 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file iperf.c
* @brief ESP32 iPerf Traffic Generator (UDP Client Only)
@ -42,8 +41,8 @@
* - Non-Volatile Storage (NVS) for persistent configuration.
* - Detailed error tracking (ENOMEM vs Route errors).
* - GPS Timestamp integration for status reporting.
* @brief ESP32 iPerf Traffic Generator (UDP Client Only) with Trip-Time Support
*/
#include <stdio.h>
#include <string.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_got_ip;
// --- Packet Structures ---
typedef struct {
// --- Packet Structures & Constants (Compatible with payloads.h) ---
#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;
uint32_t tv_sec;
uint32_t tv_usec;
int32_t id2;
} udp_datagram;
typedef struct {
int32_t flags;
int32_t numThreads;
int32_t mPort;
int32_t mBufLen;
int32_t mWinBand;
int32_t mAmount;
} client_hdr_v1;
uint16_t flags;
uint32_t start_tv_sec;
uint32_t start_tv_usec;
};
// --- Helper: Defaults ---
static void set_defaults(iperf_cfg_t *cfg) {
@ -326,13 +324,11 @@ void iperf_print_status(void) {
(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);
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",
(unsigned long)s_stats.err_mem,
(unsigned long)s_stats.err_route,
(unsigned long)s_stats.err_other);
}
}
// --- 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';
}
static void iperf_generate_client_hdr(iperf_cfg_t *cfg, client_hdr_v1 *hdr) {
memset(hdr, 0, sizeof(client_hdr_v1));
hdr->flags = htonl(0x08000000); // HEADER_SEQNO64B
static void iperf_generate_headers(iperf_cfg_t *cfg, uint8_t *buffer, bool gps_synced, struct timespec *start_time) {
struct udp_datagram *udp_hdr = (struct udp_datagram *)buffer;
// 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) {
@ -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) {
xEventGroupClearBits(s_iperf_event_group, IPERF_IP_READY_BIT);
// --- ADDED: Set Yellow on Disconnect ---
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(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);
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) {
// Note: status_led_set_state(LED_STATE_WAITING) happens inside if needed
if (!iperf_wait_for_ip()) return ESP_OK;
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);
if (sockfd < 0) {
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;
}
// --- Set Purple Slow Pulse (Starting) ---
status_led_set_state(LED_STATE_TRANSMITTING_SLOW);
udp_datagram *udp_hdr = (udp_datagram *)ctrl->buffer;
client_hdr_v1 *client_hdr = (client_hdr_v1 *)(ctrl->buffer + sizeof(udp_datagram));
iperf_generate_client_hdr(&ctrl->cfg, client_hdr);
// --- CHECK GPS SYNC ---
gps_timestamp_t gps = gps_get_timestamp();
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.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++) {
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->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;
struct udp_datagram *udp_hdr = (struct udp_datagram *)ctrl->buffer;
udp_hdr->id = htonl((uint32_t)(final_id & 0xFFFFFFFF));
udp_hdr->id2 = htonl((uint32_t)((final_id >> 32) & 0xFFFFFFFF));
clock_gettime(CLOCK_REALTIME, &ts);