#ifndef GPIO_H
#define GPIO_H
// #include <map>
#include <cstdint>
#include <vector>
#include <climits>

#include <ArduinoLog.h>
#include <Component.h>
#include <Bridge.h>
#include <enums.h>
#include <modbus/ModbusTypes.h>
#include <modbus/ModbusTCP.h>
#include <ArduinoJson.h>
// -----------------------------------------------------------------------------
//  GPIO pin number enumeration (unchanged)
// -----------------------------------------------------------------------------
enum E_GPIO_Pin
{
    E_GPIO_0 = 0,
    E_GPIO_1 = 1,
    E_GPIO_2 = 2,
    E_GPIO_3 = 3,
    E_GPIO_4 = 4,
    E_GPIO_5 = 5,
    E_GPIO_6 = 6,
    E_GPIO_7 = 7,
    E_GPIO_8 = 8,
    E_GPIO_9 = 9,
    E_GPIO_10 = 10,
    E_GPIO_11 = 11,
    E_GPIO_12 = 12,
    E_GPIO_13 = 13,
    E_GPIO_14 = 14,
    E_GPIO_15 = 15,
    E_GPIO_16 = 16,
    E_GPIO_17 = 17,
    E_GPIO_18 = 18,
    E_GPIO_19 = 19,
    E_GPIO_20 = 20,
    E_GPIO_21 = 21,
    // Skipping 22‑34 – not available
    E_GPIO_35 = 35,
    E_GPIO_36 = 36,
    E_GPIO_37 = 37,
    E_GPIO_38 = 38,
    E_GPIO_39 = 39,
    E_GPIO_40 = 40,
    E_GPIO_41 = 41,
    E_GPIO_42 = 42,
    E_GPIO_43 = 43,
    E_GPIO_44 = 44,
    E_GPIO_45 = 45,
    E_GPIO_46 = 46,
    E_GPIO_47 = 47,
    E_GPIO_48 = 48
};

// -----------------------------------------------------------------------------
//  MB_GPIO pin types / modes (unchanged)
// -----------------------------------------------------------------------------
enum E_GPIO_Type
{
    E_GPIO_TYPE_UNKNOWN,
    E_GPIO_TYPE_INPUT,
    E_GPIO_TYPE_OUTPUT,
    E_GPIO_TYPE_INPUT_PULLUP,
    E_GPIO_TYPE_INPUT_PULLDOWN,
    E_GPIO_TYPE_OUTPUT_OPEN_DRAIN,
    E_GPIO_TYPE_ANALOG_INPUT, // ADC
    E_GPIO_TYPE_TOUCH         // capacitive touch
};

// -----------------------------------------------------------------------------
//  Configuration for a single managed MB_GPIO pin – inherits Modbus meta‑data and
//  adds timing & caching so we can throttle operations and skip duplicates.
// -----------------------------------------------------------------------------
struct GPIO_PinConfig
{
    // MB_Registers fields copied here
    ushort startAddress = 0xFFFF; // Use 0xFFFF to indicate invalid/not set
    ushort count = 1;             // Assume 1 register per pin
    ushort slaveId = 0;           // Usually 0 for TCP/IP direct
    E_FN_CODE type = E_FN_CODE::FN_NONE;
    E_ModbusAccess access = MB_ACCESS_NONE;
    ushort componentId = 0; // Will be overridden by owner
    const char *name = nullptr;
    const char *group = nullptr;
    ComponentFnPtr writeCallbackFn = nullptr;

    // GPIO specific fields
    E_GPIO_Pin pinNumber = E_GPIO_0;
    E_GPIO_Type pinType = E_GPIO_TYPE_UNKNOWN;

    // Runtime helpers
    uint32_t opIntervalMs = 100;
    int cachedValue = INT_MIN;
    unsigned long lastOpTimestamp = 0;

