/*
 * 模块名称：Network Select Implementation
 * 模块功能：I/O 多路复用实现，包括 select 和 poll 两种模式，用于同时监控多个 Socket 的读写事件
 * 适用平台：STM32F407ZGTx + CH395F 以太网芯片
 * 作者：王建锋
 * 创建日期：2026-07-18
 * 修改记录：
 *     2026-07-18  王建锋  创建初始版本
 */

#include <string.h>
#include <stdio.h>

#include "cmsis_os.h"  /* CMSIS-RTOS2 API: osDelay() */
#include "FreeRTOS.h"
#include "task.h"

#include "net_select.h"
#include "net_socket.h"
#include "ch395f.h"
#include "main.h"

/*
 * 私有函数声明区
 */

static int check_socket_readable(int sockfd);
static int check_socket_writable(int sockfd);
static int check_socket_error(int sockfd);

/*
 * 公共函数实现区
 */

/*
 * 函数功能：I/O 多路复用（select 模式），等待多个 Socket 的读写事件就绪
 * 入口参数：nfds     - 最大文件描述符数 +1                                       int    > 0
 *           readfds  - 读事件集合指针                                           net_fd_set *（可为 NULL）
 *           writefds - 写事件集合指针                                           net_fd_set *（可为 NULL）
 *           exceptfds- 异常事件集合指针                                         net_fd_set *（可为 NULL）
 *           timeout  - 超时时间结构体指针                                       net_timeval *（NULL=无限等待）
 * 出口参数：readfds/writefds/exceptfds - 仅保留就绪的 Socket 位                  net_fd_set *
 * 返回值：就绪的 Socket 数量（>= 0）；-1 表示参数无效                           int
 * 限定条件：net_init() + MX_FREERTOS_Init() 已执行；必须在 netTask 上下文中调用
 * 函数说明：1. 轮询所有 Socket，检查读/写/异常事件是否就绪
 *           2. 阻塞等待直到有事件就绪或超时
 *           3. 通过 osDelay(1) 让出 CPU，平衡实时性与 CPU 利用率
 */
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
               net_fd_set *exceptfds, net_timeval *timeout) {
    uint32_t start_tick;
    uint32_t timeout_ms = 0;
    net_fd_set result_read = {0};
    net_fd_set result_write = {0};
    net_fd_set result_except = {0};
    int ready_count = 0;
    int i;

    /* 检查输入参数合法性 */
    if ((0 >= nfds) || (NET_MAX_SOCKETS < nfds)) {
        return -1;
    }

    /* 计算超时时间（毫秒） */
    if (NULL != timeout) {
        timeout_ms = (uint32_t)(timeout->tv_sec * 1000) +
                     (uint32_t)(timeout->tv_usec / 1000);
    }

    start_tick = HAL_GetTick();

    while (1) {
        /* 轮询所有 Socket */
        net_poll();

        ready_count = 0;

        /* 检查哪个 Socket 有事件 */
        for (i = 0; i < nfds && i < NET_MAX_SOCKETS; i++) {
            net_sock_t *p_sock = net_get_sock(i);

            if (NULL == p_sock) {
                continue;
            }

            /* 检查可读事件 */
            if ((NULL != readfds) && NET_FD_ISSET(i, readfds)) {
                if (check_socket_readable(i)) {
                    NET_FD_SET(i, &result_read);
                    ready_count++;
                }
            }

            /* 检查可写事件 */
            if ((NULL != writefds) && NET_FD_ISSET(i, writefds)) {
                if (check_socket_writable(i)) {
                    NET_FD_SET(i, &result_write);
                    ready_count++;
                }
            }

            /* 检查异常事件 */
            if ((NULL != exceptfds) && NET_FD_ISSET(i, exceptfds)) {
                if (check_socket_error(i)) {
                    NET_FD_SET(i, &result_except);
                    ready_count++;
                }
            }
        }

        /* 有事件就绪，返回 */
        if (0 < ready_count) {
            break;
        }

        /* 超时检测 */
        if (NULL != timeout) {
            if ((0 < timeout_ms) &&
                ((HAL_GetTick() - start_tick) >= timeout_ms)) {
                break;  /* 超时返回 0 */
            }
        }

        /* 让出 CPU：FreeRTOS osDelay() 会正确进入休眠，允许其他任务运行 */
        osDelay(1);  /* 1ms 周期轮询，平衡实时性和 CPU 利用率 */
    }

    /* 复制结果集合 */
    if (NULL != readfds) {
        readfds->fd_bits = result_read.fd_bits;
    }
    if (NULL != writefds) {
        writefds->fd_bits = result_write.fd_bits;
    }
    if (NULL != exceptfds) {
        exceptfds->fd_bits = result_except.fd_bits;
    }

    return ready_count;
}

/*
 * 函数功能：I/O 多路复用（poll 模式），等待多个 Socket 的读写事件就绪
 * 入口参数：fds     - pollfd 数组指针                                          net_pollfd *
 *           nfds    - 数组元素数量                                              int    > 0
 *           timeout - 超时时间（毫秒）                                          int    >= 0（-1=无限等待，但本实现按 >=0 处理）
 * 出口参数：fds[i].revents - 填充实际发生的事件掩码                            short
 * 返回值：就绪的 fd 数量（>= 0）；-1 表示参数无效                              int
 * 限定条件：net_init() + MX_FREERTOS_Init() 已执行；必须在 netTask 上下文中调用
 * 函数说明：1. 轮询所有 Socket，检查读/写/错误/挂起事件是否就绪
 *           2. 阻塞等待直到有事件就绪或超时
 *           3. 通过 osDelay(1) 让出 CPU，平衡实时性与 CPU 利用率
 */
