Clion开发STM32之W5500系列(三)

news2024/11/18 5:42:49

前言

  1. 编写w5500的驱动
  2. 测试驱动

驱动编写

相关宏定义

#define sys_force_static_inline      __attribute__((always_inline)) static inline

寄存器驱动头文件

#ifndef STM32_VET6_W5500_REG_H
#define STM32_VET6_W5500_REG_H

#include "sys_core.h"

#define MR (0x000000)
/**brief Gateway IP Register address*/
// 可选: 0x000100、0x000200、0x000300、0x000400
#define GAR_ADDR (0x000100)
/**brief Subnet mask Register address*/
// 可选: 0x000500、0x000600、0x000700、0x000800
#define SUB_ADDR (0x000500)
/**brief Source MAC Register address*/
// 可选: 0x000900、0x000A00、0x000B00、0x000C00、0x000D00、0x000E00
#define MAC_ADDR (0x000900)
/**@brief Source IP Register address*/
// 可选: 0x000F00、0x001000、0x001100、0x001200
#define SIPR_ADDR (0x000F00)
/**@brief set Interrupt low level timer register address*/
// 可选: 0x001300、0x001400
#define INTLEVEL_ADDR (0x001300)
/**@brief Interrupt Register*/
#define IR (0x001500)
/**@brief Interrupt mask register*/
#define W_IMR (0x001600)
/**@brief Socket Interrupt Register*/
#define SIR (0x001700)
/**@brief Socket Interrupt Mask Register*/
#define SIMR (0x001800)
/**@brief Timeout register address( 1 is 100us )*/
#define RTR0 (0x001900)
#define RTR1 (0x001A00)
/**@brief Retry count reigster*/
#define WIZ_RCR (0x001B00)
/**@briefPPP LCP Request Timer register  in PPPoE mode*/
#define PTIMER (0x001C00)
/**@brief PPP LCP Magic number register  in PPPoE mode*/
#define PMAGIC (0x001D00)
/**@brief PPP Destination MAC Register address*/
// 可选: 0x001E00、0x001F00、0x002000、0x002100、0x002200、0x002300
#define PDHAR_ADDR (0x001E00)
/**
 @brief PPP Session Identification Register
 */
// 可选: 0x002400、0x002500
#define PSID_ADDR (0x002400)
/**@brief PPP Maximum Segment Size(MSS) register*/
// 可选: 0x002600、0x002700
#define PMR_ADDR (0x002600)
/**@brief Unreachable IP register address in UDP mode*/
// 可选: 0x002800、0x002900、0x002A00、0x002B00
#define UIPR_ADDR (0x002800)
/**@brief Unreachable Port register address in UDP mode*/
#define UPORT0 (0x002C00)
#define UPORT1 (0x002D00)
/**@brief PHY Configuration Register*/
#define PHYCFGR (0x002E00)
/**@brief chip version register address*/
#define VERSIONR (0x003900)
/**@brief socket Mode register*/
#define Sn_MR(ch) (0x000008 + (ch << 5))
/**@brief channel Sn_CR register*/
#define Sn_CR(ch) (0x000108 + (ch << 5))
/**@brief channel interrupt register*/
#define Sn_IR(ch) (0x000208 + (ch << 5))
/**@brief channel status register*/
#define Sn_SR(ch) (0x000308 + (ch << 5))
/**@brief source port register*/
#define Sn_PORT0(ch) (0x000408 + (ch << 5))
#define Sn_PORT1(ch) (0x000508 + (ch << 5))
/**@brief Peer MAC register address*/
#define Sn_DHAR0(ch) (0x000608 + (ch << 5))
#define Sn_DHAR1(ch) (0x000708 + (ch << 5))
#define Sn_DHAR2(ch) (0x000808 + (ch << 5))
#define Sn_DHAR3(ch) (0x000908 + (ch << 5))
#define Sn_DHAR4(ch) (0x000A08 + (ch << 5))
#define Sn_DHAR5(ch) (0x000B08 + (ch << 5))
/**@brief Peer IP register address*/
#define Sn_DIPR0(ch) (0x000C08 + (ch << 5))
#define Sn_DIPR1(ch) (0x000D08 + (ch << 5))
#define Sn_DIPR2(ch) (0x000E08 + (ch << 5))
#define Sn_DIPR3(ch) (0x000F08 + (ch << 5))
/**@brief Peer port register address*/
#define Sn_DPORT0(ch) (0x001008 + (ch << 5))
#define Sn_DPORT1(ch) (0x001108 + (ch << 5))
/**@brief Maximum Segment Size(Sn_MSSR0) register address*/
#define Sn_MSSR0(ch) (0x001208 + (ch << 5))
#define Sn_MSSR1(ch) (0x001308 + (ch << 5))

#define Sn_PROTO(ch) (0x001408 + (ch << 5))
/** @brief IP Type of Service(TOS) Register */
#define Sn_TOS(ch) (0x001508 + (ch << 5))
/**@brief IP Time to live(TTL) Register */
#define Sn_TTL(ch) (0x001608 + (ch << 5))
/**@brief Receive memory size reigster*/
#define Sn_RXMEM_SIZE(ch) (0x001E08 + (ch << 5))
/**@brief Transmit memory size reigster*/
#define Sn_TXMEM_SIZE(ch) (0x001F08 + (ch << 5))
/**@brief Transmit free memory size register*/
#define Sn_TX_FSR0(ch) (0x002008 + (ch << 5))
#define Sn_TX_FSR1(ch) (0x002108 + (ch << 5))
/**
 @brief Transmit memory read pointer register address
 */
#define Sn_TX_RD0(ch) (0x002208 + (ch << 5))
#define Sn_TX_RD1(ch) (0x002308 + (ch << 5))
/**@brief Transmit memory write pointer register address*/
#define Sn_TX_WR0(ch) (0x002408 + (ch << 5))
#define Sn_TX_WR1(ch) (0x002508 + (ch << 5))
/**@brief Received data size register*/
#define Sn_RX_RSR0(ch) (0x002608 + (ch << 5))
#define Sn_RX_RSR1(ch) (0x002708 + (ch << 5))
/**@brief Read point of Receive memory*/
#define Sn_RX_RD0(ch) (0x002808 + (ch << 5))
#define Sn_RX_RD1(ch) (0x002908 + (ch << 5))
/**@brief Write point of Receive memory*/
#define Sn_RX_WR0(ch) (0x002A08 + (ch << 5))
#define Sn_RX_WR1(ch) (0x002B08 + (ch << 5))
/**@brief socket interrupt mask register*/
#define Sn_IMR(ch) (0x002C08 + (ch << 5))
/**@brief frag field value in IP header register*/
#define Sn_FRAG(ch) (0x002D08 + (ch << 5))
/**@brief Keep Timer register*/
#define Sn_KPALVTR(ch) (0x002F08 + (ch << 5))

/* MODE register values */
#define MR_RST 0x80      /**< reset */
#define MR_WOL 0x20      /**< Wake on Lan */
#define MR_PB 0x10       /**< ping block */
#define MR_PPPOE 0x08    /**< enable pppoe */
#define MR_UDP_FARP 0x02 /**< enbale FORCE ARP */
/* IR register values */
#define IR_CONFLICT 0x80 /**< check ip confict */
#define IR_UNREACH 0x40  /**< get the destination unreachable message in UDP sending */
#define IR_PPPoE 0x20    /**< get the PPPoE close message */
#define IR_MAGIC 0x10    /**< get the magic packet interrupt */

/* Sn_MR values */
#define Sn_MR_CLOSE 0x00  /**< unused socket */
#define Sn_MR_TCP 0x01    /**< TCP */
#define Sn_MR_UDP 0x02    /**< UDP */
#define Sn_MR_IPRAW 0x03  /**< IP LAYER RAW SOCK */
#define Sn_MR_MACRAW 0x04 /**< MAC LAYER RAW SOCK */
#define Sn_MR_PPPOE 0x05  /**< PPPoE */
#define Sn_MR_UCASTB 0x10 /**< Unicast Block in UDP Multicating*/
#define Sn_MR_ND 0x20     /**< No Delayed Ack(TCP) flag */
#define Sn_MR_MC 0x20     /**< Multicast IGMP (UDP) flag */
#define Sn_MR_BCASTB 0x40 /**< Broadcast blcok in UDP Multicating */
#define Sn_MR_MULTI 0x80  /**< support UDP Multicating */