    // Constructor initializes all members
    GPIO_PinConfig(E_GPIO_Pin pNum = E_GPIO_0,
                   E_GPIO_Type pType = E_GPIO_TYPE_UNKNOWN,
                   ushort addr = 0xFFFF,
                   E_FN_CODE fn = E_FN_CODE::FN_NONE,
                   E_ModbusAccess acc = MB_ACCESS_NONE,
                   uint32_t intervalMs = 100,
                   const char *regName = nullptr,
                   const char *regGroup = nullptr,
                   ComponentFnPtr cb = nullptr)
        : startAddress(addr),
          count(1),
          slaveId(0),
          type(fn),
          access(acc),
          // componentId(0), // Let owner set it
          name(regName),
          group(regGroup),
          writeCallbackFn(cb),
          pinNumber(pNum),
          pinType(pType),
          opIntervalMs(intervalMs),
          cachedValue(INT_MIN),
          lastOpTimestamp(0) // Default initialized
    {
    }
};

// -----------------------------------------------------------------------------
//  Capability bit‑mask (unchanged – table at end)
// -----------------------------------------------------------------------------
// Define capabilities using a bitmask
enum E_GPIO_Capability : uint32_t
{
    CAP_NONE = 0,
    CAP_RTC = 1 << 0,
    CAP_ADC1 = 1 << 1,
    CAP_ADC2 = 1 << 2,
    CAP_TOUCH = 1 << 3,
    CAP_JTAG_TCK = 1 << 4, // GPIO4 (TCK), GPIO39 (MTCK)
    CAP_JTAG_TDI = 1 << 5, // GPIO3 (TDI?), GPIO41 (MTDI)
    CAP_JTAG_TDO = 1 << 6, // GPIO3 (TDO?), GPIO40 (MTDO)
    CAP_JTAG_TMS = 1 << 7, // GPIO42 (MTMS)
    CAP_FSPI_CS0 = 1 << 8,
    CAP_FSPI_CLK = 1 << 9,
    CAP_FSPI_MISO = 1 << 10,   // Q/IO1
    CAP_FSPI_MOSI = 1 << 11,   // D/IO0
    CAP_FSPI_HD = 1 << 12,     // IO3 / GPIO9
    CAP_FSPI_WP = 1 << 13,     // IO2 / GPIO10, GPIO38
    CAP_FSPI_IO4 = 1 << 14,    // GPIO14
    CAP_FSPI_IO5 = 1 << 15,    // GPIO13
    CAP_FSPI_IO6 = 1 << 16,    // GPIO11, GPIO37
    CAP_FSPI_IO7 = 1 << 17,    // GPIO12, GPIO36
    CAP_UART0_TX = 1 << 18,    // GPIO43
    CAP_UART0_RX = 1 << 19,    // GPIO44
    CAP_UART1_TX = 1 << 20,    // GPIO18
    CAP_UART1_RX = 1 << 21,    // GPIO17
    CAP_UART2_TX = 1 << 22,    // GPIO20
    CAP_UART2_RX = 1 << 23,    // GPIO19
    CAP_I2C0_SDA = 1 << 24,    // GPIO8
    CAP_I2C0_SCL = 1 << 25,    // GPIO9
    CAP_CLK_OUT1 = 1 << 26,    // GPIO2, GPIO20, GPIO41
    CAP_CLK_OUT2 = 1 << 27,    // GPIO1, GPIO19, GPIO40
    CAP_CLK_OUT3 = 1 << 28,    // GPIO0, GPIO39
    CAP_USB_D_PLUS = 1 << 29,  // GPIO20
    CAP_USB_D_MINUS = 1 << 30, // GPIO19
    CAP_LED_BUILTIN = 1U << 31 // GPIO38
    // Note: RGB LED (GPIO48), XTAL, Strapping pins are not included in this bitmask
};
// -----------------------------------------------------------------------------
//  MB_GPIO component – manages a *group* of pins
// -----------------------------------------------------------------------------
class MB_GPIO : public Component
{
private:
    // Internal copy of the pin configurations
    std::vector<GPIO_PinConfig> pinConfigs;

