/*
 * STM32F4以太网硬件抽象层实现
 * 功能：实现STM32F4平台的以太网硬件抽象层
 * 依赖硬件：STM32F407VE
 * 跨平台适配点：通过硬件抽象层接口适配不同平台
 */

#include "hal.h"
#include "stm32f4xx_hal.h"
#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/timeouts.h"
#include "netif/etharp.h"
#include "lwip/ethip6.h"
#include <string.h>

/* 以太网句柄 */
static ETH_HandleTypeDef heth;
static uint32_t g_phy_address = 0; /* 存储PHY地址 */
static uint32_t g_last_link_check_time = 0; /* 上次链接状态检测时间 */
static uint32_t g_link_check_interval = 1000; /* 链接状态检测间隔 (ms) */
static uint8_t g_link_state_stable = 0; /* 链接状态稳定性标志 */
static uint8_t g_link_state_counter = 0; /* 链接状态计数器，用于防抖 */

/* DMA描述符和缓冲区 */
/* 优化缓冲区对齐方式，提高内存访问效率 */
__attribute__((section(".RxDecripSection"))) __attribute__((aligned(32))) static ETH_DMADescTypeDef  DMARxDscrTab[ETH_RXBUFNB];
__attribute__((section(".TxDecripSection"))) __attribute__((aligned(32))) static ETH_DMADescTypeDef  DMATxDscrTab[ETH_TXBUFNB];
__attribute__((section(".RxArraySection"))) __attribute__((aligned(32))) static uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];
__attribute__((section(".TxArraySection"))) __attribute__((aligned(32))) static uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE];

/* 信号量 */
static osal_sem_t s_xSemaphore = NULL;

/**
 * @brief  检测并配置PHY
 * @return HAL_StatusTypeDef: 操作结果
 * @note   负责检测PHY地址并进行配置
 */
static hal_status_t detect_and_configure_phy(void)
{
    uint32_t phy_id1 = 0, phy_id2 = 0;
    uint8_t detected_phy_addr = 0xFF; /* 无效的初始值 */
    uint32_t regvalue;
    
    /* 优先检查常见的PHY地址，减少遍历次数 */
    uint8_t common_phy_addresses[] = {0, 1, 2, 3, 16, 17, 18, 19, 20};
    uint8_t common_phy_count = sizeof(common_phy_addresses) / sizeof(common_phy_addresses[0]);
    
    /* 先检查常见地址 */
    for(uint8_t i = 0; i < common_phy_count; i++) {
        uint8_t addr = common_phy_addresses[i];
        /* 读取PHY ID寄存器（通常是Reg 2和3） */
        if(HAL_ETH_ReadPHYRegister(&heth, addr, 2, &phy_id1) == HAL_OK &&
           HAL_ETH_ReadPHYRegister(&heth, addr, 3, &phy_id2) == HAL_OK) {
            if((phy_id1 != 0xFFFF) && (phy_id1 != 0x0000) && (phy_id1 != 0)) {
                detected_phy_addr = addr;
                osal_log_i("Found PHY at Address %d (ID: %04x %04x)", addr, phy_id1, phy_id2);
                goto phy_found;
            }
        }
    }
    
    /* 如果常见地址没找到，再遍历所有可能的地址 */
    for(uint8_t addr = 0; addr <= 31; addr++) {
        /* 跳过已经检查过的常见地址 */
        uint8_t skip = 0;
        for(uint8_t i = 0; i < common_phy_count; i++) {
            if(addr == common_phy_addresses[i]) {
                skip = 1;
                break;
            }
        }
        if(skip) continue;
        
        /* 读取PHY ID寄存器（通常是Reg 2和3） */
        if(HAL_ETH_ReadPHYRegister(&heth, addr, 2, &phy_id1) == HAL_OK &&
           HAL_ETH_ReadPHYRegister(&heth, addr, 3, &phy_id2) == HAL_OK) {
            if((phy_id1 != 0xFFFF) && (phy_id1 != 0x0000) && (phy_id1 != 0)) {
                detected_phy_addr = addr;
                osal_log_i("Found PHY at Address %d (ID: %04x %04x)", addr, phy_id1, phy_id2);
                goto phy_found;
            }
        }
    }
    
phy_found:
    
    if (detected_phy_addr != 0xFF)
    {
        g_phy_address = detected_phy_addr;
        
        /* PHY软复位 */
        osal_log_i("Resetting PHY at address %d...", g_phy_address);
        /* 写入复位位 */
        HAL_ETH_WritePHYRegister(&heth, g_phy_address, PHY_BCR, PHY_RESET);
        
        /* 等待复位完成 */
        uint32_t tickstart = osal_tick_get();
        uint32_t reset_timeout = 200; // 优化为200ms超时
        do {
            HAL_ETH_ReadPHYRegister(&heth, g_phy_address, PHY_BCR, &regvalue);
            if((regvalue & PHY_RESET) == 0) break;
        } while ((osal_tick_get() - tickstart) < reset_timeout); // 200ms超时
        
        /* 添加延迟以确保PHY稳定 */
        osal_thread_mdelay(50); // 优化为50ms延迟
        return HAL_STATUS_OK;
    }
    else
    {
        osal_log_e("No PHY found!");
        return HAL_STATUS_ERROR;
    }
}

