#ifndef POWER_MGMT_H #define POWER_MGMT_H #include #include /* * power_mgmt — STM32F7 STOP-mode sleep/wake manager (Issue #178). * * State machine: * PM_ACTIVE ──(idle ≥ PM_IDLE_TIMEOUT_MS or sleep cmd)──► PM_SLEEP_PENDING * PM_SLEEP_PENDING ──(fade complete, ≥ PM_FADE_MS)──► PM_SLEEPING (WFI) * PM_SLEEPING ──(EXTI wake)──► PM_WAKING ──(clocks restored)──► PM_ACTIVE * * Any call to power_mgmt_activity() during SLEEP_PENDING or SLEEPING * immediately transitions back toward PM_ACTIVE. * * Wake sources (EXTI, falling edge on UART idle-high RX pin or IMU INT): * EXTI1 PA1 UART4_RX — CRSF/ELRS start bit * EXTI7 PB7 USART1_RX — JLink start bit * EXTI4 PC4 MPU6000 INT — IMU motion (handler owned by mpu6000.c) * * Peripheral gating on sleep entry (clock disable, state preserved): * Disabled: SPI3/I2S3 (audio amp), SPI2 (OSD), USART6, UART5 (debug) * Active: SPI1 (IMU), UART4 (CRSF), USART1 (JLink), I2C1 (baro/mag) * * Sleep LED (LED1, active-low PC15): * PM_SLEEP_PENDING: triangle-wave pulse, period PM_LED_PERIOD_MS * All other states: 0 (caller uses normal LED logic) * * IWDG: * Fed immediately before WFI. STOP wakeup <10 ms typical — well within * WATCHDOG_TIMEOUT_MS (50 ms). * * Safety interlock: * Caller MUST NOT call power_mgmt_tick() while armed; call * power_mgmt_activity() instead to keep the idle timer reset. * * JLink integration: * JLINK_CMD_SLEEP (0x09) → power_mgmt_request_sleep() * Any valid JLink frame → power_mgmt_activity() (handled in main loop) */ typedef enum { PM_ACTIVE = 0, /* Normal, all peripherals running */ PM_SLEEP_PENDING = 1, /* Idle timeout reached; LED fade-out in progress */ PM_SLEEPING = 2, /* In STOP mode (WFI); execution blocked in tick() */ PM_WAKING = 3, /* Transitional; clocks/peripherals being restored */ } PowerState; /* ---- API ---- */ /* * power_mgmt_init() — configure wake EXTI lines (EXTI1, EXTI7). * Call after crsf_init() and jlink_init(). */ void power_mgmt_init(void); /* * power_mgmt_activity() — record cmd_vel event (CRSF frame, JLink frame). * Resets idle timer; aborts any pending/active sleep. */ void power_mgmt_activity(void); /* * power_mgmt_request_sleep() — force sleep regardless of idle timer * (called on JLINK_CMD_SLEEP). Next tick() enters PM_SLEEP_PENDING. */ void power_mgmt_request_sleep(void); /* * power_mgmt_tick(now_ms) — drive state machine. May block in WFI during * STOP mode. Returns state after this tick. * MUST NOT be called while balance_state == BALANCE_ARMED. */ PowerState power_mgmt_tick(uint32_t now_ms); /* power_mgmt_state() — non-blocking read of current state. */ PowerState power_mgmt_state(void); /* * power_mgmt_led_brightness() — 0-255 brightness for sleep-pending pulse. * Returns 0 when not in PM_SLEEP_PENDING; caller uses normal LED logic. */ uint8_t power_mgmt_led_brightness(void); /* * power_mgmt_current_ma() — estimated total current draw (mA) based on * gating state; populated in JLINK_TLM_POWER telemetry. */ uint16_t power_mgmt_current_ma(void); /* power_mgmt_idle_ms() — ms elapsed since last power_mgmt_activity() call. */ uint32_t power_mgmt_idle_ms(void); #endif /* POWER_MGMT_H */