    // Internal helper to find config by Modbus address
    const GPIO_PinConfig *findConfigByModbusAddress(ushort address) const
    {
        // Iterate internal vector
        for (const auto &cfg : pinConfigs) // Use direct member access
        {
            if (cfg.startAddress == address)
                return &cfg;
        }
        return nullptr;
    }

    // Internal helper to find *non-const* config (needed for write)
    GPIO_PinConfig *findConfigByModbusAddress(ushort address)
    {
        // Needs to iterate over the internal vector non-constantly
        for (auto &cfg : pinConfigs) // Use direct member access
        {
            if (cfg.startAddress == address)
                return &cfg;
        }
        return nullptr;
    }

    // -------------------------------------------------------------------------
    // Raw read helper
    // -------------------------------------------------------------------------
    int readPinInternal(E_GPIO_Pin pin, E_GPIO_Type type) const
    {
        return (type == E_GPIO_TYPE_ANALOG_INPUT) ? analogRead(static_cast<int>(pin))
                                                  : digitalRead(static_cast<int>(pin));
    }

    // -------------------------------------------------------------------------
    // Raw *and throttled* write helper – skips duplicates & enforces interval.
    // Returns E_OK even when operation skipped (so Modbus sees no error).
    // -------------------------------------------------------------------------
    short writePinInternal(GPIO_PinConfig &cfg, int value)
    {
        if (!(cfg.pinType == E_GPIO_TYPE_OUTPUT || cfg.pinType == E_GPIO_TYPE_OUTPUT_OPEN_DRAIN))
        {
            Log.warningln("MB_GPIO::writePinInternal - Pin %d not output type (%d)", (int)cfg.pinNumber, (int)cfg.pinType);
            return E_INVALID_PARAMETER;
        }

        unsigned long now = millis();
        if (value == cfg.cachedValue)
        {
            // duplicate value → skip silently
            return E_OK;
        }
        if (now - cfg.lastOpTimestamp < cfg.opIntervalMs)
        {
            // too soon → skip
            return E_OK;
        }

        digitalWrite(static_cast<int>(cfg.pinNumber), value ? HIGH : LOW);
        cfg.cachedValue = value;
        cfg.lastOpTimestamp = now;
        return E_OK;
    }

    // -------------------------------------------------------------------------
    //  Modbus block storage
    // -------------------------------------------------------------------------
    MB_Registers *mbRegisterBlocksData = nullptr;
    int mbRegisterBlocksCount = 0;
    ModbusBlockView mbBlockView; // {data,count}

public:
    // static const std::map<E_GPIO_Pin, uint32_t> pinCapabilities;

    // Constructor takes std::vector reference and copies the data
    MB_GPIO(Component *owner,
            short _id,
            const std::vector<GPIO_PinConfig> &configs) // Accept const reference
        : Component("GPIO_Group", _id, Component::COMPONENT_DEFAULT, owner),
          pinConfigs(configs) // Initialize by copying
    {
        setNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS);
        allocateAndPopulateMbBlocks(); // Uses the internal pinConfigs copy
        Log.verboseln("MB_GPIO %d constructed - Copied %d configs, %d Modbus blocks prepared", id, (int)pinConfigs.size(), mbRegisterBlocksCount);
    }
    ~MB_GPIO() override { delete[] mbRegisterBlocksData; } // Destructor unchanged

    // Component API ------------------------------------------------------------
    short setup() override;
    short loop() override;
    short info(short flags = 0, short val = 0) override;
    short debug() override { return info(); }
    short serial_register(Bridge *bridge) override;
    short load(const JsonObject &config); // Removed override, base Component doesn't have virtual load

    // Modbus TCP ---------------------------------------------------------------
    short mb_tcp_read(short address) override;
    short mb_tcp_read(MB_Registers *reg) override { return reg ? mb_tcp_read(reg->startAddress) : 0; }
    short mb_tcp_write(short address, short networkValue) override;
    short mb_tcp_write(MB_Registers *reg, short networkValue) override { return reg ? mb_tcp_write(reg->startAddress, networkValue) : E_INVALID_PARAMETER; }
    ModbusBlockView *mb_tcp_blocks() const override { return const_cast<ModbusBlockView *>(&mbBlockView); }
    void mb_tcp_register(ModbusTCP *manager) override;

