#pragma once #include // ------------------------- Hardware configuration ------------------------- // Enabled for the hand-wired prototype. Comment out for the production PCB. // Both profiles map S3 signals by physical header position with 5V/GND aligned. #define MAKETKA // Additionally log raw GPIO_RX level changes while no test is running. //#define RX_PIN_CHANGE_TEST // Standalone PWM output check. While enabled, the normal application is not // started: GPIO_PWM continuously outputs the frequency and duty below. // Comment this define out after the hardware check. //#define PWM_OUTPUT_TEST constexpr uint32_t PWM_OUTPUT_TEST_FREQUENCY_HZ = 1000; constexpr uint32_t PWM_OUTPUT_TEST_SWEEP_PERIOD_MS = 2000; constexpr uint32_t PWM_OUTPUT_TEST_UPDATE_MS = 10; constexpr uint32_t PWM_OUTPUT_TEST_MIN_PULSE_NS = 1000; constexpr uint32_t PWM_OUTPUT_TEST_MAX_PULSE_NS = 10000; #if CONFIG_IDF_TARGET_ESP32C3 constexpr bool TARGET_IS_C3 = true; constexpr uint8_t GPIO_PWM = 3; constexpr uint8_t GPIO_RX = 4; #ifdef MAKETKA constexpr uint8_t GPIO_BUTTON_MODE = 0; constexpr uint8_t GPIO_BUTTON_START = 1; #else constexpr uint8_t GPIO_BUTTON_MODE = 20; constexpr uint8_t GPIO_BUTTON_START = 10; constexpr uint8_t GPIO_VBAT = 2; constexpr uint8_t GPIO_ANALOG_RX = 0; #endif constexpr uint8_t GPIO_SDA = 6; constexpr uint8_t GPIO_SCL = 7; #elif CONFIG_IDF_TARGET_ESP32S3 constexpr bool TARGET_IS_C3 = false; #ifdef MAKETKA // Same physical header contacts as the C3 MAKETKA profile when 5V/GND align. constexpr uint8_t GPIO_PWM = 12; constexpr uint8_t GPIO_RX = 13; constexpr uint8_t GPIO_BUTTON_MODE = 9; constexpr uint8_t GPIO_BUTTON_START = 10; constexpr uint8_t GPIO_SDA = 44; constexpr uint8_t GPIO_SCL = 1; #else // The S3 SuperMini is fitted so its 5V and GND pins occupy the same PCB // contacts as on the C3 SuperMini. Signals therefore follow header position. constexpr uint8_t GPIO_PWM = 12; constexpr uint8_t GPIO_RX = 13; constexpr uint8_t GPIO_BUTTON_MODE = 5; constexpr uint8_t GPIO_BUTTON_START = 4; constexpr uint8_t GPIO_SDA = 44; constexpr uint8_t GPIO_SCL = 1; constexpr uint8_t GPIO_VBAT = 11; constexpr uint8_t GPIO_ANALOG_RX = 9; #endif #else #error "Only ESP32-C3 and ESP32-S3 are supported" #endif constexpr uint8_t OLED_ROTATION = 0; constexpr uint8_t OLED_ADDRESS = 0x3C; constexpr uint8_t ESPNOW_WIFI_CHANNEL = 6; constexpr uint32_t SERIAL_BAUD = 115200; // Native USB CDC may keep a stale "connected" state after light sleep. Keep // logging non-blocking so a missing host can never delay button polling. constexpr uint32_t SERIAL_TX_TIMEOUT_MS = 2; constexpr bool SERIAL_ACTION_LOG = true; constexpr bool SERIAL_LOG_TIMESTAMPS = true; constexpr bool SERIAL_MINIMAL_LOG = true; #define BUTTON_ACTIVE_LEVEL LOW // Fixed PCB conversion between electrical GPIO levels and actual optical // light. User settings HH/HL/LH/LL operate only in the optical domain and // never change these hardware facts. #define TX_LIGHT_ON_GPIO_LEVEL LOW #define RX_LIGHT_ON_GPIO_LEVEL LOW #define TX_LIGHT_OFF_GPIO_LEVEL (TX_LIGHT_ON_GPIO_LEVEL == HIGH ? LOW : HIGH) #define PWM_SETTLE_CYCLES 5U constexpr uint32_t BUTTON_DEBOUNCE_MS = 30; constexpr uint32_t BUTTON_LONG_PRESS_MS = 500; constexpr uint32_t BUTTON_REPEAT_DELAY_MS = 600; constexpr uint32_t BUTTON_REPEAT_MS = 180; constexpr uint32_t FACTORY_RESET_HOLD_MS = 1500; constexpr uint32_t LINK_REPLY_TIMEOUT_MS = 1500; constexpr uint8_t LINK_PACKET_RETRIES = 10; constexpr uint32_t LINK_RETRY_INTERVAL_MS = 1000; constexpr uint32_t DISCOVERY_RETRY_INTERVAL_MS = 20; // During discovery Master alternates actual optical light ON and OFF to wake // a sleeping Slave through the optical channel. constexpr uint32_t OPTICAL_WAKE_HALF_PERIOD_MS = 50; constexpr uint32_t LINK_HEARTBEAT_INTERVAL_MS = 500; constexpr uint32_t LINK_HEARTBEAT_TIMEOUT_MS = 2500; constexpr uint32_t FINAL_ACK_RETRY_INTERVAL_MS = 50; constexpr uint8_t FINAL_ACK_RETRIES = 2; constexpr uint8_t NO_SIGNAL_TIMEOUT_PERIODS = 8; constexpr uint16_t PERIOD_BATCH_SIZE = 128; // Retained as the minimum statistical depth used by the hardware-resolution // calculation and diagnostics. PASS/FAIL is evaluated for every complete // pulse independently; accumulated values are used only for display. constexpr uint16_t MEASUREMENT_AVERAGING_PERIODS = 100; static_assert(MEASUREMENT_AVERAGING_PERIODS > 0, "Averaging window must contain at least one period"); constexpr uint8_t MEASUREMENT_PROGRESS_STEPS = 10; constexpr uint32_t OLED_PROGRESS_UPDATE_MS = 15; constexpr uint8_t DRIVER_SHORT_SAMPLE_PROGRESS_STEPS = 10; constexpr uint32_t DRIVER_PROGRESS_INTERVAL_MS = 100; constexpr uint32_t IDLE_POWER_SAVE_TIMEOUT_MS = 60000; // usb_serial_jtag_is_connected() needs no open COM port or CDC traffic, but a // short SOF detection gap must not send the board to sleep. constexpr uint32_t USB_HOST_DISCONNECT_GRACE_MS = 5000; constexpr uint16_t SLAVE_LISTEN_INTERVAL_MS = 100; constexpr uint16_t SLAVE_LISTEN_WINDOW_MS = 20; static_assert(SLAVE_LISTEN_WINDOW_MS < SLAVE_LISTEN_INTERVAL_MS, "Slave listen window must be shorter than its interval"); // Conservative sustained validation rate calibrated from real C3 logs. constexpr uint32_t RX_PROCESSING_PERIODS_PER_SECOND = 300000; constexpr uint32_t C3_STRICT_MAX_HZ = 1000000; constexpr uint32_t S3_STRICT_MAX_HZ = 1000000; // S3 MCPWM Capture uses one 32-bit 80 MHz timer for both edges. Unlike RMT, // its width does not constrain long LOW/HIGH intervals, so capture precision // stays at 12.5 ns for every selectable PWM frequency and pulse length. constexpr uint32_t MCPWM_CAPTURE_RESOLUTION_HZ = 80000000; // C3 uses the 40 MHz crystal as the LEDC clock. // Keep this explicit so the resolution calculation never asks LEDC for an // impossible frequency/resolution combination. constexpr uint32_t LEDC_SOURCE_CLOCK_HZ = 40000000; constexpr uint8_t LEDC_CHANNEL = 0; constexpr uint8_t LEDC_MAX_BITS = 14; // S3 uses the dedicated MCPWM peripheral. A 20 MHz timer clock keeps the // selectable 500 Hz period within the S3's 16-bit counter while retaining // 50 ns pulse resolution and exact periods for every menu frequency. constexpr uint32_t MCPWM_RESOLUTION_HZ = 20000000; constexpr uint32_t MCPWM_MAX_PERIOD_TICKS = 65535; // Concept 1SP0635 status acknowledgement, expressed in the optical domain. constexpr uint32_t DRIVER_MIN_INPUT_PULSE_NS = 2000; constexpr uint32_t DRIVER_ACK_DELAY_NS = 250; constexpr uint32_t DRIVER_ACK_WIDTH_NS = 700; constexpr uint32_t DRIVER_ACK_START_MAX_NS = 2000; constexpr uint32_t DRIVER_ACK_MERGE_MARGIN_NS = 250; // The first MCPWM TX end may belong to a pulse that was already active when // capture was enabled. The following period also drains capture events that // were pending independently in the rising/falling channels. Validation // therefore begins at the third TX period. constexpr uint8_t DRIVER_CAPTURE_SYNC_CYCLES = 2; // Any response this long is a fault, not a normal acknowledgement. constexpr uint32_t DRIVER_FAULT_MIN_NS = 1500; constexpr uint32_t DRIVER_RX_STUCK_MIN_NS = 20000; // Retained by the generic receiver backend; the driver test itself uses the // stricter ACK start deadline above. constexpr uint32_t DRIVER_RESPONSE_TIMEOUT_NS = 10000; // -------------------------- Menu value arrays ----------------------------- // The test uses one selected PWM frequency and walks the pulse-width list from // the selected maximum down to the selected minimum. Widths are stored in // nanoseconds so sub-microsecond pulses remain representable without floats. constexpr uint32_t PWM_FREQUENCY_OPTIONS_HZ[] = { 500, 1000, 2000, 5000, 10000, }; constexpr uint32_t MAX_PULSE_OPTIONS_NS[] = { 2000, 5000, 10000, 50000, 100000, 500000 }; constexpr uint32_t MIN_PULSE_OPTIONS_NS[] = { 250, 500, 1000, 2000, 5000, 10000, 50000 }; constexpr uint32_t TEST_PULSE_WIDTHS_NS[] = { 50, 100, 150, 200, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000 }; constexpr float ACCURACY_OPTIONS_PCT[] = {1.0f, 2.0f, 5.0f, 10.0f}; constexpr uint32_t TEST_TIME_OPTIONS_MS[] = {100, 250, 500, 1000, 2000, 5000, 60000}; template constexpr size_t countOf(const T (&)[N]) { return N; }