/*
 * 模块名称：Network Socket API
 * 模块功能：BSD Socket API 兼容接口，提供 TCP/UDP 网络通信功能，
 *          底层基于 CH395F 以太网协议栈芯片
 * 适用平台：STM32F4 系列（CH395F 以太网芯片）
 * 作者：王建锋
 * 创建日期：2026-07-18
 * 修改记录：
 */

#ifndef __NET_SOCKET_H
#define __NET_SOCKET_H

#ifdef __cplusplus
extern "C" {
#endif

#include "net_types.h"
#include "FreeRTOS.h"
#include "task.h"

/*
 * 消息队列类型定义
 */
typedef enum {
    NET_MSG_SEND,
    NET_MSG_RECV,
    NET_MSG_CLOSE,
    NET_MSG_CONNECT,
    NET_MSG_LISTEN,
    NET_MSG_ACCEPT,
} net_msg_type_t;

typedef struct {
    net_msg_type_t  type;           /* 操作类型 */
    int             sockfd;         /* Socket 描述符 */
    void           *buf;            /* 数据缓冲区（send/recv） */
    int             len;            /* 数据长度/缓冲区大小 */
    int             flags;          /* 接收标志 */
    TaskHandle_t    caller;         /* 调用方任务句柄 */
    int             result;         /* 操作结果 */
    /* 连接参数 */
    struct net_sockaddr_in  addr;   /* 连接地址 */
    int             addrlen;        /* 地址长度 */
} net_msg_t;

/*
 * 网络初始化接口
 */

/*
 * 函数功能：网络子系统初始化（配置 CH395F + 启用多连接模式）
 * 入口参数：ip       - 本地 IP 地址字符串 "192.168.1.100"，NULL 使用 DHCP
 *          mask     - 子网掩码字符串 "255.255.255.0"，NULL 使用默认
 *          gateway  - 网关地址字符串 "192.168.1.1"，NULL 使用默认
 * 返回值：0 成功，-1 失败
 * 限定条件：SPI2 已正确初始化
 * 函数说明：必须在所有网络操作之前调用
 */
int net_init(const char *ip, const char *mask, const char *gateway);

/*
 * 函数功能：轮询所有 Socket 状态（必须在主循环中调用）
 * 返回值：有事件发生的 socket 数量
 * 限定条件：net_init() 已调用
 * 函数说明：此函数处理所有 Socket 的中断事件，更新状态，
 *          并触发事件回调。在非阻塞模式下必须定期调用。
 */
int net_poll(void);

/*
 * 核心 Socket API
 */

/*
 * 函数功能：创建 socket
 * 入口参数：domain   - 地址族，仅支持 AF_INET
 *          type     - SOCK_STREAM(TCP) 或 SOCK_DGRAM(UDP)
 *          protocol - 通常为 0
 * 返回值：socket 描述符 (0~7)，失败返回 -1
 * 限定条件：net_init() 已调用
 * 函数说明：自动分配空闲 Socket 控制块
 */
int net_socket(int domain, int type, int protocol);

/*
 * 函数功能：绑定本地地址和端口
 * 入口参数：sockfd   - socket 描述符
 *          addr     - 本地地址结构体指针
 *          addrlen  - 地址结构体长度
 * 返回值：0 成功，-1 失败
 * 限定条件：socket 已创建且未绑定
 * 函数说明：设置 CH395F 源端口
 */
int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);

/*
 * 函数功能：TCP Server 监听
 * 入口参数：sockfd   - socket 描述符
 * 返回值：0 成功，-1 失败
 * 限定条件：socket 已绑定
 * 函数说明：内部调用 ch395f_tcp_listen，监听 Socket 自身即为数据通道
 */
int net_listen(int sockfd);

/*
 * 函数功能：TCP Server 接受连接
 * 入口参数：sockfd   - 监听 socket 描述符
 *          addr     - 输出：客户端地址
 *          addrlen  - 输入输出：地址长度
 * 返回值：新 socket 描述符，失败返回 -1
 * 限定条件：socket 正在监听
 * 函数说明：在非阻塞模式下，如果没有新连接，返回 -1 并设置
 *          net_errno 为 NET_ERR_WOULDBLOCK
 */