private:
    void populateMbRegisterBlocks();    // Removed component_id parameter
    void allocateAndPopulateMbBlocks(); // New helper combining allocation & population
    short configurePinModeInternal(E_GPIO_Pin pin, E_GPIO_Type type);
};

// -----------------------------------------------------------------------------
//  Helper to manage Modbus block allocation and population
// -----------------------------------------------------------------------------
inline void MB_GPIO::allocateAndPopulateMbBlocks()
{
    // Clear previous allocation if any
    delete[] mbRegisterBlocksData;
    mbRegisterBlocksData = nullptr;
    mbRegisterBlocksCount = 0;
    mbBlockView = {nullptr, 0};

    if (pinConfigs.empty()) { 
        clearNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS);
        return; 
    }

    setNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS);

    int mappedCount = 0;
    for (const auto &cfg : pinConfigs) 
    {
        if (cfg.startAddress != 0xFFFF)
            ++mappedCount;
    }
    if (mappedCount > 0)
    {
        mbRegisterBlocksCount = mappedCount;
        mbRegisterBlocksData = new MB_Registers[mappedCount];
        if (!mbRegisterBlocksData)
        {
            Log.fatalln("MB_GPIO %d: Failed to allocate Modbus blocks", id);
            mbRegisterBlocksCount = 0;
            clearNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS);
        }
        else
        {
            populateMbRegisterBlocks();
            mbBlockView = {mbRegisterBlocksData, mbRegisterBlocksCount};
        }
    } else {
         clearNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS);
    }
}

// -----------------------------------------------------------------------------
//  populateMbRegisterBlocks – uses internal pinConfigs Vector
// -----------------------------------------------------------------------------
inline void MB_GPIO::populateMbRegisterBlocks()
{
    if (!mbRegisterBlocksData || mbRegisterBlocksCount == 0)
        return;
    int idx = 0;
    for (const auto &cfg : pinConfigs) // Use direct member access
    {
        // L_INFO("MB_GPIO %d: Populating block %d, Address %u, Count %u, Type %u, Access %u", id, idx, cfg.startAddress, cfg.count, cfg.type, cfg.access);
        if (cfg.startAddress != 0xFFFF && idx < mbRegisterBlocksCount)
        {
            mbRegisterBlocksData[idx] = MB_Registers(
                cfg.startAddress, cfg.count, cfg.type, cfg.access,
                id, // Set the owner MB_GPIO component's ID
                cfg.slaveId, cfg.name, cfg.group, cfg.writeCallbackFn
                // No associatedPin in MB_Registers constructor
            );
            ++idx;
        }
    }
     if (idx != mbRegisterBlocksCount) {
        Log.warningln("MB_GPIO %d: Mismatch in Modbus block count. Expected %d, populated %d.", id, mbRegisterBlocksCount, idx);
    }
    mbRegisterBlocksCount = idx; // Use actual populated count
    mbBlockView.count = idx;
}