/**
 * @brief  配置MAC
 * @param  macConf: MAC配置结构体指针
 * @return 无
 * @note   负责配置MAC的双工模式、速度和校验和等
 */
static void configure_mac(ETH_MACConfigTypeDef *macConf)
{
    HAL_ETH_GetMACConfig(&heth, macConf);
    macConf->DuplexMode = ETH_FULLDUPLEX_MODE;
    macConf->Speed = ETH_SPEED_100M;
    macConf->ChecksumOffload = ENABLE; /* 启用硬件校验和 */
    HAL_ETH_SetMACConfig(&heth, macConf);
}

/**
 * @brief  以太网初始化
 * @return hal_status_t: 操作结果
 * @note   初始化以太网硬件
 */
static hal_status_t stm32f4_eth_init(void)
{
    /* 使用固定MAC地址避免冲突/过滤 */
    uint8_t macaddress[6] = { 0x00, 0x80, 0xE1, 0x00, 0x00, 0x55 };
    ETH_MACConfigTypeDef macConf;
    HAL_StatusTypeDef hal_eth_init_status;
    
    osal_log_i("MAC: %02x:%02x:%02x:%02x:%02x:%02x", 
        macaddress[0], macaddress[1], macaddress[2], 
        macaddress[3], macaddress[4], macaddress[5]);

    /* 初始化ETH句柄 */
    heth.Instance = ETH;
    heth.Init.MACAddr = macaddress;
    heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
    heth.Init.TxDesc = DMATxDscrTab;
    heth.Init.RxDesc = DMARxDscrTab;
    heth.Init.RxBuffLen = ETH_RX_BUF_SIZE;
    
    /* 初始化ETH（MAC、DMA、GPIO通过MSP）以启用MDC/MDIO */
    hal_eth_init_status = HAL_ETH_Init(&heth);

    if (hal_eth_init_status == HAL_OK)
    {
        /* 检测并配置PHY */
        if (detect_and_configure_phy() == HAL_STATUS_OK)
        {
            /* 配置MAC */
            configure_mac(&macConf);

            /* 手动启用混杂模式，因为它不在结构体中 */
            heth.Instance->MACFFR |= ETH_MACFFR_PM;

            /* 启动ETH中断 */
            HAL_ETH_Start_IT(&heth);
            
            /* 创建信号量 */
            s_xSemaphore = osal_sem_create("eth_sem", 0);
            
            return HAL_STATUS_OK;
        }
    }
    else
    {
        osal_log_e("HAL_ETH_Init failed");
    }
    
    return HAL_STATUS_ERROR;
}

/**
 * @brief  以太网反初始化
 * @return hal_status_t: 操作结果
 * @note   反初始化以太网硬件
 */
static hal_status_t stm32f4_eth_deinit(void)
{
    /* 停止ETH */
    HAL_ETH_Stop(&heth);
    
    /* 反初始化ETH */
    if (HAL_ETH_DeInit(&heth) != HAL_OK) {
        return HAL_STATUS_ERROR;
    }
    
    /* 删除信号量 */
    if (s_xSemaphore != NULL) {
        osal_sem_delete(s_xSemaphore);
        s_xSemaphore = NULL;
    }
    
    return HAL_STATUS_OK;
}

/**
 * @brief  以太网发送数据
 * @param  data: 数据指针
 * @param  len: 数据长度
 * @return hal_status_t: 操作结果
 * @note   发送数据
 */
static hal_status_t stm32f4_eth_send(const uint8_t *data, uint32_t len)
{
    ETH_TxPacketConfigTypeDef txConfig;
    ETH_BufferTypeDef txBuffer;
    
    memset(&txConfig, 0, sizeof(ETH_TxPacketConfigTypeDef));
    /* 启用硬件校验和插入 */
    txConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
    txConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
    txConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
    
    txBuffer.buffer = (uint8_t*)data;
    txBuffer.len = len;
    txBuffer.next = NULL;
    
    txConfig.Length = len;
    txConfig.TxBuffer = &txBuffer;

    if (HAL_ETH_Transmit(&heth, &txConfig, 10) == HAL_OK) {
        return HAL_STATUS_OK;
    } else {
        return HAL_STATUS_ERROR;
    }
}

/**
 * @brief  以太网接收数据
 * @param  data: 数据指针
 * @param  len: 数据长度指针
 * @param  timeout: 超时时间
 * @return hal_status_t: 操作结果
 * @note   接收数据
 */
static hal_status_t stm32f4_eth_recv(uint8_t *data, uint32_t *len, uint32_t timeout)
{
    uint8_t *buffer = NULL;
    uint32_t rxLength = 0;
    
    if (s_xSemaphore == NULL) {
        return HAL_STATUS_ERROR;
    }
    
    if (osal_sem_take(s_xSemaphore, timeout) != OSAL_OK) {
        return HAL_STATUS_TIMEOUT;
    }
    
    if (HAL_ETH_ReadData(&heth, (void**)&buffer) == HAL_OK)
    {
        /* Get the received frame length from Rx descriptor list */
        rxLength = heth.RxDescList.RxDataLength;
        
        if (rxLength > 0 && buffer != NULL && data != NULL && len != NULL) {
            memcpy(data, buffer, rxLength);
            *len = rxLength;
            return HAL_STATUS_OK;
        }
    }
    
    return HAL_STATUS_ERROR;
}