int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen);

/*
 * 函数功能：TCP Client 发起连接
 * 入口参数：sockfd   - socket 描述符
 *          addr     - 服务器地址
 *          addrlen  - 地址长度
 * 返回值：0 成功，-1 失败
 * 限定条件：socket 已创建
 * 函数说明：连接过程是异步的，需要调用 net_poll() 等待连接完成，
 *          或使用 select() 等待可写事件
 */
int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen);

/*
 * 函数功能：发送数据（TCP）
 * 入口参数：sockfd  - socket 描述符
 *          buf     - 数据缓冲区
 *          len     - 数据长度
 *          flags   - 通常为 0
 * 返回值：实际发送字节数，失败返回 -1
 * 限定条件：TCP 连接已建立，指针非空
 * 函数说明：阻塞等待发送缓冲区空闲，拷贝数据后触发发送
 */
int net_send(int sockfd, const void *buf, int len, int flags);

/*
 * 函数功能：接收数据（TCP）
 * 入口参数：sockfd  - socket 描述符
 *          buf     - 接收缓冲区
 *          len     - 缓冲区大小
 *          flags   - 通常为 0，可设置 NET_MSG_DONTWAIT 非阻塞
 * 返回值：实际接收字节数，0=对端关闭，-1=错误
 * 限定条件：TCP 连接已建立
 * 函数说明：在阻塞模式下，如果没有数据，函数会等待；
 *          在非阻塞模式下，如果没有数据，返回 -1 并设置
 *          net_errno 为 NET_ERR_WOULDBLOCK
 */
int net_recv(int sockfd, void *buf, int len, int flags);

/*
 * 函数功能：发送 UDP 数据
 * 入口参数：sockfd    - socket 描述符
 *          buf       - 数据缓冲区
 *          len       - 数据长度
 *          flags     - 通常为 0
 *          dest_addr - 目标地址
 *          addrlen   - 地址长度
 * 返回值：实际发送字节数，失败返回 -1
 * 限定条件：socket 已创建，指针非空
 * 函数说明：设置目标地址后调用 CH395F 发送
 */
int net_sendto(int sockfd, const void *buf, int len, int flags,
               const struct net_sockaddr *dest_addr, int addrlen);

/*
 * 函数功能：接收 UDP 数据
 * 入口参数：sockfd   - socket 描述符
 *          buf      - 接收缓冲区
 *          len      - 缓冲区大小
 *          flags    - 通常为 0
 *          src_addr - 输出：发送方地址
 *          addrlen  - 输入输出：地址长度
 * 返回值：实际接收字节数，失败返回 -1
 * 限定条件：socket 已创建，指针非空
 * 函数说明：读取 CH395F 接收缓冲区，获取对端地址
 */
int net_recvfrom(int sockfd, void *buf, int len, int flags,
                 struct net_sockaddr *src_addr, int *addrlen);

/*
 * 函数功能：关闭 socket
 * 入口参数：sockfd - socket 描述符
 * 返回值：0 成功，-1 失败
 * 限定条件：socket 已打开
 * 函数说明：释放 Socket 控制块，TCP 先断开连接
 */
int net_close(int sockfd);

/*
 * 事件回调 API
 */

/*
 * 函数功能：注册事件回调
 * 入口参数：sockfd - socket 描述符
 *          cb     - 回调函数
 *          arg    - 用户参数
 * 返回值：0 成功，-1 失败
 * 限定条件：socket 已创建
 * 函数说明：回调在 net_poll 上下文中触发
 */
int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg);

/*
 * 辅助函数
 */

/*
 * 函数功能：获取 socket 最后错误码
 * 返回值：错误码（NET_ERR_xxx）
 */
int net_get_errno(void);

/*
 * 函数功能：将 IP 地址字符串转为网络字节序
 * 入口参数：cp - 点分十进制字符串 "192.168.1.100"
 * 返回值：网络字节序 IP，失败返回 0
 * 限定条件：cp 指针非空
 * 函数说明：不支持域名解析
 */
uint32_t net_inet_addr(const char *cp);