// -----------------------------------------------------------------------------
// Load method implementation - Can now modify internal pinConfigs
// -----------------------------------------------------------------------------
inline short MB_GPIO::load(const JsonObject &config)
{
    Log.verboseln("MB_GPIO::load - ID: %d", id);

    JsonArray pinsArray = config["pins"].as<JsonArray>();
    if (!pinsArray)
    {
        Log.warningln("MB_GPIO %d: JSON config missing 'pins' array or it's not an array. Clearing existing config.", id);
        pinConfigs.clear(); // Clear internal vector
    }
    else
    {
        L_INFO("MB_GPIO %d: Loading %zu pin configurations from JSON...", id, pinsArray.size());
        pinConfigs.clear(); // Clear internal vector before loading new ones
        pinConfigs.reserve(pinsArray.size()); // Reserve capacity

        for (JsonObject pinConfigJson : pinsArray)
        {
            // --- Parse individual pin config ---
            E_GPIO_Pin pinNum = (E_GPIO_Pin)pinConfigJson["pinNumber"].as<int>();  // Required
            E_GPIO_Type pinType = (E_GPIO_Type)pinConfigJson["pinType"].as<int>(); // Required

            ushort addr = pinConfigJson["modbusAddress"] | 0xFFFF; // Use default invalid address
            E_FN_CODE fn = (E_FN_CODE)(pinConfigJson["modbusFunction"] | (int)E_FN_CODE::FN_NONE);
            E_ModbusAccess acc = (E_ModbusAccess)(pinConfigJson["modbusAccess"] | (int)MB_ACCESS_NONE);
            uint32_t interval = pinConfigJson["opIntervalMs"] | 100; // Default interval
            const char *name = pinConfigJson["name"] | nullptr;
            const char *group = pinConfigJson["group"] | nullptr;

            // Basic validation (example)
            if (pinNum < E_GPIO_0 || pinNum > E_GPIO_48)
            {
                L_ERROR("MB_GPIO %d: Invalid pinNumber %d in config.", id, (int)pinNum);
                continue; // Skip this pin config
            }

            pinConfigs.emplace_back(pinNum, pinType, addr, fn, acc, interval, name, group); // Use emplace_back
        }
    }

    allocateAndPopulateMbBlocks(); // Re-create Modbus blocks from the new internal pinConfigs
    setup();                       // Re-apply pin modes based on the new internal pinConfigs

    L_INFO("MB_GPIO %d: Load complete. %d pins configured, %d Modbus blocks prepared.", id, pinConfigs.size(), mbRegisterBlocksCount);
    return E_OK;
}

// -----------------------------------------------------------------------------
//  setup / loop ---------------------------------------------------------------
// -----------------------------------------------------------------------------
inline short MB_GPIO::setup()
{
    for (const auto &cfg : pinConfigs) // Use direct member access
    {
        configurePinModeInternal(cfg.pinNumber, cfg.pinType);
    }
    return E_OK;
}

inline short MB_GPIO::loop()
{
    Component::loop();
    return E_OK;
}

inline short MB_GPIO::info(short flags, short val)
{
    Log.verboseln("MB_GPIO::info – ID %d, pins %d, NetCaps 0x%04X", id, (int)pinConfigs.size(), nFlags); // Use direct access
    for (size_t i = 0; i < pinConfigs.size(); ++i) // Use direct access
    {
        const auto &cfg = pinConfigs[i]; // Use direct access
        Log.verboseln(" [%d] Pin %d, Type %d, MB %u, Access %d, Intv %u, Last %ld, Cached %d",
                      (int)i, (int)cfg.pinNumber, (int)cfg.pinType, cfg.startAddress, (int)cfg.access,
                      cfg.opIntervalMs, cfg.lastOpTimestamp, cfg.cachedValue);
    }
    for(int i = 0; i < mbRegisterBlocksCount; ++i) {
       Log.verboseln("  - Block %d: Addr=%u, Cnt=%u, Type=%u, Acc=%u, Name=%s", i, mbRegisterBlocksData[i].startAddress, mbRegisterBlocksData[i].count, mbRegisterBlocksData[i].type, mbRegisterBlocksData[i].access, mbRegisterBlocksData[i].name ? mbRegisterBlocksData[i].name : "null");
    }
    return E_OK;
}