/**
 * @brief  获取以太网链接状态
 * @return hal_status_t: 操作结果
 * @note   获取以太网链接状态
 */
static hal_status_t stm32f4_eth_get_link_status(void)
{
    uint32_t regvalue = 0;
    uint32_t current_time = osal_tick_get();

    /* 实现时间间隔控制，减少PHY寄存器读取 */
    if ((current_time - g_last_link_check_time) < g_link_check_interval)
    {
        return g_link_state_stable ? HAL_STATUS_OK : HAL_STATUS_ERROR;
    }
    g_last_link_check_time = current_time;

    /* 检查PHY地址是否有效 */
    if (g_phy_address == 0 || g_phy_address > 31) {
        osal_log_e("Invalid PHY address: %d", g_phy_address);
        g_link_state_stable = 0;
        g_link_state_counter = 0;
        return HAL_STATUS_ERROR;
    }

    /* 使用配置的PHY地址读取状态寄存器 */
    HAL_StatusTypeDef status = HAL_ETH_ReadPHYRegister(&heth, g_phy_address, PHY_BSR, &regvalue);
    if (status != HAL_OK) {
        osal_log_e("Failed to read PHY register, status=%d", status);
        g_link_state_counter--;
        if (g_link_state_counter <= 0) {
            g_link_state_counter = 0;
            g_link_state_stable = 0;
        }
        return HAL_STATUS_ERROR;
    }

    osal_log_i("PHY BSR=0x%04x, LinkStatus=%d", regvalue, (regvalue & PHY_LINKED_STATUS) != 0);

    if ((regvalue & PHY_LINKED_STATUS) != 0)
    {
        /* 链接状态防抖 */
        g_link_state_counter++;
        if (g_link_state_counter >= 3) /* 连续3次检测到链接状态为up */
        {
            g_link_state_stable = 1;
        }
        return HAL_STATUS_OK;
    }
    else
    {
        /* 链接状态防抖 */
        g_link_state_counter--;
        if (g_link_state_counter <= 0) /* 连续3次检测到链接状态为down */
        {
            g_link_state_counter = 0;
            g_link_state_stable = 0;
        }
        return HAL_STATUS_ERROR;
    }
}

/* 以太网硬件抽象层操作结构体 */
const hal_eth_ops_t stm32f4_eth_ops = {
    .init = stm32f4_eth_init,
    .deinit = stm32f4_eth_deinit,
    .send = stm32f4_eth_send,
    .recv = stm32f4_eth_recv,
    .get_link_status = stm32f4_eth_get_link_status
};

/**
 * @brief  以太网Rx完成回调
 * @param  heth: 以太网句柄
 * @return 无
 * @note   以太网接收完成回调函数
 */
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
    (void)heth;
    if (s_xSemaphore != NULL)
    {
        osal_sem_release(s_xSemaphore);
    }
}

/**
 * @brief  以太网Rx分配回调
 * @param  buff: 缓冲区指针
 * @return 无
 * @note   以太网接收缓冲区分配回调函数
 */
void HAL_ETH_RxAllocateCallback(uint8_t **buff)
{
    static int rx_idx = 0;
    *buff = Rx_Buff[rx_idx];
    rx_idx = (rx_idx + 1) % ETH_RXBUFNB;
}

/**
 * @brief  以太网Rx链接回调
 * @param  pStart: 开始指针
 * @param  pEnd: 结束指针
 * @param  buff: 缓冲区指针
 * @param  Length: 长度
 * @return 无
 * @note   以太网接收链接回调函数
 */
void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
{
    (void)Length;
    *pStart = (void *)buff;
    *pEnd = (void *)buff;
}

/**
 * @brief  以太网中断处理函数
 * @return 无
 * @note   以太网中断处理函数
 */
void ETH_IRQHandler(void)
{
    /* 直接调用HAL中断处理函数，不使用全局临界区
     * HAL_ETH_IRQHandler内部已经有适当的中断保护机制
     */
    HAL_ETH_IRQHandler(&heth);
}

/**
 * @brief  以太网MSP初始化
 * @param  heth: 以太网句柄
 * @return 无
 * @note   初始化以太网的MSP
 */
void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
    (void)heth;
    GPIO_InitTypeDef GPIO_InitStructure;

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_SYSCFG_CLK_ENABLE();

    __HAL_RCC_ETH_CLK_ENABLE();

    /* PA1, PA2, PA7 */
    GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* PC1, PC4, PC5 */
    GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);

    /* PB11, PB12, PB13 */
    GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    HAL_NVIC_SetPriority(ETH_IRQn, 0x07, 0);
    HAL_NVIC_EnableIRQ(ETH_IRQn);
}