/* Sn_MR values on MACRAW MODE */
#define Sn_MR_MIP6N 0x10 /**< IPv6 packet Block */
#define Sn_MR_MMB 0x20   /**< IPv4 Multicasting Block */
//#define Sn_MR_BCASTB                 0x40     /**< Broadcast blcok */
#define Sn_MR_MFEN 0x80 /**< support MAC filter enable */

/* Sn_CR values */
#define Sn_CR_OPEN 0x01      /**< initialize or open socket */
#define Sn_CR_LISTEN 0x02    /**< wait connection request in tcp mode(Server mode) */
#define Sn_CR_CONNECT 0x04   /**< send connection request in tcp mode(Client mode) */
#define Sn_CR_DISCON 0x08    /**< send closing reqeuset in tcp mode */
#define Sn_CR_CLOSE 0x10     /**< close socket */
#define Sn_CR_SEND 0x20      /**< update txbuf pointer, send data */
#define Sn_CR_SEND_MAC 0x21  /**< send data with MAC address, so without ARP process */
#define Sn_CR_SEND_KEEP 0x22 /**<  send keep alive message */
#define Sn_CR_RECV 0x40      /**< update rxbuf pointer, recv data */

#ifdef __DEF_IINCHIP_PPP__
#define Sn_CR_PCON 0x23
#define Sn_CR_PDISCON 0x24
#define Sn_CR_PCR 0x25
#define Sn_CR_PCN 0x26
#define Sn_CR_PCJ 0x27
#endif

/* Sn_IR values */
#ifdef __DEF_IINCHIP_PPP__
#define Sn_IR_PRECV 0x80
#define Sn_IR_PFAIL 0x40
#define Sn_IR_PNEXT 0x20
#endif

#define Sn_IR_SEND_OK 0x10 /**< complete sending */
#define Sn_IR_TIMEOUT 0x08 /**< assert timeout */
#define Sn_IR_RECV 0x04    /**< receiving data */
#define Sn_IR_DISCON 0x02  /**< closed socket */
#define Sn_IR_CON 0x01     /**< established connection */

/* Sn_SR values */
typedef enum {
    /**
     * @brief 关闭状态,资源被释放。
     * @note W5500 对应的Socket会无视之前的状态,变为 SOCK_CLOSED。
     * */
    s_closed = 0x00,
    /**
     * @brief 端口打开并处于 TCP 工作模式。
     * @note 当 Sn_MR (P[3:0]) = ‘0001’且 OPEN 命令生效时,Sn_SR 变为 SOCK_INIT。之后才可以使用 LISTEN 或 CONNECT 命令。
     */
    s_init = 0x13,
    /**
     * @brief 工作在 TCP 服务器模式下,且等待对方(TCP 客户端)的连接请求(SYN Packet)。
     * @note 当 连 接 请 求 被 成 功 接 收 以 后 , Socket_SR 会 变 为SOCK_ESTALBLISHED 状态。
     *       否则将会在触发 超时中断之后,变为 SOCK_CLOSED 状态。
     * */
    s_listen = 0x14,
    s_syn_sent = 0x15,
    s_syn_recv = 0x16,
    /**
     * @brief SOCK_LISTEN 状态下,当 TCP 服务器处理 TCP 客户端的 SYN 请求包或当 CONNECT 命令配置成功时,变为 SOCK_ESTABLISHED。
     *        在此状态下,可以使用 SEND 或者 RECV 命令进行数据包传输。
     */
    s_established = 0x17,
    s_fin_wait = 0x18,
    s_closing = 0x1A,
    s_time_wait = 0x1B,
    /**
     * @brief 指示了 Socket n 接收到了来自连接对方发来的断开连接请求(FIN packet)。这是一个半关闭状态,可以进行数据传输
     * @note  若要全部关闭,需要使用 DISCON 命令。而如果是要关闭Socket,需要使用 CLOSE 命令。
     */
    s_close_wait = 0x1C,
    s_last_ack = 0x1D,
    s_udp = 0x22,
    s_ip_raw = 0x32,
    s_mac_raw = 0x42,
    s_pppoe = 0x5F,
} socket_status_type;

/* IP PROTOCOL */
#define IPPROTO_IP 0    /**< Dummy for IP */
#define IPPROTO_ICMP 1  /**< Control message protocol */
#define IPPROTO_IGMP 2  /**< Internet group management protocol */
#define IPPROTO_GGP 3   /**< Gateway^2 (deprecated) */
#define IPPROTO_TCP 6   /**< TCP */
#define IPPROTO_PUP 12  /**< PUP */
#define IPPROTO_UDP 17  /**< UDP */
#define IPPROTO_IDP 22  /**< XNS idp */
#define IPPROTO_ND 77   /**< UNOFFICIAL net disk protocol */
#define IPPROTO_RAW 255 /**< Raw IP packet */

/*********************************************************
 * iinchip access function
 *********************************************************/
/**
*@brief		从W5500读出一个8位数据
*@param		addr: 写入数据的地址
*@param        data:从写入的地址处读取到的8位数据
*@return	无
*/
extern uint8_t w5500_read(uint32_t addr);

/**
 *@brief		写入一个8位数据到W5500
 *@param		addr: 写入数据的地址
 *@param   		data:写入的8位数据
 *@return	无
 */
extern void w5500_write(uint32_t addr, uint8_t data);

/**
*@brief		向W5500写入len字节数据
*@param		addr: 写入数据的地址
*@param        buf:写入字符串
*@param        len:字符串长度
*@return	        返回字符串长度
*/
extern uint16_t w5500_writes(uint32_t addr, uint8_t *buf, uint16_t len);

/**
 *@brief		从W5500读出len字节数据
 *@param		addr: 读取数据的地址
 *@param 		buf:存放读取数据
 *@param		len:字符串长度
 *@return		len:返回字符串长度
 */
extern uint16_t w5500_reads(uint32_t addr, uint8_t *buf, uint16_t len);

/**
 * @brief 读取 模式寄存器
 * @note 用于 S/W 复位,ping block 模式和 PPPoE 模式。
 * @param val
 *
 */
sys_force_static_inline void w5500_reg_mr_set(uint8_t val) {
    w5500_write(MR, val);
}

/**
 * @brief 读取 模式寄存器
 * @note 用于 S/W 复位,ping block 模式和 PPPoE 模式。
 */
sys_force_static_inline void w5500_reg_mr_read(void) {
    w5500_read(MR);
}

/**
 * @brief S/W 内部寄存器将被初始化。它会在复位后自动清零
 */
sys_force_static_inline void w5500_chip_init(void) {
    w5500_reg_mr_set(MR_RST);
}
/**
 * @brief 设置重新传输时间。
 *  @note 每一单位数值为 100 微秒。初始化时值设为 2000
 * @param timeout
 */
sys_force_static_inline void w5500_reg_rtr_set(uint16_t timeout) {
    w5500_write(RTR0, (uint8_t) ((timeout & 0xff00) >> 8));
    w5500_write(RTR1, (uint8_t) (timeout & 0x00ff));
}



/**
 * @brief 此功能用于在主动模式下设置 TCP 的最大段大小),而在被动模式下由对等方设置
 * @param s (socket num)
 * @param Sn_MSSR
 */
sys_force_static_inline void w5500_socket_segment_set(uint8_t s, uint16_t Sn_MSSR) {
    w5500_write(Sn_MSSR0(s), (uint8_t) ((Sn_MSSR & 0xff00) >> 8));
    w5500_write(Sn_MSSR1(s), (uint8_t) (Sn_MSSR & 0x00ff));
}



/**
 * @brief 设置生存时间寄存器
 *  @note 它应在执行 OPEN 命令之前设置。
 * @param s (socket num)
 * @param ttl (单位: 秒)
 */
sys_force_static_inline void w5500_reg_ttl_set(uint8_t s, uint8_t ttl) {
    w5500_write(Sn_TTL(s), ttl);
}
/**
 * @brief 设置重新传送的次数
 *  。当第‘RCR+1’次重传时,超时中断就会置‘1’。(中断寄存器(Sn_IR)的 ‘中断’位(‘TIMEOUT’ bit)设置为'1')
 * @param [in] retry 次数
 */