inline short MB_GPIO::serial_register(Bridge *bridge)
{
    Component::serial_register(bridge);
    bridge->registerMemberFunction(id, this, C_STR("info"), (ComponentFnPtr)&MB_GPIO::info);
    return E_OK;
}

// -----------------------------------------------------------------------------
//  Modbus read / write ---------------------------------------------------------
// -----------------------------------------------------------------------------
inline short MB_GPIO::mb_tcp_read(short address)
{
    if (!hasNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS))
        return E_INVALID_PARAMETER;

    const auto *cfg = findConfigByModbusAddress(address); // Uses internal pinConfigs
    if (!cfg){
         return 0;
    }
    if (cfg->access == MB_ACCESS_READ_ONLY || cfg->access == MB_ACCESS_READ_WRITE)
    {
        return readPinInternal(cfg->pinNumber, cfg->pinType);
    }
    return E_OK;
}

inline short MB_GPIO::mb_tcp_write(short address, short networkValue)
{
    if (!hasNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS))
        return E_INVALID_PARAMETER;

    GPIO_PinConfig *cfg = findConfigByModbusAddress(address);
    if (!cfg)
        return E_INVALID_PARAMETER;

    if (cfg->access == MB_ACCESS_WRITE_ONLY || cfg->access == MB_ACCESS_READ_WRITE)
    {
        return writePinInternal(*cfg, networkValue); // Pass the non-const config
    }
    Log.warningln("MB_GPIO %d: MB Write Addr %u (Pin %d) - Access denied (%d)", id, cfg->startAddress, static_cast<int>(cfg->pinNumber), static_cast<int>(cfg->access));
    return E_INVALID_PARAMETER;
}

inline void MB_GPIO::mb_tcp_register(ModbusTCP *manager) const
{
    if (!hasNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS) || !manager)
        return;
    if (!mbRegisterBlocksData || mbRegisterBlocksCount == 0)
        return;
    Component *self = const_cast<MB_GPIO *>(this);
    for (int i = 0; i < mbRegisterBlocksCount; ++i)
    {
        manager->registerModbus(self, mbRegisterBlocksData[i]);
    }
}