int net_poll_events(net_pollfd *fds, int nfds, int timeout) {
    uint32_t start_tick;
    int ready = 0;
    int i;

    if ((NULL == fds) || (0 >= nfds)) {
        return -1;
    }

    start_tick = HAL_GetTick();

    while (1) {
        /* 轮询 */
        net_poll();

        ready = 0;

        for (i = 0; i < nfds; i++) {
            fds[i].revents = 0;

            /* 检查 fd 有效性 */
            if ((0 > fds[i].fd) || (NET_MAX_SOCKETS <= fds[i].fd)) {
                fds[i].revents |= NET_POLLNVAL;
                ready++;
                continue;
            }

            net_sock_t *p_sock = net_get_sock(fds[i].fd);

            if (NULL == p_sock) {
                fds[i].revents |= NET_POLLNVAL;
                ready++;
                continue;
            }

            /* 检查可读 */
            if (fds[i].events & NET_POLLIN) {
                if (check_socket_readable(fds[i].fd)) {
                    fds[i].revents |= NET_POLLIN;
                    ready++;
                }
            }

            /* 检查可写 */
            if (fds[i].events & NET_POLLOUT) {
                if (check_socket_writable(fds[i].fd)) {
                    fds[i].revents |= NET_POLLOUT;
                    ready++;
                }
            }

            /* 检查错误 */
            if (check_socket_error(fds[i].fd)) {
                fds[i].revents |= NET_POLLERR;
                ready++;
            }

            /* 检查挂起（连接断开） */
            if (NET_SOCK_STATE_CLOSED == p_sock->state) {
                fds[i].revents |= NET_POLLHUP;
                ready++;
            }
        }

        if (0 < ready) {
            break;
        }

        /* 超时检测 */
        if (0 <= timeout) {
            if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout) {
                break;
            }
        }

        /* 让出 CPU：FreeRTOS osDelay() 会正确进入休眠，允许其他任务运行 */
        osDelay(1);  /* 1ms 周期轮询，平衡实时性和 CPU 利用率 */
    }

    return ready;
}

/*
 * 私有函数实现区
 */

/*
 * 函数功能：检查指定 Socket 当前是否可读
 * 入口参数：sockfd - 待检查的 Socket 描述符                                int    0 - NET_MAX_SOCKETS-1
 * 出口参数：无
 * 返回值：1 - 可读（监听态有新连接，或已连接态接收缓冲非空）；0 - 不可读或描述符无效  int
 * 限定条件：net_init() 已调用
 * 函数说明：1. 监听态 Socket 视为可读（存在可 accept 的新连接）
 *           2. 已建立连接且接收缓冲区长度大于 0 时视为可读
 */
static int check_socket_readable(int sockfd) {
    net_sock_t *p_sock;
    uint16_t recv_len;

    p_sock = net_get_sock(sockfd);
    if (NULL == p_sock) {
        return 0;
    }

    /* 监听 Socket 有新连接时可读 */
    if (NET_SOCK_STATE_LISTENING == p_sock->state) {
        return 1;
    }

    /* 已建立连接的 Socket 有数据可读 */
    if (NET_SOCK_STATE_ESTABLISHED == p_sock->state) {
        recv_len = ch395f_get_recv_len(sockfd);
        if (0 < recv_len) {
            return 1;
        }
    }

    return 0;
}

/*
 * 函数功能：检查指定 Socket 当前是否可写
 * 入口参数：sockfd - 待检查的 Socket 描述符                                int    0 - NET_MAX_SOCKETS-1
 * 出口参数：无
 * 返回值：1 - 可写（已连接且发送缓冲空闲）；0 - 不可写或描述符无效        int
 * 限定条件：net_init() 已调用
 * 函数说明：1. 仅已建立连接且 send_ready 标志置位的 Socket 视为可写
 */
static int check_socket_writable(int sockfd) {
    net_sock_t *p_sock;

    p_sock = net_get_sock(sockfd);
    if (NULL == p_sock) {
        return 0;
    }

    /* 已建立连接的 Socket 发送缓冲区空闲时可写 */
    if (NET_SOCK_STATE_ESTABLISHED == p_sock->state) {
        if (p_sock->send_ready) {
            return 1;
        }
    }

    return 0;
}

/*
 * 函数功能：检查指定 Socket 是否存在错误状态
 * 入口参数：sockfd - 待检查的 Socket 描述符                                int    0 - NET_MAX_SOCKETS-1
 * 出口参数：无
 * 返回值：1 - 有错误（含描述符越界或 Socket 未分配）；0 - 无错误          int
 * 限定条件：无
 * 函数说明：1. 描述符越界视为错误
 *           2. 未分配（net_get_sock 返回 NULL）的 Socket 视为错误
 */
static int check_socket_error(int sockfd) {
    net_sock_t *p_sock;

    /* 无效 fd 视为错误 */
    if ((0 > sockfd) || (NET_MAX_SOCKETS <= sockfd)) {
        return 1;
    }

    p_sock = net_get_sock(sockfd);
    if (NULL == p_sock) {
        return 1;  /* 未使用的 Socket 视为错误 */
    }

    return 0;
}
