From fe6aa9663d4cdabdc6e71db6068f8cd9e3739ffe Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 19 May 2026 13:14:48 +0530 Subject: feat: WiFi beacon price discovery via Vendor IE (two-board verified) Price discovery allows TollGate ESP32 boards to advertise their per-step price via WiFi Vendor-Specific Information Elements (OUI 0xC0FFEE) in beacon and probe response frames. Nearby boards passively scan and build a market view of competing TollGates without requiring internet access. Features: - beacon_price.c/h: 26-byte packed Vendor IE payload (price, step, metric, mint_hash, geohash, npub_hash), injected via esp_wifi_set_vendor_ie() - market.c/h: Passive WiFi scan receiver, vendor IE callback parsing, BSSID-correlated market entries, effective price ranking - GET /market API endpoint: JSON market snapshot with discovered entries - AP-only services: beacon + market + API start on WIFI_EVENT_AP_START, independent of STA connectivity - STA reconnect fix: 2s delay between retries creates scan windows; s_sta_connecting guard prevents double-connect - write-config-ap-only-a/b Makefile targets for STA-less testing - market_tick() in main loop, client price comparison logging Hardware verified: both boards discover each other via Vendor IE beacons. Board A sees TollGate-C0E9CA (RSSI=-30), Board B sees TollGate-B96D80 (RSSI=-25). test-market.mjs: 9/9, test-price-discovery.mjs: 7/7 per board. Unit tests: 45 new assertions across test_beacon_price (28) and test_market (17). All 15 test suites pass. ESP-IDF build clean for ESP32-S3. --- tests/unit/stubs/esp_wifi.h | 64 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'tests/unit/stubs') diff --git a/tests/unit/stubs/esp_wifi.h b/tests/unit/stubs/esp_wifi.h index 6aa5787..5eb14bf 100644 --- a/tests/unit/stubs/esp_wifi.h +++ b/tests/unit/stubs/esp_wifi.h @@ -2,6 +2,7 @@ #define STUBS_ESP_WIFI_H #include +#include #include #include "esp_err.h" @@ -37,4 +38,67 @@ static inline esp_err_t esp_wifi_set_config(int ifx, const wifi_config_t *cfg) { static inline esp_err_t esp_wifi_set_mode(uint8_t mode) { (void)mode; return ESP_OK; } static inline esp_err_t esp_wifi_start(void) { return ESP_OK; } +#define WIFI_VENDOR_IE_ELEMENT_ID 0xDD + +typedef enum { + WIFI_VND_IE_TYPE_BEACON, + WIFI_VND_IE_TYPE_PROBE_REQ, + WIFI_VND_IE_TYPE_PROBE_RESP, + WIFI_VND_IE_TYPE_ASSOC_REQ, + WIFI_VND_IE_TYPE_ASSOC_RESP, +} wifi_vendor_ie_type_t; + +typedef enum { + WIFI_VND_IE_ID_0, + WIFI_VND_IE_ID_1, +} wifi_vendor_ie_id_t; + +typedef struct { + uint8_t element_id; + uint8_t length; + uint8_t vendor_oui[3]; + uint8_t vendor_oui_type; + uint8_t payload[0]; +} vendor_ie_data_t; + +typedef void (*esp_vendor_ie_cb_t)(void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const vendor_ie_data_t *vnd_ie, int rssi); + +static inline esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, const void *vnd_ie) { (void)enable; (void)type; (void)idx; (void)vnd_ie; return ESP_OK; } +static inline esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx) { (void)cb; (void)ctx; return ESP_OK; } + +#define WIFI_SCAN_TYPE_PASSIVE 0 + +typedef struct { + uint8_t bssid[6]; + uint8_t ssid[33]; + uint8_t primary; + int second; + int8_t rssi; + int authmode; +} wifi_ap_record_t; + +typedef struct { + uint8_t *ssid; + uint8_t *bssid; + uint8_t channel; + bool show_hidden; + int scan_type; + union { + struct { int min; int max; } active; + int passive; + } scan_time; +} wifi_scan_config_t; + +static inline esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *cfg, bool block) { (void)cfg; (void)block; return ESP_OK; } +static inline esp_err_t esp_wifi_scan_get_ap_num(uint16_t *n) { *n = 0; return ESP_OK; } +static inline esp_err_t esp_wifi_scan_get_ap_records(uint16_t *n, wifi_ap_record_t *records) { (void)records; *n = 0; return ESP_OK; } + +#define WIFI_EVENT_SCAN_DONE 3 + +typedef void *esp_event_handler_instance_t; +typedef const char *esp_event_base_t; +#define WIFI_EVENT "WIFI_EVENT" + +static inline esp_err_t esp_event_handler_instance_register(esp_event_base_t a, int32_t b, void *c, void *d, esp_event_handler_instance_t *e) { (void)a; (void)b; (void)c; (void)d; (void)e; return ESP_OK; } + #endif -- cgit v1.2.3