/*
 * 函数功能：将网络字节序 IP 转为字符串
 * 入口参数：addr - 网络字节序 IP
 *          buf  - 输出缓冲区（至少 16 字节）
 * 返回值：buf 指针
 * 限定条件：buf 指针非空
 */
char *net_inet_ntoa(uint32_t addr, char *buf);

/*
 * 函数功能：端口字节序转换（主机序 -> 网络序）
 * 入口参数：hostshort - 主机序端口
 * 返回值：网络序端口
 * 限定条件：无
 * 函数说明：小端 → 大端
 */
uint16_t net_htons(uint16_t hostshort);

/*
 * 函数功能：端口字节序转换（网络序 -> 主机序）
 * 入口参数：netshort - 网络序端口
 * 返回值：主机序端口
 * 限定条件：无
 * 函数说明：大端 → 小端
 */
uint16_t net_ntohs(uint16_t netshort);

/*
 * 函数功能：IP 地址字节序转换（主机序 -> 网络序）
 * 入口参数：hostlong - 主机序 IP
 * 返回值：网络序 IP
 * 限定条件：无
 * 函数说明：小端 → 大端
 */
uint32_t net_htonl(uint32_t hostlong);

/*
 * 函数功能：IP 地址字节序转换（网络序 -> 主机序）
 * 入口参数：netlong - 网络序 IP
 * 返回值：主机序 IP
 * 限定条件：无
 * 函数说明：大端 → 小端
 */
uint32_t net_ntohl(uint32_t netlong);

/*
 * 函数功能：处理消息队列中的请求（必须在 netTask 主循环中调用）
 * 限定条件：net_init() 已调用
 * 函数说明：处理其他任务通过 net_send/net_recv 等接口发送的请求，
 *          在 netTask 上下文中串行化执行所有 CH395F 操作
 */
void net_process_messages(void);

/*
 * 函数功能：获取 Socket 控制块指针（内部使用）
 * 入口参数：sockfd - socket 描述符
 * 返回值：Socket 控制块指针，失败返回 NULL
 */
net_sock_t *net_get_sock(int sockfd);

/*
 * 函数功能：获取 Socket 本地地址（IP + Port）
 * 入口参数：sockfd  - socket 描述符
 *          addr    - 输出：本地地址
 *          addrlen - 输入输出：地址结构体长度
 * 返回值：0 成功，-1 失败
 * 限定条件：socket 已创建或已绑定
 */
int net_getsockname(int sockfd, struct net_sockaddr *addr, int *addrlen);

/*
 * 内部 API（需在 netTask 上下文中调用，绕过消息队列）
 */

/*
 * 函数功能：发送数据（内部版本，直接操作，不经过消息队列）
 * 入口参数：p_sock - Socket 控制块指针
 *          buf    - 数据缓冲区
 *          len    - 数据长度
 * 返回值：实际发送字节数，失败返回 -1
 * 限定条件：必须在 netTask 上下文中调用
 */
int net_send_sock(net_sock_t *p_sock, const void *buf, int len);

/*
 * 函数功能：接收数据（内部版本，直接操作，不经过消息队列）
 * 入口参数：p_sock - Socket 控制块指针
 *          buf    - 接收缓冲区
 *          len    - 缓冲区大小
 *          flags  - 通常为 0，可设置 NET_MSG_DONTWAIT
 * 返回值：实际接收字节数，0=对端关闭，-1=错误
 * 限定条件：必须在 netTask 上下文中调用
 */
int net_recv_sock(net_sock_t *p_sock, void *buf, int len, int flags);

/*
 * 函数功能：关闭 socket（内部版本，直接操作，不经过消息队列）
 * 入口参数：p_sock - Socket 控制块指针
 * 返回值：0 成功，-1 失败
 * 限定条件：必须在 netTask 上下文中调用
 */
int net_close_sock(net_sock_t *p_sock);

/*
 * 函数功能：启动 TCP Server 监听（内部版本，直接操作，不经过消息队列）
 * 入口参数：sockfd  - Socket 描述符
 * 返回值：0 成功，-1 失败
 * 限定条件：必须在 netTask 上下文中调用
 */
int net_listen_locked(int sockfd);

#ifdef __cplusplus
}
#endif

#endif /* __NET_SOCKET_H */