// -----------------------------------------------------------------------------
//  Helper to set pin‑mode ------------------------------------------------------
// -----------------------------------------------------------------------------
inline short MB_GPIO::configurePinModeInternal(E_GPIO_Pin pin, E_GPIO_Type type)
{
    switch (type)
    {
    case E_GPIO_TYPE_INPUT:
        pinMode((int)pin, INPUT);
        return E_OK;
    case E_GPIO_TYPE_OUTPUT:
        pinMode((int)pin, OUTPUT);
        return E_OK;
    case E_GPIO_TYPE_INPUT_PULLUP:
        pinMode((int)pin, INPUT_PULLUP);
        return E_OK;
    case E_GPIO_TYPE_OUTPUT_OPEN_DRAIN:
        pinMode((int)pin, OUTPUT_OPEN_DRAIN);
        return E_OK;
    case E_GPIO_TYPE_INPUT_PULLDOWN:
        return E_NOT_IMPLEMENTED;
    case E_GPIO_TYPE_ANALOG_INPUT:
    case E_GPIO_TYPE_TOUCH:
        return E_OK;
    default:
        L_ERROR("Unknown MB_GPIO type %d for pin %d", (int)type, (int)pin);
        return E_INVALID_PARAMETER;
    }
}
/*
// -----------------------------------------------------------------------------
//  Static map of pin capabilities (unchanged – omitted here for brevity)
// -----------------------------------------------------------------------------
// Define static capabilities map (if still needed)
inline const std::map<E_GPIO_Pin, uint32_t> MB_GPIO::pinCapabilities = {
    {E_GPIO_0, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_CLK_OUT3},
    {E_GPIO_1, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_CLK_OUT2},
    {E_GPIO_2, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_CLK_OUT1},
    {E_GPIO_3, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_JTAG_TDI | CAP_JTAG_TDO}, // Pinout shows TDO, schematic might show TDI
    {E_GPIO_4, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_JTAG_TCK},
    {E_GPIO_5, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_FSPI_CS0},
    {E_GPIO_6, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_FSPI_CLK},
    {E_GPIO_7, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_FSPI_MISO},
    {E_GPIO_8, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_I2C0_SDA},
    {E_GPIO_9, CAP_RTC | CAP_ADC1 | CAP_TOUCH | CAP_I2C0_SCL | CAP_FSPI_HD},
    {E_GPIO_10, CAP_RTC | CAP_ADC2 | CAP_TOUCH | CAP_FSPI_WP},
    {E_GPIO_11, CAP_RTC | CAP_ADC2 | CAP_TOUCH | CAP_FSPI_IO6},
    {E_GPIO_12, CAP_RTC | CAP_ADC2 | CAP_TOUCH | CAP_FSPI_IO7},
    {E_GPIO_13, CAP_RTC | CAP_ADC2 | CAP_TOUCH | CAP_FSPI_IO5},
    {E_GPIO_14, CAP_RTC | CAP_ADC2 | CAP_TOUCH | CAP_FSPI_IO4},
    {E_GPIO_15, CAP_RTC | CAP_ADC2 | CAP_UART0_RX},                                  // TOUCH? No. ADC2_5. XTAL_P. RTS0.
    {E_GPIO_16, CAP_RTC | CAP_ADC2 | CAP_UART0_TX},                                  // TOUCH? No. ADC2_6. XTAL_N. CTS0.
    {E_GPIO_17, CAP_RTC | CAP_ADC2 | CAP_UART1_RX},                                  // ADC2_7? No ADC2_6. RXD1
    {E_GPIO_18, CAP_RTC | CAP_ADC2 | CAP_UART1_TX},                                  // ADC2_7. TXD1
    {E_GPIO_19, CAP_RTC | CAP_ADC2 | CAP_USB_D_MINUS | CAP_CLK_OUT2 | CAP_UART2_RX}, // ADC2_8. RTS1.
    {E_GPIO_20, CAP_RTC | CAP_ADC2 | CAP_USB_D_PLUS | CAP_CLK_OUT1 | CAP_UART2_TX},  // ADC2_9. CTS1.
    {E_GPIO_21, CAP_RTC},
    {E_GPIO_35, CAP_RTC | CAP_ADC1},                // ADC1_7.
    {E_GPIO_36, CAP_RTC | CAP_ADC1 | CAP_FSPI_IO7}, // ADC1_8.
    {E_GPIO_37, CAP_RTC | CAP_ADC1 | CAP_FSPI_IO6}, // ADC1_9.
    {E_GPIO_38, CAP_RTC | CAP_FSPI_WP | CAP_LED_BUILTIN},
    {E_GPIO_39, CAP_RTC | CAP_CLK_OUT3 | CAP_JTAG_TCK}, // MTCK
    {E_GPIO_40, CAP_RTC | CAP_CLK_OUT2 | CAP_JTAG_TDO}, // MTDO
    {E_GPIO_41, CAP_RTC | CAP_CLK_OUT1 | CAP_JTAG_TDI}, // MTDI
    {E_GPIO_42, CAP_RTC | CAP_JTAG_TMS},                // MTMS
    {E_GPIO_43, CAP_UART0_TX},
    {E_GPIO_44, CAP_UART0_RX},
    {E_GPIO_45, CAP_NONE}, // VSPI, Strapping
    {E_GPIO_46, CAP_NONE}, // Strapping
    {E_GPIO_47, CAP_NONE}, // SPICLK_P
    {E_GPIO_48, CAP_NONE}  // SPICLK_N, RGB LED
};
*/
#endif // GPIO_H