sys_force_static_inline void w5500_reg_rcr_set(uint8_t retry) {
    w5500_write(WIZ_RCR, retry);
}
/**
 * @brief 设置socket 中断状态
 * @param [in] s (socket num)
 * @param [in] val (中断状态)
 */
sys_force_static_inline void w5500_reg_socket_it_set(uint8_t s, uint8_t val) {
    w5500_write(Sn_IR(s), val);
}

/**
 * @brief 寄存器gw设置
 * @param [in] addr ip地址数组,@note 长度为4
 */
sys_force_static_inline void w5500_reg_gw_set(uint8_t *addr) {
    w5500_writes(GAR_ADDR, addr, 4);
}
/**
 * @brief 寄存器mac设置
 * @param [in] addr ip地址数组,@note 长度为6
 */
sys_force_static_inline void w5500_reg_mac_set(uint8_t *addr) {
    w5500_writes(MAC_ADDR, addr, 6);
}

/**
 * @brief 寄存器sub设置
 * @param [in] addr @note 长度为4
 */
sys_force_static_inline void w5500_reg_sub_set(uint8_t *addr) {
    w5500_writes(SUB_ADDR, addr, 4);
}
/**
 * @brief 寄存器IP设置
 * @param [in] addr ip地址数组,@note 长度为4
 */
sys_force_static_inline void w5500_reg_ip_set(uint8_t *addr) {
    w5500_writes(SIPR_ADDR, addr, 4);
}

/*------------------------------寄存器读取-----------------------------------*/
/**
 * @brief 此功能用于在公共寄存器中获取中断寄存器。
 * @return
 */
sys_force_static_inline uint8_t w5500_reg_it_read(void) {
    return w5500_read(IR);
}

/**
 * @brief clear interrupt
 *  此功能是对中断掩码启用禁用适当的中断。
 *  (“1”:中断使能)如果IMR中的任何位设置为“0”,则尽管该位在IR寄存器中设置,但没有中断信号。
 * @param mask
 */
sys_force_static_inline void w5500_reg_it_clear(uint8_t mask) {
    w5500_write(IR, ~mask | w5500_reg_it_read());
}
/**
 * @brief 读取socket 中断状态
 * @param s
 * @return
 */
sys_force_static_inline uint8_t w5500_socket_it_status_read(uint8_t s) {
    return w5500_read(Sn_IR(s));
}


/**
 * @brief 读取socket状态
 * @param [in] s (socket num)
 * @return [out] 状态
 */
sys_force_static_inline uint8_t w5500_socket_status_read(uint8_t s) {
    return w5500_read(Sn_SR(s));
}

sys_force_static_inline socket_status_type w5500_status_read(uint8_t s) {
    return w5500_read(Sn_SR(s));
}
/**
 * @brief 读取重传次数
 * @return
 */
sys_force_static_inline uint8_t w5500_reg_rcr_read(void) {
    return w5500_read(WIZ_RCR);
}
/**
 * @brief 寄存器gw读取(网关)
 * @param [out] addr  ip地址数组,@note 长度为4
 */
sys_force_static_inline void w5500_reg_gw_read(uint8_t *addr) {
    w5500_reads(GAR_ADDR, addr, 4);
}
/**
 * @brief 寄存器sub读取
 * @param [out] addr  ip地址数组,@note 长度为4
 */
sys_force_static_inline void w5500_reg_sub_read(uint8_t *addr) {
    w5500_reads(SUB_ADDR, addr, 4);
}

/**
 * @brief 寄存器mac读取
 * @param [out] addr  ip地址数组,@note 长度为6
 */
sys_force_static_inline void w5500_reg_mac_read(uint8_t *addr) {
    w5500_reads(MAC_ADDR, addr, 6);
}

/**
 * @brief 寄存器IP读取
 * @param [out] addr  ip地址数组,@note 长度为4
 */
sys_force_static_inline void w5500_reg_ip_read(uint8_t *addr) {
    w5500_reads(SIPR_ADDR, addr, 4);
}

/**
 * @brief 获取socket 发送区大小
 * @param s (socket num)
 * @return
 */
sys_force_static_inline uint16_t w5500_socket_tx_size_read(uint8_t s) {
    uint16_t val = 0, val1 = 0;
    do {
        val1 = w5500_read(Sn_TX_FSR0(s));
        val1 = (val1 << 8) + w5500_read(Sn_TX_FSR1(s));
        if (val1 != 0) {
            val = w5500_read(Sn_TX_FSR0(s));
            val = (val << 8) + w5500_read(Sn_TX_FSR1(s));
        }
    } while (val != val1);
    return val;
}

/**
 * @brief 获取socket 接送区大小
 * @param s (socket num)
 * @return
 */
sys_force_static_inline uint16_t w5500_socket_rx_size_read(uint8_t s) {
    uint16_t val = 0, val1 = 0;
    do {
        val1 = w5500_read(Sn_RX_RSR0(s));
        val1 = (val1 << 8) + w5500_read(Sn_RX_RSR1(s));
        if (val1 != 0) {
            val = w5500_read(Sn_RX_RSR0(s));
            val = (val << 8) + w5500_read(Sn_RX_RSR1(s));
        }
    } while (val != val1);
    return val;
}
/**
 * @brief 此函数读取 Tx 写入指针寄存器,并在缓冲区中复制数据后更新 Tx 写入指针寄存器。
 *          @note 应先读取上字节,然后再读取小字节以获得正确的值
 * @param s (socket num)
 * @param [in] data 写入数据
 * @param [in] len 数据长度
 */
sys_force_static_inline void w5500_send_data_processing(uint8_t s, uint8_t *data, uint16_t len) {
    uint16_t ptr = 0;
    uint32_t addrbsb = 0;
    if (len == 0) return;
    ptr = w5500_read(Sn_TX_WR0(s));
    ptr = ((ptr & 0x00ff) << 8) + w5500_read(Sn_TX_WR1(s));
    addrbsb = (uint32_t) (ptr << 8) + (s << 5) + 0x10;
    w5500_writes(addrbsb, data, len);
    ptr += len;
    w5500_write(Sn_TX_WR0(s), (uint8_t) ((ptr & 0xff00) >> 8));
    w5500_write(Sn_TX_WR1(s), (uint8_t) (ptr & 0x00ff));
}
/**
 * @brief 此函数读取 Rx 读取指针寄存器,并在从接收缓冲区复制数据后更新 Rx 写入指针寄存器。
 *          @note 应先读取上字节,然后再读取小字节以获得正确的值
 * @param s (socket num)
 * @param [out] data 读取的数据
 * @param [in] len 读取数据长度
 */
sys_force_static_inline void w5500_recv_data_processing(uint8_t s, uint8_t *data, uint16_t len) {
    uint16_t ptr = 0;
    uint32_t addrbsb = 0;
    if (len == 0) return;
    ptr = w5500_read(Sn_RX_RD0(s));
    ptr = ((ptr & 0x00ff) << 8) + w5500_read(Sn_RX_RD1(s));
    addrbsb = (uint32_t) (ptr << 8) + (s << 5) + 0x18;
    w5500_reads(addrbsb, data, len);
    ptr += len;
    w5500_write(Sn_RX_RD0(s), (uint8_t) ((ptr & 0xff00) >> 8));
    w5500_write(Sn_RX_RD1(s), (uint8_t) (ptr & 0x00ff));
}

#endif //STM32_VET6_W5500_REG_H

w5500配置

头文件

