#ifndef LED_H #define LED_H #include #include /* * led.h — WS2812B NeoPixel status indicator driver (Issue #193) * * Hardware: TIM3_CH1 PWM on PB4 at 800 kHz (1.25 µs per bit). * Controls an 8-LED ring with state-based animations: * - Boot: Blue chase (startup sequence) * - Armed: Solid green * - Error: Red blinking (visual alert) * - Low Battery: Yellow pulsing (warning) * - Charging: Green breathing (soft indication) * - E-Stop: Red strobe (immediate action required) * * State transitions are non-blocking via a 1 ms timer callback (led_tick). * Each state defines its own animation envelope: color, timing, and brightness. * * WS2812 protocol (NRZ): * - Bit "0": High 350 ns, Low 800 ns (1.25 µs total) * - Bit "1": High 700 ns, Low 600 ns (1.25 µs total) * - Reset: Low > 50 µs * * PWM-based implementation via DMA: * - 10 levels: [350 ns, 400, 450, 500, 550, 600, 650, 700, 750, 800] * - Bit "0" → High 350-400 ns Bit "1" → High 650-800 ns * - Each bit requires one PWM cycle; 24 bits/LED × 8 LEDs = 192 cycles * - DMA rings through buffer, auto-reloads on update events */ /* LED state enumeration */ typedef enum { LED_STATE_BOOT = 0, /* Blue chase (startup) */ LED_STATE_ARMED = 1, /* Solid green */ LED_STATE_ERROR = 2, /* Red blinking */ LED_STATE_LOW_BATT = 3, /* Yellow pulsing */ LED_STATE_CHARGING = 4, /* Green breathing */ LED_STATE_ESTOP = 5, /* Red strobe */ LED_STATE_COUNT } LEDState; /* RGB color (8-bit per channel) */ typedef struct { uint8_t r; uint8_t g; uint8_t b; } RGBColor; /* * led_init() * * Configure TIM3_CH1 PWM on PB4 at 800 kHz, set up DMA for bit streaming, * and initialize the LED buffer. Call once at startup, after buzzer_init() * but before the main loop. */ void led_init(void); /* * led_set_state(state) * * Change the LED display state. The animation runs non-blocking via led_tick(). * Valid states: LED_STATE_BOOT, LED_STATE_ARMED, LED_STATE_ERROR, etc. */ void led_set_state(LEDState state); /* * led_get_state() * * Return the current LED state. */ LEDState led_get_state(void); /* * led_set_color(r, g, b) * * Manually set the LED ring to a solid color. Overrides the current state * animation until led_set_state() is called again. */ void led_set_color(uint8_t r, uint8_t g, uint8_t b); /* * led_tick(now_ms) * * Advance animation state machine. Must be called every 1 ms from the main loop. * Handles state-specific animations: chase timing, pulse envelope, strobe phase, etc. * Updates the DMA buffer with new LED values without blocking. */ void led_tick(uint32_t now_ms); /* * led_is_animating() * * Returns true if the current state is actively animating (e.g., chase, pulse, strobe). * Returns false for static states (armed, error solid). */ bool led_is_animating(void); #endif /* LED_H */