Line-based JSON protocol over the ESP32-S3 native USB OTG port, providing deterministic sub-millisecond attenuator control without WiFi interference. Runs alongside the existing REST API. Commands: identify, status, config, set, sweep, sweep_stop Protocol: usb-serial-json-v1 (one JSON object per \n-terminated line) Also addresses pre-existing reliability issues found during review: - Thread safety: FreeRTOS mutex in Attenuator class (web server callbacks run on async_tcp task, not loop()) - NVS flash wear: skip persist during sweep, save on stop - WiFi credentials: moved to gitignored platformio_local.ini - Shared header: sweep.h replaces duplicated extern declarations
89 lines
3.0 KiB
C
89 lines
3.0 KiB
C
#pragma once
|
|
|
|
#include <Arduino.h>
|
|
|
|
// --- Firmware Version ---
|
|
#define FW_VERSION "2026-02-02"
|
|
#define FW_HOSTNAME "attenuator"
|
|
|
|
// --- WiFi Credentials ---
|
|
// Define WIFI_SSID and WIFI_PASS via build_flags in platformio_override.ini
|
|
#ifndef WIFI_SSID
|
|
#error "WIFI_SSID not defined — add build_flags to firmware/platformio_override.ini (see platformio_override.ini.example)"
|
|
#endif
|
|
#ifndef WIFI_PASS
|
|
#error "WIFI_PASS not defined — add build_flags to firmware/platformio_override.ini (see platformio_override.ini.example)"
|
|
#endif
|
|
|
|
#define WIFI_TIMEOUT_MS 15000
|
|
|
|
// WiFi TX power level (dBm)
|
|
// Lower = less current draw, less RF interference on bench
|
|
// Valid: WIFI_POWER_2dBm to WIFI_POWER_19_5dBm
|
|
// Using minimum (2 dBm / ~1.6 mW) to prevent brownout on USB power
|
|
#ifndef WIFI_TX_POWER_DBM
|
|
#define WIFI_TX_POWER_DBM WIFI_POWER_2dBm
|
|
#endif
|
|
|
|
// --- HMC472A Control Pins (active-low) ---
|
|
// Optimized mapping: GPIO number = step bit position + 1
|
|
// Enables single-instruction bitwise ops instead of loop
|
|
//
|
|
// Wiring (GPIO → HMC472A pin):
|
|
// GPIO1 → V6 (0.5 dB) = step bit 0 (LSB)
|
|
// GPIO2 → V5 (1 dB) = step bit 1
|
|
// GPIO3 → V4 (2 dB) = step bit 2
|
|
// GPIO4 → V3 (4 dB) = step bit 3
|
|
// GPIO5 → V2 (8 dB) = step bit 4
|
|
// GPIO6 → V1 (16 dB) = step bit 5 (MSB)
|
|
//
|
|
static constexpr uint8_t PIN_V6 = 1; // 0.5 dB (LSB) - step bit 0
|
|
static constexpr uint8_t PIN_V5 = 2; // 1 dB - step bit 1
|
|
static constexpr uint8_t PIN_V4 = 3; // 2 dB - step bit 2
|
|
static constexpr uint8_t PIN_V3 = 4; // 4 dB - step bit 3
|
|
static constexpr uint8_t PIN_V2 = 5; // 8 dB - step bit 4
|
|
static constexpr uint8_t PIN_V1 = 6; // 16 dB (MSB) - step bit 5
|
|
|
|
// Pin array ordered by attenuation value (V1=16dB first)
|
|
static constexpr uint8_t ATTEN_PINS[6] = {PIN_V1, PIN_V2, PIN_V3, PIN_V4, PIN_V5, PIN_V6};
|
|
static constexpr float ATTEN_DB[6] = {16.0f, 8.0f, 4.0f, 2.0f, 1.0f, 0.5f};
|
|
|
|
// Bitmask: 0b01111110 = bits 1-6 in GPIO register
|
|
static constexpr uint32_t ATTEN_PIN_MASK = 0x7E;
|
|
|
|
// --- Status LED ---
|
|
static constexpr uint8_t PIN_LED = 15; // Built-in LED, active HIGH
|
|
|
|
// --- OLED Display (SSD1306 128x64 I2C) ---
|
|
static constexpr uint8_t PIN_SDA = 8;
|
|
static constexpr uint8_t PIN_SCL = 9;
|
|
static constexpr uint8_t OLED_ADDR = 0x3C; // 7-bit address (0x78 >> 1)
|
|
static constexpr uint8_t OLED_WIDTH = 128;
|
|
static constexpr uint8_t OLED_HEIGHT = 64;
|
|
|
|
// --- Attenuator Limits ---
|
|
static constexpr float DB_MIN = 0.0f;
|
|
static constexpr float DB_MAX = 31.5f;
|
|
static constexpr float DB_STEP = 0.5f;
|
|
static constexpr uint8_t STEP_MIN = 0;
|
|
static constexpr uint8_t STEP_MAX = 63;
|
|
|
|
// --- Sweep Defaults ---
|
|
static constexpr uint32_t SWEEP_DWELL_MS_DEFAULT = 500;
|
|
static constexpr uint32_t SWEEP_DWELL_MS_MIN = 10;
|
|
static constexpr uint32_t SWEEP_DWELL_MS_MAX = 10000;
|
|
|
|
// --- NVS ---
|
|
#define NVS_NAMESPACE "atten"
|
|
#define NVS_KEY_STEP "step"
|
|
|
|
// --- Watchdog ---
|
|
#define WDT_TIMEOUT_S 120
|
|
|
|
// --- Web Server ---
|
|
#define WEB_PORT 80
|
|
|
|
// --- USB Serial Command Interface ---
|
|
#define USB_SERIAL_BAUD 115200
|
|
#define USB_SERIAL_BUF_LEN 256
|