/*******************************************************************************
 *  Copyright (c) [scl]。保留所有权利。
 *
 *     @note
 *          1. W5500 的 SPI 数据帧包括:
 *              16位地址段的偏移地址,
 *              8 位控制段
 *              N 字节数据段。
 *          2. 8 位控制段可以通过修改区域选择位 (BSB[4:0]),读/写访问模式位(RWB)以及 SPI工作模式位(OM[1:0])来重新定义。
 * 地址段
 *      地址段为 W5500 的寄存器或 TX/RX 缓存区指定了 16 位的偏移地址。这 16 位偏移地址的值来自于从最高标志位到最低标志位的顺序传输。
 *      SPI 数据帧的数据段(2/4/N 字节)通过偏移地址自增(每传输 1 字节偏移地址加 1)支持连续数据读/写
 * 控制段
 *      控制段指定了地址段设定的偏移区域的归属,读/写访问模式以及 SPI 工作模式。
 *      BSB [4:0]
 *          00000 选择通用寄存器
 *          00001 选择Socket 0寄存器
 *          00010 选择Socket 0发送缓存
 *          00011 选择Socket 0接收缓存
 *          00100 保留位
 *          00101 选择Socket 1寄存器
 *          00110 选择Socket 1发送缓存
 *          00111 选择Socket 1接收缓存
 *          01000 保留位
 *          01001 选择Socket 2寄存器
 *          01010 选择Socket 2发送缓存
 *          01011 选择Socket 2接收缓存*
 *          (*******)
 *     RWB 读/写访问模式位 (0: 读; 1:写)
 *     OM [1:0] 工作模式位
 *          00 可变数据长度模式,N字节数据段(1 ≤ N)
 *          01 固定数据长度模式,1字节数据长度(N = 1)
 *          10 固定数据长度模式,1字节数据长度(N = 2)
 *          11 固定数据长度模式,1字节数据长度(N = 4)
 *数据段
 *      在 SPI 工作模式位 OM[1:0]设定了控制端之后,数据段被设定为 2 种长度类型:
 *          1 种为可变的 N 字节长度(可变数据长度模式),
 *          另一种为确定的 1/2/4 字节长度(固定数据长度模式)。
 ******************************************************************************/

#ifndef STM32_VET6_W5500_CONFIG_H
#define STM32_VET6_W5500_CONFIG_H

#include "w5500_reg.h"

#define SOCKET_MAX_NUM 8
typedef uint8_t SOCKET;
#define TCP_CLIENT_PORT 3000  // TCP客户端本地端口
#define UDP_CLIENT_PORT 4000 //  UDP客户端本地端口

typedef struct __attribute__((packed)) {
    uint8_t ip_addr[4];
    uint8_t gw[4];
    uint8_t sub[4];
    uint16_t port;
} w5500_net_conf_t;
typedef struct {
    uint8_t *buf;
    uint16_t buf_len;
} w5500_buf_t; // 数据结构体

typedef struct {
    struct {
        uint8_t socket_num; /*使用socket的数量*/
        uint8_t tx_size[8]; /*socket发送缓存取的大小(单位KB),总共16KB*/
        uint8_t rx_size[8]; /*socket接收缓存取的大小(单位KB),总共16KB*/
    } base_conf;/*w5500 基础配置*/
    struct {
        uint8_t mac[6]; /*mac地址*/
        uint8_t ip[4];  /*IP地址*/
        uint8_t sub[4]; /*子网掩码地址*/
        uint8_t gw[4]; /*网关地址*/

    } net_conf;/*w5500 网络配置*/
    struct {
        void (*send_and_rec_bytes)(uint8_t *in_data, uint8_t *out_data, uint16_t len);/*收发多字节*/
        void (*delay)(uint32_t ms);/*延迟*/
        void (*cs_low)();/*使能引脚置低电平*/
        void (*cs_high)();/*使能引脚置高电平*/
        void (*rst_low)();/*复位引脚低电平*/
        void (*rst_high)();/*复位引脚高电平*/
    } driver;

    struct {
        void (*msp_init)();/*硬件驱动初始化*/
    } api;
    /*--------------以下函数:默认情况下无需重新引用------------*/
    bool (*check_net_conf)(void);

    /*硬件检测(如果网线没插会阻塞)*/
    void (*phy_check)(void);

    void (*net_conf_init)();/*网络配置初始化(由内部封装实现)*/
} module_w5500_t; /*w5500 模块*/
/**
 * @brief 初始化w5500相关信息
 * @param w5500
 */
void module_w5500_init(module_w5500_t *w5500);

/**
 * @brief 获取对应的信息
 * @return
 */
module_w5500_t *module_w5500_read(void);


#endif //STM32_VET6_W5500_CONFIG_H

源文件

#include "w5500_config.h"
/*是否输出日志*/
//#define DBG_ENABLE
#define DBG_SECTION_NAME "w5500-module"
#define DBG_LEVEL DBG_LOG

#include "sys_dbg.h"

static module_w5500_t *net_w5500 = NULL;

static void net_init();

/*校验网络配置*/
static bool check_net_conf();

static void w5500_phy_check(void);

void module_w5500_init(module_w5500_t *w5500) {
    sys_assert_void(w5500 != NULL);
    w5500->net_conf_init = net_init;
    w5500->check_net_conf = check_net_conf;
    w5500->phy_check = w5500_phy_check;
    net_w5500 = w5500;

}

static void net_init() {
    sys_assert_void(net_w5500 != NULL);
    LOG_D("--------------net_init start--------------");
    /*该引脚需要保持低电平至少 500 us,才能重置 W5500;*/
    net_w5500->driver.rst_low();
    net_w5500->driver.delay(1);
    net_w5500->driver.rst_high();
    net_w5500->driver.delay(500);
    LOG_D("set mac addr");
    w5500_writes(MAC_ADDR, net_w5500->net_conf.mac, 6);/*设置mac地址*/
    LOG_D("set sub addr");
    w5500_writes(SUB_ADDR, net_w5500->net_conf.sub, 4); /*子网掩码*/
    LOG_D("set gateway addr");
    w5500_writes(GAR_ADDR, net_w5500->net_conf.gw, 4); /*网关*/
    LOG_D("set ip addr");
    w5500_writes(SIPR_ADDR, net_w5500->net_conf.ip, 4); /*IP配置*/
    LOG_D("set other conf");
    // 配置socket缓存大小
    for (uint8_t i = 0; i < net_w5500->base_conf.socket_num; i++) {
        w5500_write(Sn_TXMEM_SIZE(i), net_w5500->base_conf.tx_size[i]);
        w5500_write(Sn_RXMEM_SIZE(i), net_w5500->base_conf.rx_size[i]);
        w5500_write(Sn_TTL(i), 2); // 设置生存时间寄存器 2秒

    }
    LOG_D("--------------net_init end--------------");
}

inline module_w5500_t *module_w5500_read(void) {
    return net_w5500;
}

static inline uint8_t w5500_send_byte(uint8_t dat) {
    uint8_t data = 0;
    net_w5500->driver.send_and_rec_bytes(&dat, &data, 1);
    return data;
}

void w5500_write(uint32_t addr, uint8_t data) {
    net_w5500->driver.cs_low();
    w5500_send_byte((addr & 0x00FF0000) >> 16);
    w5500_send_byte((addr & 0x0000FF00) >> 8);
    w5500_send_byte((addr & 0x000000F8) + 4);
    w5500_send_byte(data);
    net_w5500->driver.cs_high();
}


uint8_t w5500_read(uint32_t addr) {
    net_w5500->driver.cs_low();
    w5500_send_byte((addr & 0x00FF0000) >> 16);
    w5500_send_byte((addr & 0x0000FF00) >> 8);
    w5500_send_byte((addr & 0x000000F8));
    uint8_t data = w5500_send_byte(0x00);
    net_w5500->driver.cs_high();
    return data;
}


uint16_t w5500_writes(uint32_t addr, uint8_t *buf, uint16_t len) {
    if (len == 0) {
        LOG_E("Unexpected2 length 0");
    }
    net_w5500->driver.cs_low();
    w5500_send_byte((addr & 0x00FF0000) >> 16);
    w5500_send_byte((addr & 0x0000FF00) >> 8);
    w5500_send_byte((addr & 0x000000F8) + 4);
    net_w5500->driver.send_and_rec_bytes(buf, NULL, len);
    net_w5500->driver.cs_high();
    return len;
}


uint16_t w5500_reads(uint32_t addr, uint8_t *buf, uint16_t len) {
    if (len == 0) {
        LOG_E("Unexpected2 length 0");
    }
    net_w5500->driver.cs_low();
    w5500_send_byte((addr & 0x00FF0000) >> 16);
    w5500_send_byte((addr & 0x0000FF00) >> 8);
    w5500_send_byte((addr & 0x000000F8));
    net_w5500->driver.send_and_rec_bytes(NULL, buf, len);
    net_w5500->driver.cs_high();
    return len;
}

