//! IO MUX and GPIO matrix routing for {{ ir.board.name }}.
//!
//! For each assigned pin we either:
//!
//! * take the **direct IO MUX fast path** by writing the `mcu_sel` field of
//!   `IO_MUX.gpio<n>` when the peripheral signal has `iomux_pin == gpio`;
//! * or fall back to the **GPIO matrix**, writing
//!   `GPIO.func<id>_out_sel_cfg` / `func<id>_in_sel_cfg` so the signal is
//!   routed through the matrix.
//!
//! Pins tagged `flash_reserved` in the chip IR are filtered out upstream by
//! `espressif::load::merge`; any that reach this file are a generator bug.

use super::pac;

/// Apply the board's pin mux and GPIO matrix routing.
pub fn init() {
    let p = unsafe { pac::Peripherals::steal() };
    {% for pin in pin_routes %}
    // GPIO{{ pin.gpio }} — {{ pin.signal }}{% if pin.peripheral %} ({{ pin.peripheral }}){% endif %}
    {% if pin.route.kind == "direct" %}
    // Direct IO MUX fast path: fn{{ pin.route.fn_slot }}
    p.IO_MUX.gpio({{ pin.gpio }}).modify(|_, w| unsafe {
        w.mcu_sel().bits({{ pin.route.fn_slot }})
         .fun_ie().{% if pin.direction == "in" or pin.direction == "inout" %}set_bit{% else %}clear_bit{% endif %}()
         .fun_wpu().{% if pin.pull == "up" %}set_bit{% else %}clear_bit{% endif %}()
         .fun_wpd().{% if pin.pull == "down" %}set_bit{% else %}clear_bit{% endif %}()
    });
    {% elif pin.route.kind == "matrix" %}
    // Route via GPIO matrix: signal id {{ pin.route.signal_id }}
    {% if pin.direction == "out" or pin.direction == "inout" %}
    p.GPIO.func_out_sel_cfg({{ pin.gpio }}).modify(|_, w| unsafe { w.out_sel().bits({{ pin.route.signal_id }}) });
    {% endif %}
    {% if pin.direction == "in" or pin.direction == "inout" %}
    p.GPIO.func_in_sel_cfg({{ pin.route.signal_id }}).modify(|_, w| unsafe { w.in_sel().bits({{ pin.gpio }}).in_inv_sel().clear_bit() });
    {% endif %}
    // mcu_sel=1 selects the GPIO matrix function. Also configure input
    // enable + pulls so matrix-routed inout signals like I2C SDA/SCL
    // actually reach the peripheral.
    p.IO_MUX.gpio({{ pin.gpio }}).modify(|_, w| unsafe {
        w.mcu_sel().bits(1)
         .fun_ie().{% if pin.direction == "in" or pin.direction == "inout" %}set_bit{% else %}clear_bit{% endif %}()
         .fun_wpu().{% if pin.pull == "up" %}set_bit{% else %}clear_bit{% endif %}()
         .fun_wpd().{% if pin.pull == "down" %}set_bit{% else %}clear_bit{% endif %}()
    });
    {% else %}
    // Plain GPIO (no peripheral): configure IO MUX for software-driven GPIO
    p.IO_MUX.gpio({{ pin.gpio }}).modify(|_, w| unsafe {
        w.mcu_sel().bits(1)
         .fun_ie().{% if pin.direction == "in" or pin.direction == "inout" %}set_bit{% else %}clear_bit{% endif %}()
         .fun_wpu().{% if pin.pull == "up" %}set_bit{% else %}clear_bit{% endif %}()
         .fun_wpd().{% if pin.pull == "down" %}set_bit{% else %}clear_bit{% endif %}()
    });
    {% if pin.direction == "out" %}
    p.GPIO.enable_w1ts().write(|w| unsafe { w.bits(1 << {{ pin.gpio }}) });
    {% endif %}
    {% endif %}
    {% endfor %}
}