static bool check_net_conf() {
    /*验证ip和网关是否在同一网段*/
    uint8_t *ptr1 = net_w5500->net_conf.ip;
    uint8_t *ptr2 = net_w5500->net_conf.gw;
    for (int i = 0; i < 3; ++i) {
        if (*ptr1 != *ptr2) return false;
        ptr1++;
        ptr2++;
    }
    /*验证子网掩码 @note 固定为 255.255.255.0 */
    ptr1 = net_w5500->net_conf.sub;
    if (ptr1[0] == 255 && ptr1[1] == 255 && ptr1[2] == 255 && ptr1[3] == 0) return true;
    return false;

}


/**
 * @brief 检测物理层连接
 * @return
 */
static void w5500_phy_check(void) {
    uint8_t phyConnect = 0x01 & w5500_read(PHYCFGR);
    if (phyConnect == 0) {
        phyConnect = 0;
        do {
            w5500_write(Sn_CR(phyConnect), Sn_CR_CLOSE);
            /* wait to process the command... */
            while (w5500_read(Sn_CR(phyConnect))); /* ------- */
            w5500_write(Sn_IR(phyConnect), 0xFF); /* all clear */
            phyConnect++;
        } while (phyConnect < SOCKET_MAX_NUM);
        phyConnect = 0;
        while (phyConnect == 0) {
            phyConnect = 0x01 & w5500_read(PHYCFGR);
            net_w5500->driver.delay(500);
            LOG_E("please check net driver connect");
        }
    }
}


socket封装

头文件

#ifndef STM32_VET6_SOCKET_H
#define STM32_VET6_SOCKET_H

#include "w5500_config.h"

// Opens a socket(TCP or UDP or IP_RAW mode)
extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag);

// Close socket
extern void close(SOCKET s);

// Establish TCP connection (Active connection)
extern uint8_t connect(SOCKET s, uint8_t *addr, uint16_t port);

extern void disconnect(SOCKET s);

extern uint8_t listen(SOCKET s);

// Send data (TCP)
extern uint16_t send(SOCKET s, const uint8_t *buf, uint16_t len);

// Receive data (TCP)
extern uint16_t recv(SOCKET s, uint8_t *buf, uint16_t len);

// Send data (UDP/IP RAW)
extern uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port);

// Receive data (UDP/IP RAW)
extern uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port);



extern void clearSocketFlag(SOCKET s);


sys_force_static_inline uint8_t socket_status(SOCKET s) {
    return w5500_status_read(s);
}


bool udp_socket_init(SOCKET s, uint16_t local_port);

bool udp_send(SOCKET s, uint8_t *dst_ip, uint16_t dst_port, uint8_t *data, uint16_t len);

bool udp_rec(SOCKET s, uint16_t listen_port, uint8_t *dstIp, uint16_t *dstPort, uint8_t *recData, uint16_t *recLen);


void tcp_client_connect(SOCKET s, uint8_t *dst_ip, uint16_t dst_port);

bool tcp_client_send(SOCKET s, uint8_t *data, uint16_t len);

uint16_t tcp_client_rec(SOCKET s, uint8_t *out_data);

/******************************************TCP SERVER 端********************************************/
/**
 * @brief 服务端初始化
 * @param s
 * @param listen_port 监听端口
 * @param netData 数据区域
 */
void tcp_server_init(SOCKET s, uint16_t listen_port, w5500_buf_t *netData);

/**
 * @brief 监听socket
 * @param s
 * @return
 */
w5500_buf_t *tcp_server_listen(SOCKET s);
/*响应字节数组数据*/
sys_force_static_inline void tcp_server_resp(SOCKET s, uint8_t *data, uint16_t len) {
    sys_assert_void(data != NULL);
    send(s, data, len);
}


#endif //STM32_VET6_SOCKET_H

源文件

#include "socket.h"

#define DBG_ENABLE
#define DBG_SECTION_NAME "socket-module"
#define DBG_LEVEL DBG_WARNING

#include "sys_dbg.h"

uint16_t udp_local_port = UDP_CLIENT_PORT;
uint16_t tcp_local_port = TCP_CLIENT_PORT;
uint16_t socket_port[8];
w5500_buf_t *socket_net_data[8];
#define w5500_tx_max_size(i) (module_w5500_read()->base_conf.tx_size[i]*1024)

/****************************************************************
 * @Date: 2022-08-27 13:39:17
 * @Funticon name: 清除socket 中断标志位
 * @Berif:
 * @Author: scl
 * @Note:
 * @param {SOCKET} s
 * @return {*}
 ******************************************************************/
void clearSocketFlag(SOCKET s) {
    uint8_t stat = w5500_socket_it_status_read(s);
    if (stat & Sn_IR_CON) // tcp
    {
        w5500_reg_socket_it_set(s, Sn_IR_CON); /*清除接收中断标志位*/
        return;
    }
    if (stat & Sn_IR_RECV) {
        w5500_reg_socket_it_set(s, Sn_IR_RECV); /*清接收中断*/
        return;
    }
}

/**
*@brief   This Socket function initialize the channel in perticular mode,
			   and set the port and wait for W5200 done it.
*@param		s: socket number.
*@param		protocol: The socket to chose.
*@param		port:The port to bind.
*@param		flag: Set some bit of MR,such as **< No Delayed Ack(TCP) flag.
*@return  1 for sucess else 0.
*/
uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) {
    uint8_t ret;
    if (((protocol & 0x0F) == Sn_MR_TCP) || ((protocol & 0x0F) == Sn_MR_UDP) ||
        ((protocol & 0x0F) == Sn_MR_IPRAW) || ((protocol & 0x0F) == Sn_MR_MACRAW) ||
        ((protocol & 0x0F) == Sn_MR_PPPOE)) {
        close(s);
        w5500_write(Sn_MR(s), protocol | flag);
        w5500_write(Sn_PORT0(s), (uint8_t) ((port & 0xff00) >> 8));
        w5500_write(Sn_PORT1(s), (uint8_t) (port & 0x00ff));
        w5500_write(Sn_CR(s), Sn_CR_OPEN); // run sockinit Sn_CR

        /* wait to process the command... */
        while (w5500_read(Sn_CR(s)));
        /* ------- */
        ret = 1;
    } else {
        ret = 0;
    }
    return ret;
}

/**
 *@brief   This function close the socket and parameter is "s" which represent
 *the socket number
 *@param		s: socket number.
 *@return  None
 */
void close(SOCKET s) {

    w5500_write(Sn_CR(s), Sn_CR_CLOSE);
    /* 验证配置是否成功 */
    while (w5500_read(Sn_CR(s)));
    /* all clear */
    w5500_write(Sn_IR(s), 0xFF);
}

/**
*@brief   This function established  the connection for the channel in passive
(server) mode. This function waits for the request from the peer.
*@param		s: socket number.
*@return  1 for success else 0.
*/
uint8_t listen(SOCKET s) {
    uint8_t ret;
    if (w5500_read(Sn_SR(s)) == s_init) {
        w5500_write(Sn_CR(s), Sn_CR_LISTEN);
        /* wait to process the command... */
        while (w5500_read(Sn_CR(s)));
        /* ------- */
        ret = 1;
    } else {
        ret = 0;
    }
    return ret;
}

/**
*@brief		This function established  the connection for the channel in
Active (client) mode. This function waits for the untill the connection is
established.
*@param		s: socket number.
*@param		addr: The server IP address to connect
*@param		port: The server IP port to connect
*@return  1 for success else 0.
*/
uint8_t connect(SOCKET s, uint8_t *addr, uint16_t port) {
    uint8_t ret;
    if (((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) &&
         (addr[3] == 0xFF)) ||
        ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) &&
         (addr[3] == 0x00)) ||
        (port == 0x00)) {
        ret = 0;
    } else {
        ret = 1;
        // set destination IP
        w5500_write(Sn_DIPR0(s), addr[0]);
        w5500_write(Sn_DIPR1(s), addr[1]);
        w5500_write(Sn_DIPR2(s), addr[2]);
        w5500_write(Sn_DIPR3(s), addr[3]);
        w5500_write(Sn_DPORT0(s), (uint8_t) ((port & 0xff00) >> 8));
        w5500_write(Sn_DPORT1(s), (uint8_t) (port & 0x00ff));
        w5500_write(Sn_CR(s), Sn_CR_CONNECT);
        /* wait for completion */
        while (w5500_read(Sn_CR(s)));

        while (w5500_read(Sn_SR(s)) != s_syn_sent) {
            if (w5500_read(Sn_SR(s)) == s_established) {
                break;
            }
            if (w5500_socket_it_status_read(s) & Sn_IR_TIMEOUT) {
                w5500_write(Sn_IR(s), (Sn_IR_TIMEOUT)); // clear TIMEOUT Interrupt
                ret = 0;
                break;
            }
            if (w5500_socket_it_status_read(s) & Sn_IR_DISCON) { // clear dis connect Interrupt
                disconnect(s);
                ret = 0;
                break;
            }
        }
    }

    return ret;
}

/**
 *@brief   This function used for disconnect the socket s
 *@param		s: socket number.
 *@return  1 for success else 0.
 */
void disconnect(SOCKET s) {
    w5500_write(Sn_CR(s), Sn_CR_DISCON);

    /* wait to process the command... */
    while (w5500_read(Sn_CR(s)));
    /* ------- */
}

/**
 *@brief   This function used to send the data in TCP mode
 *@param		s: socket number.
 *@param		buf: data buffer to send.
 *@param		len: data length.
 *@return  1 for success else 0.
 */
uint16_t send(SOCKET s, const uint8_t *buf, uint16_t len) {
    uint8_t status = 0;
    uint16_t ret = 0;
    uint16_t freesize = 0;
    if (len > w5500_tx_max_size(s))
        ret = w5500_tx_max_size(s); // check size not to exceed MAX size.
    else
        ret = len;

    // if freebuf is available, start.
    do {
        freesize = w5500_socket_tx_size_read(s);
        status = w5500_read(Sn_SR(s));
        if ((status != s_established) && (status != s_close_wait)) {
            ret = 0;
            break;
        }
    } while (freesize < ret);

    // copy data
    w5500_send_data_processing(s, (uint8_t *) buf, ret);
    w5500_write(Sn_CR(s), Sn_CR_SEND);

    /* wait to process the command... */
    while (w5500_read(Sn_CR(s)));

    while ((w5500_read(Sn_IR(s)) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK) {
        status = w5500_read(Sn_SR(s));
        if ((status != s_established) && (status != s_close_wait)) {
            //			printf("SEND_OK Problem!!\r\n");
            close(s);
            return 0;
        }
    }
    w5500_write(Sn_IR(s), Sn_IR_SEND_OK);

#ifdef __DEF_IINCHIP_INT__
    putISR(s, getISR(s) & (~Sn_IR_SEND_OK));
#else
    w5500_write(Sn_IR(s), Sn_IR_SEND_OK);
#endif

    return ret;
}

/**
*@brief		This function is an application I/F function which is used to
receive the data in TCP mode. It continues to wait for data as much as the
application wants to receive.
*@param		s: socket number.
*@param		buf: data buffer to receive.
*@param		len: data length.
*@return  received data size for success else 0.
*/
uint16_t recv(SOCKET s, uint8_t *buf, uint16_t len) {
    uint16_t ret = 0;
    if (len > 0) {
        w5500_recv_data_processing(s, buf, len);
        w5500_write(Sn_CR(s), Sn_CR_RECV);
        /* wait to process the command... */
        while (w5500_read(Sn_CR(s)));
        /* ------- */
        ret = len;
    }
    return ret;
}

/**
*@brief   This function is an application I/F function which is used to send the
data for other then TCP mode. Unlike TCP transmission, The peer's destination
address and the port is needed.
*@param		s: socket number.
*@param		buf: data buffer to send.
*@param		len: data length.
*@param		addr: IP address to send.
*@param		port: IP port to send.
*@return  This function return send data size for success else 0.
*/
uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port) {
    uint16_t ret = 0;

    if (len > w5500_tx_max_size(s))
        ret = w5500_tx_max_size(s); // check size not to exceed MAX size.
    else
        ret = len;

    if (((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
        ((port == 0x00))) //||(ret == 0) )
    {
        /* added return value */
        ret = 0;
    } else {
        w5500_write(Sn_DIPR0(s), addr[0]);
        w5500_write(Sn_DIPR1(s), addr[1]);
        w5500_write(Sn_DIPR2(s), addr[2]);
        w5500_write(Sn_DIPR3(s), addr[3]);
        w5500_write(Sn_DPORT0(s), (uint8_t) ((port & 0xff00) >> 8));
        w5500_write(Sn_DPORT1(s), (uint8_t) (port & 0x00ff));
        // copy data
        w5500_send_data_processing(s, (uint8_t *) buf, ret);
        w5500_write(Sn_CR(s), Sn_CR_SEND);
        /* wait to process the command... */
        while (w5500_read(Sn_CR(s)));
        /* ------- */
        while ((w5500_read(Sn_IR(s)) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK) {
            if (w5500_read(Sn_IR(s)) & Sn_IR_TIMEOUT) {
                /* clear interrupt */
                w5500_write(Sn_IR(s), (Sn_IR_SEND_OK | Sn_IR_TIMEOUT)); /* clear SEND_OK & TIMEOUT */
                return 0;
            }
        }
        w5500_write(Sn_IR(s), Sn_IR_SEND_OK);
    }
    return ret;
}

/**
*@brief   This function is an application I/F function which is used to receive
the data in other then TCP mode. This function is used to receive UDP, IP_RAW
and MAC_RAW mode, and handle the header as well.
*@param		s: socket number.
*@param		buf: data buffer to receive.
*@param		len: data length.
*@param		addr: IP address to receive.
*@param		port: IP port to receive.
*@return	This function return received data size for success else 0.
*/
uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port) {
    uint8_t head[8];
    uint16_t data_len = 0;
    uint16_t ptr = 0;
    uint32_t addrbsb = 0;
    if (len > 0) {
        ptr = w5500_read(Sn_RX_RD0(s));
        ptr = ((ptr & 0x00ff) << 8) + w5500_read(Sn_RX_RD1(s));
        addrbsb = (uint32_t) (ptr << 8) + (s << 5) + 0x18;

        switch (w5500_read(Sn_MR(s)) & 0x07) {
            case Sn_MR_UDP:
                w5500_reads(addrbsb, head, 0x08);
                ptr += 8;
                // read peer's IP address, port number.
                addr[0] = head[0];
                addr[1] = head[1];
                addr[2] = head[2];
                addr[3] = head[3];
                *port = head[4];
                *port = (*port << 8) + head[5];
                data_len = head[6];
                data_len = (data_len << 8) + head[7];

                addrbsb = (uint32_t) (ptr << 8) + (s << 5) + 0x18;
                w5500_reads(addrbsb, buf, data_len);
                ptr += data_len;

                w5500_write(Sn_RX_RD0(s), (uint8_t) ((ptr & 0xff00) >> 8));
                w5500_write(Sn_RX_RD1(s), (uint8_t) (ptr & 0x00ff));
                break;
            case Sn_MR_IPRAW:
                w5500_reads(addrbsb, head, 0x06);
                ptr += 6;
                addr[0] = head[0];
                addr[1] = head[1];
                addr[2] = head[2];
                addr[3] = head[3];
                data_len = head[4];
                data_len = (data_len << 8) + head[5];

                addrbsb = (uint32_t) (ptr << 8) + (s << 5) + 0x18;

                //		printf(" data:%d \r\n",data_len);
                w5500_reads(addrbsb, buf, data_len);

                ptr += data_len;

                w5500_write(Sn_RX_RD0(s), (uint8_t) ((ptr & 0xff00) >> 8));
                w5500_write(Sn_RX_RD1(s), (uint8_t) (ptr & 0x00ff));

                break;

            case Sn_MR_MACRAW:
                w5500_reads(addrbsb, head, 0x02);
                ptr += 2;
                data_len = head[0];
                data_len = (data_len << 8) + head[1] - 2;
                if (data_len > 1514) {
                    //					printf("data_len over 1514\r\n");
                    while (1);
                }

                addrbsb = (uint32_t) (ptr << 8) + (s << 5) + 0x18;
                w5500_reads(addrbsb, buf, data_len);
                ptr += data_len;

                w5500_write(Sn_RX_RD0(s), (uint8_t) ((ptr & 0xff00) >> 8));
                w5500_write(Sn_RX_RD1(s), (uint8_t) (ptr & 0x00ff));
                break;

            default:
                break;
        }
        w5500_write(Sn_CR(s), Sn_CR_RECV);

        /* wait to process the command... */
        while (w5500_read(Sn_CR(s)));
        /* ------- */
    }
    return data_len;
}


bool udp_socket_init(SOCKET s, uint16_t local_port) {
    udp_local_port = local_port;
    socket(s, Sn_MR_UDP, udp_local_port, 0);
    return true;
}

bool udp_send(SOCKET s, uint8_t *dst_ip, uint16_t dst_port, uint8_t *data, uint16_t len) {
    clearSocketFlag(s); /*清接收中断*/
    if (w5500_socket_status_read(s) != s_udp) {
        socket(s, Sn_MR_UDP, udp_local_port, 0);
    }
    return sendto(s, data, len, dst_ip, dst_port) == len ? true : false;
}

bool udp_rec(SOCKET s, uint16_t listen_port, uint8_t *dstIp, uint16_t *dstPort, uint8_t *recData, uint16_t *recLen) {
    uint16_t len;
    switch (w5500_socket_status_read(s)) /*获取socket的状态*/
    {
        case s_udp: /*socket初始化完成*/
            clearSocketFlag(s);
            if ((len = w5500_socket_rx_size_read(s)) > 0) /*接收到数据*/
            {
                recvfrom(s, recData, len, dstIp, dstPort); /*W5500接收计算机发送来的数据*/
                *recLen = len;
                recData[len] = 0x00;
                return true; /*添加字符串结束符*/
            }
            break;
        case s_closed:/*socket处于关闭状态*/
        default:
            socket(s, Sn_MR_UDP, listen_port, 0); /*初始化socket*/
            break;
    }
    return false;
}


void tcp_client_connect(SOCKET s, uint8_t *dst_ip, uint16_t dst_port) {
    uint8_t status = w5500_socket_status_read(s);
    if (status == s_close_wait) {
        disconnect(s);
        status = w5500_socket_status_read(s);
        LOG_D("close socket");
    }
    if (status == s_closed) {
        socket(s, Sn_MR_TCP, tcp_local_port++, Sn_MR_ND);
        status = w5500_socket_status_read(s);
        LOG_D("build socket");
    }
    if (status == s_init) {
        connect(s, dst_ip, dst_port);
        LOG_D("connect");

    }
}

bool tcp_client_send(SOCKET s, uint8_t *data, uint16_t len) {

    if (w5500_status_read(s) == s_established) {
        send(s, data, len);
        return true;
    }
    return false;
}

uint16_t tcp_client_rec(SOCKET s, uint8_t *out_data) {
    if (w5500_status_read(s) == s_established) {
        uint16_t len = w5500_socket_rx_size_read(s); /*定义len为已接收数据的长度*/
        if (len > 0) {
            recv(s, out_data, len); /*接收来自Client的数据*/
            return len;
        }
    }
    return 0;
}

/**
 * @brief 初始化tcp server 接口
 * @param s
 * @param listen_port
 * @param buf
 * @param buf_len
 */
void tcp_server_init(SOCKET s, uint16_t listen_port, w5500_buf_t *netData) {
    socket_port[s] = listen_port;
    socket_net_data[s] = netData;
    // 关闭上次的socket
    disconnect(s);
    close(s);
}

w5500_buf_t *tcp_server_listen(SOCKET s) {
    socket_status_type state = w5500_status_read(s);
    socket_net_data[s]->buf_len = 0;
    switch (state) {
        case s_closed: {
            socket(s, Sn_MR_TCP, socket_port[s], Sn_MR_ND); /*打开socket*/
            break;
        }
        case s_init: { /*socket建立监听*/
            listen(s);
            break;
        }
        case s_established: {/*与客户端建立连接*/
            clearSocketFlag(s);                       // 清除接收中断标志位
            uint16_t len = w5500_socket_rx_size_read(s); /*定义len为已接收数据的长度*/
            if (len > 0) {
                memset(socket_net_data[s]->buf, 0, socket_net_data[s]->buf_len);
                recv(s, socket_net_data[s]->buf, len); /*接收来自Client的数据*/
            } else {
                // 检查芯片处于连接状态,但网线已断开时,自动释放端口,避免下次无法连接
                if ((w5500_read(PHYCFGR) & 0x1) == 0) {
                    close(s);
                }
            }
            socket_net_data[s]->buf_len = len;
            return socket_net_data[s];
        }
        case s_listen: { /*服务端处于监听中*/
            // todo 统计失去控制时间
            break;
        }
        case s_close_wait: { /*客户端,主动断开连接*/
            disconnect(s);
            break;
        }

        default: {
            disconnect(s);
            close(s);
            break;
        }
    }

    return socket_net_data[s];

}



驱动测试

w5500硬件驱动接口实现

/*******************************************************************************
 *  Copyright (c) [scl]。保留所有权利。
 *     本文仅供个人学习和研究使用,禁止用于商业用途。
 ******************************************************************************/

#include "app_conf.h"
#include "w5500_config.h"

#if APP_CONFIG_W5500

static SPI_HandleTypeDef *w5500_spi = NULL;

sys_force_static_inline void send_and_rec_bytes(uint8_t *in_dat, uint8_t *out_data, uint16_t len) {
    if (in_dat == NULL && out_data == NULL) return;
    uint8_t *p_tx = in_dat;
    uint8_t *p_rx = out_data;
    if (p_tx == NULL) {
        p_tx = p_rx;
    } else if (p_rx == NULL) {
        p_rx = p_tx;
    }
    HAL_SPI_TransmitReceive(w5500_spi, p_tx, p_rx, len, 100);
}

sys_force_static_inline void W5500_RST_HIGH(void) {
    pin_high(GPIOB, GPIO_PIN_10);
}

sys_force_static_inline void W5500_RST_LOW(void) {
    pin_low(GPIOB, GPIO_PIN_10);
}

sys_force_static_inline void W5500_CS_LOW(void) {
    pin_low(GPIOB, GPIO_PIN_12);
}

sys_force_static_inline void W5500_CS_HIGH(void) {
    pin_high(GPIOB, GPIO_PIN_12);
}

sys_force_static_inline void W5500_Driver_MspInit(void) {
    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    pin_low(GPIOB, GPIO_PIN_12 | GPIO_PIN_10);
    /*CS*/
    gpio_init(GPIOB, GPIO_PIN_12, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW);
    /*RST*/
    gpio_init(GPIOB, GPIO_PIN_10, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW);
    /*初始化SPI外设*/
    /*W5500 支持 SPI 模式 0 及模式 3..MOSI 和 MISO 信号无论是接收或发送,均遵从从最高标志位(MSB)到最低标志位(LSB)的传输序列。*/
    bsp_SpiHandleInit(w5500_spi, SPI_BAUDRATEPRESCALER_2, spi_mode_0);
}

module_w5500_t w5500_conf = {
        .base_conf={
                .socket_num = 4,
                .rx_size={4, 4, 4, 4},
                .tx_size={4, 4, 4, 4},
        },
        .net_conf={
                .ip={192, 168, 8, 98},
                .gw={192, 168, 8, 1},
                .sub={255, 255, 255, 0},
        },
        .driver={
                .cs_high = W5500_CS_HIGH,
                .cs_low = W5500_CS_LOW,
                .rst_high= W5500_RST_HIGH,
                .rst_low=W5500_RST_LOW,
                .delay = HAL_Delay,
                .send_and_rec_bytes = send_and_rec_bytes
        },
        .api = {
                .msp_init=W5500_Driver_MspInit,
//                .log = os_ps
        }
};


static void w5500_pre_init(void) {
    /*一般做数据加载,此时系统时钟使用的是内部时钟,如需要使用系统时钟的外设不在此进行初始化*/
    w5500_spi = conv_spi_handle_ptr(handle_get_by_id(spi2_id));
    /*初始化资源*/
    module_w5500_init(&w5500_conf);
    uint32_t uid0 = HAL_GetUIDw0();
    uint32_t uid1 = HAL_GetUIDw1();
    uint32_t uid2 = HAL_GetUIDw2();
    uint8_t mac[6] = {0, uid0 >> 8, uid1, uid1 >> 8, uid2, uid2 >> 8};
    memcpy(w5500_conf.net_conf.mac, mac, sizeof(mac));
}

static void w5500_init(void) {
    /*初始化*/
    w5500_conf.api.msp_init();
}


static void w5500_after_init(void) {
    w5500_conf.net_conf_init();
//    printf("w5500 invoke after\r\n");
}

app_init_export(w5500_net_conf, w5500_pre_init, w5500_init, w5500_after_init);
#endif



测试结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/694920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java发送邮件-工具类-基于springboot

那么&#xff0c;废话少说&#xff0c;直接上代码。 1. 目录结构 重点是那几个带mail的&#xff0c;其他文件不用管。 2. pom <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schema…

【Java-14】3万字深入理解HashMap集合(高级)

1.HashMap集合简介 ​ HashMap基于哈希表的Map接口实现&#xff0c;是以key-value存储形式存在&#xff0c;即主要用来存放键值对。HashMap 的实现不是同步的&#xff0c;这意味着它不是线程安全的。它的key、value都可以为null。此外&#xff0c;HashMap中的映射不是有序的。…

chatgpt赋能python:Python跑步轨迹生成:如何利用Python生成跑步轨迹

Python跑步轨迹生成&#xff1a;如何利用Python生成跑步轨迹 如果你经常跑步&#xff0c;你可能会想知道你每次跑步的轨迹&#xff0c;而不仅仅是跑步的距离和时间。这时&#xff0c;Python可以帮助你生成跑步轨迹&#xff0c;并且还可以将轨迹可视化。在本文中&#xff0c;我…

软考高级系统架构设计师(五) 系统性能评价

目录 概要 性能指标 性能调整 ​阿姆达尔 性能评价 概要 性能指标 参考&#xff1a;【软考-系统架构设计师】知识要点-8 - 知乎 响应时间&#xff1a; 0.1秒&#xff1a;用户感觉不到任何延迟&#xff1b;1.0秒&#xff1a;用户愿意接受的系统立即响应的时间极限&#x…

Liunx 安装MySQL 8 社区版

1.下载MySQL版本 在官网可直接找见对应版本 wget https://dev.mysql.com/get/mysql80-community-release-el8-5.noarch.rpmrpm -ivh mysql80-community-release-el8-5.noarch.rpm2. 使用命令 ls /etc/yum.repos.d/ | grep mysql 查看是否存在以下两个repo文件 3.更新yum资源 …

云原生改造- istio (二)

目录 1 VirtualService 文件 2 DestinationRule 文件 3 演示结果 前提 基于内容的灰度发布&#xff0c;保证在chrome下可以访问V2版本&#xff0c;其他浏览器可以访问v1. 1 VirtualService 文件 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata:n…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)二:登录界面及对应功能实现

一、本章内容 本章介绍系统登录界面、登录流程、登录接口等相关内容的开发,实现包括账号密码登录、短信验证登录等不同的登录方式,使用svg-capter生成图形验证码,使用expressjwt实现登录token的生成及验证。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预…

CNAS软件测评实验室内审流程与技巧

软件检测实验室通过内部审核活动&#xff0c;可以验证内部体系的运行是否符合管理体系的要求&#xff0c;在内审时&#xff0c;需要审核宜检查管理体系是否满足 ISO/IEC17025 或 ISO/IEC17020、或其他相关准则文件的要求&#xff0c;即符合性检查。 还要检查组织的质量手册及相…

npm install 报错 gyp 解决方案

问题&#xff1a; 接手别人的项目&#xff0c;在安装项目依赖npm install时&#xff0c;一直提示 gyp相关的错误。 问题原因&#xff1a; 项目中依赖项"node-sass": "^4.14.1",与当前node.js版本不符合。 解决问题&#xff1a; 通过百度踩坑&#xff0c;…

nslookup提示-bash: nslookup: command not found

nslookup使用时&#xff0c;提示-bash: nslookup: command not found的错误。 yum install -y nslookup提示No package nslookup available.。 yum provides nslookup查看一下那个安装包提供nslookup命令。 yum install -y bind-utils安装bind-utils。 nslookup,然后输…

为什么同样是手机,你拍的照片没别人好看?避开4个常见摄影坑,秒变摄影师!

你有没有过这样的疑惑&#xff1a;为什么同一个场景&#xff0c;有的人可以用手机拍出大片感、电影感、史诗感&#xff0c;而你拍出来的照片却平平无奇&#xff0c;甚至有些毁人毁景&#xff1f; 如果说出片效果的差别是因为器材、手机参数一样导致的&#xff0c;那多少还可以…

数据结构--单链表的查找

数据结构–单链表的查找 均以带头结点链表为例 目标&#xff1a; GetElem(Li):按位查找操作。获取表L中第i个位置的元素的值。 LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。 按位查找 按位查找,返回第i 个元素&#xff08;带头结点) 代码实现 typ…

【算法题】动态规划基础阶段之斐波那契数列、青蛙跳台阶问题、连续子数组的最大和

动态规划基础阶段 前言一、斐波那契数列1.2、思路1.2、代码实现 二、青蛙跳台阶问题2.2、思路2.2、代码实现 三、连续子数组的最大和3.1、思路3.2、代码实现 总结 前言 动态规划&#xff08;Dynamic Programming&#xff0c;简称 DP&#xff09;是一种解决多阶段决策过程最优化…

Unity编辑器开发——特性(常用特性、自定义特性)

特性在Unity开发中是非常好用的。 常用特性&#xff1a; 下面记录下我常用的C#预置的特性&#xff1a; 一、程序集级别 二、脚本级别 三、脚本成员级别 1.字段 (1)Int/Float (2)string (3)Enum (4)List (5)Range(滑动条&#xff0c;其实也是对Int/Float&#xff09; …

TypeError: transpileDependencies.map is not a function——解决办法——亲测有效

今天在npm run serve项目的时候遇到一个问题&#xff0c;终端提示TypeError: transpileDependencies.map is not a function&#xff0c;项目跑不起来。 网上搜到的解决办法&#xff1a; 网上提供的解决办法基本上是&#xff1a; 1.npm audit fix执行才会报这个错——没用 2.…

深入理解 Golang: Go 程序的编译运行过程

Go program 编译过程 package mainimport "fmt"func main() {fmt.Println("Hello Go") }编译前端 词法分析 将源代码翻译成 Token(最小语义结构) 句法分析 Token 序列经过处理&#xff0c;变成语法树 AST 语义分析 类型检查类型推断函数调用内联逃逸分析…

C语言学习笔记---初始C语言005

C语言程序设计笔记---005 初识C语言三大结构语句函数数组操作符1、初识C语言三个结构2、初识函数3、初识一维数组4、初识C语言操作符4.1、算数操作符例程4.2、赋值操作符例程4.3、关系操作符例程4.4、复合操作符例程4.5、单目操作符例程4.6、条件操作符例程4.7、逻辑操作符例程…

222. 完全二叉树的节点个数

题目描述&#xff1a; 主要思路&#xff1a; 利用二分答案的思想进行求解。 首先遍历到最底下的最左结点&#xff0c;然后可以得到一个答案范围&#xff0c;然后二分求解验证即可。 具体细节见代码。 /*** Definition for a binary tree node.* struct TreeNode {* int v…

工程安全监测无线振弦采集仪在建筑物的应用

工程安全监测无线振弦采集仪在建筑物的应用 工程安全监测无线振弦采集仪是一种先进的监测设备&#xff0c;可以在建筑物、桥梁、隧道、大坝等工程施工或运营中进行振动监测和安全评估。其在建筑物的应用主要是针对建筑物结构的振动和变形进行监测和分析&#xff0c;以确保建筑…

java抽象类中的静态方法

Java的抽象类中可以包含静态方法&#xff0c;即类方法。尽管抽象类不能实例化&#xff0c;但抽象类中的静态方法是可以用抽象类直接调用的。 下面的代码示例定义了一个抽象类AbstractDemo &#xff0c;其中包含一个抽象方法method&#xff0c;一个public静态方法showMessage。…