Clion开发STM32之W5500系列(四)

news2024/10/6 20:36:55

W5500协议层之DHCP功能

头文件

#ifndef STM32_VET6_W5500_DHCP_H
#define STM32_VET6_W5500_DHCP_H


#include "socket.h"

#define DEVICE_ID "w5500"
#define IP_CONFLICT_STR "CHECK_IP_CONFLICT"
#define  DHCP_FLAGSBROADCAST     0x8000
/* UDP port numbers for DHCP */
#define  DHCP_SERVER_PORT        67    /* from server to client */
#define  DHCP_CLIENT_PORT        68    /* from client to server */
/* DHCP message OP code */
#define  DHCP_BOOTREQUEST        1
#define  DHCP_BOOTREPLY          2
/* DHCP message type */
#define  DHCP_DISCOVER           1
#define  DHCP_OFFER              2
#define  DHCP_REQUEST            3
#define  DHCP_DECLINE            4
#define  DHCP_ACK                5
#define  DHCP_NAK                6
#define  DHCP_RELEASE            7
#define  DHCP_INFORM             8
#define DHCP_HTYPE10MB           1
#define DHCP_HTYPE100MB          2
#define DHCP_HLENETHERNET        6
#define DHCP_HOPS                0
#define DHCP_SECS                0
#define MAGIC_COOKIE             0x63825363
#define DEFAULT_XID              0x12345678
#define MAX_DHCP_OPT    16
/* DHCP state machine. */
enum {
    STATE_DHCP_READY = 0,
    STATE_DHCP_DISCOVER,
    STATE_DHCP_REQUEST,
    STATE_DHCP_LEASED,
    STATE_DHCP_REREQUEST,
    STATE_DHCP_RELEASE,
};
/* DHCP option and value (cf. RFC1533) */
enum {
    padOption = 0,
    subnetMask = 1,
    timerOffset = 2,
    routersOnSubnet = 3,
    timeServer = 4,
    nameServer = 5,
    dns = 6,
    logServer = 7,
    cookieServer = 8,
    lprServer = 9,
    impressServer = 10,
    resourceLocationServer = 11,
    hostName = 12,
    bootFileSize = 13,
    meritDumpFile = 14,
    domainName = 15,
    swapServer = 16,
    rootPath = 17,
    extentionsPath = 18,
    IPforwarding = 19,
    nonLocalSourceRouting = 20,
    policyFilter = 21,
    maxDgramReasmSize = 22,
    defaultIPTTL = 23,
    pathMTUagingTimeout = 24,
    pathMTUplateauTable = 25,
    ifMTU = 26,
    allSubnetsLocal = 27,
    broadcastAddr = 28,
    performMaskDiscovery = 29,
    maskSupplier = 30,
    performRouterDiscovery = 31,
    routerSolicitationAddr = 32,
    staticRoute = 33,
    trailerEncapsulation = 34,
    arpCacheTimeout = 35,
    ethernetEncapsulation = 36,
    tcpDefaultTTL = 37,
    tcpKeepaliveInterval = 38,
    tcpKeepaliveGarbage = 39,
    nisDomainName = 40,
    nisServers = 41,
    ntpServers = 42,
    vendorSpecificInfo = 43,
    netBIOSnameServer = 44,
    netBIOSdgramDistServer = 45,
    netBIOSnodeType = 46,
    netBIOSscope = 47,
    xFontServer = 48,
    xDisplayManager = 49,
    dhcpRequestedIPaddr = 50,
    dhcpIPaddrLeaseTime = 51,
    dhcpOptionOverload = 52,
    dhcpMessageType = 53,
    dhcpServerIdentifier = 54,
    dhcpParamRequest = 55,
    dhcpMsg = 56,
    dhcpMaxMsgSize = 57,
    dhcpT1value = 58,
    dhcpT2value = 59,
    dhcpClassIdentifier = 60,
    dhcpClientIdentifier = 61,
    endOption = 255
};
typedef struct _RIP_MSG {
    uint8_t op;
    uint8_t htype;
    uint8_t hlen;
    uint8_t hops;
    uint32_t xid;
    uint16_t secs;
    uint16_t flags;
    uint8_t ciaddr[4];
    uint8_t yiaddr[4];
    uint8_t siaddr[4];
    uint8_t giaddr[4];
    uint8_t chaddr[16];
    uint8_t sname[64];
    uint8_t file[128];
    uint8_t OPT[312];
} RIP_MSG;
void dhcp_init();

void dhcp_config_registry(module_w5500_t *conf);


bool do_dhcp(SOCKET s, uint32_t timeout_cnt);


#endif //STM32_VET6_W5500_DHCP_H

源文件

#include "w5500_dhcp.h"

#define DBG_ENABLE
#define DBG_SECTION_NAME "dhcp"
#define DBG_LEVEL DBG_INFO

#include "sys_dbg.h"

uint8_t EXTERN_DHCPBUF[1024];
RIP_MSG *pRIPMSG = (RIP_MSG *) EXTERN_DHCPBUF; /*DHCP消息指针*/
uint32_t DHCP_XID = DEFAULT_XID;

uint8_t OLD_SIP[4]; /*最初获取到的IP地址*/
uint8_t DHCP_SIP[4] = {0}; /*已发现的DNS服务器地址*/
uint8_t DHCP_REAL_SIP[4] = {0};/*从DHCP列表中选择使用的DHCP服务器*/

static module_w5500_t *w5500_ptr;

uint32_t dhcp_lease_time;                                           /*租约时间*/

void send_DHCP_DISCOVER(SOCKET s);                                      /*向DHCP服务器发送发现报文*/
void send_DHCP_REQUEST(SOCKET s, uint8_t pkt_type);                                       /*向DHCP服务器发送请求报文*/
void send_DHCP_RELEASE_DECLINE(SOCKET s, char msgtype);                       /*向DHCP服务器发送释放报文*/

uint8_t parseDHCPMSG(SOCKET s, uint16_t length);

uint8_t check_leasedIP(SOCKET s);           /*检查获取的IP是否冲突*/
uint8_t *SRC_MAC_ADDR = NULL;                       /*本地MAC地址*/
uint8_t *GET_SIP = NULL;                            /*从DHCP服务器获取到的本机IP*/
uint8_t *GET_GW_IP = NULL;                          /*从DHCP服务器获取到的网关地址*/
uint8_t *GET_SN_MASK = NULL;                        /*从DHCP服务器获取到的子网掩码*/
uint8_t GET_DNS_IP[4] = {0};                              /*从DHCP服务器获取到的DNS服务器地址*/
void dhcp_config_registry(module_w5500_t *conf) {
    w5500_ptr = conf;
    GET_SIP = conf->net_conf.ip;
    GET_SN_MASK = conf->net_conf.sub;
    SRC_MAC_ADDR = conf->net_conf.mac;
    GET_GW_IP = conf->net_conf.gw;
}

void dhcp_init() {
    /*该引脚需要保持低电平至少 500 us,才能重置 W5500;*/
    w5500_ptr->driver.rst_low();
    w5500_ptr->driver.delay(3);
    w5500_ptr->driver.rst_high();
    w5500_ptr->driver.delay(1600);
    w5500_chip_init();
    /*设置mac地址*/
    w5500_writes(MAC_ADDR, w5500_ptr->net_conf.mac, 6);
    /*初始化Socket的发送接收缓存大小*/
    for (uint8_t i = 0; i < w5500_ptr->base_conf.socket_num; i++) {
        w5500_write(Sn_TXMEM_SIZE(i), w5500_ptr->base_conf.tx_size[i]);
        w5500_write(Sn_RXMEM_SIZE(i), w5500_ptr->base_conf.rx_size[i]);
    }
}


uint16_t wait_DHCP_Response(SOCKET s, uint32_t timeout_cnt) {
    uint16_t len;
    uint8_t type = 0;
    for (int i = 0; i < timeout_cnt; ++i) {
        len = w5500_socket_rx_size_read(s);
        if (len > 0) {
            type = parseDHCPMSG(s, len);
            break;
        } /*接收到数据*/
    }
    return type;
}

bool do_dhcp(SOCKET s, uint32_t timeout_cnt) {
    uint16_t type;
    if (udp_client_init(s, DHCP_CLIENT_PORT)) {
        // 01-发送DISCOVER包
        send_DHCP_DISCOVER(s);
        // 02-等待响应
        type = wait_DHCP_Response(s, timeout_cnt);
        if (type == DHCP_OFFER) {
            send_DHCP_REQUEST(s, STATE_DHCP_REQUEST); /*发送REQUEST包*/
            type = wait_DHCP_Response(s, timeout_cnt);
            if (type == DHCP_ACK) {
                LOG_D("dhcp_lease_time is %d", dhcp_lease_time);
                if (check_leasedIP(s)) {
                    memcpy(OLD_SIP, GET_SIP, 4);
                    DHCP_XID++;
                    send_DHCP_REQUEST(s, STATE_DHCP_LEASED);
                    type = wait_DHCP_Response(s, timeout_cnt);
                    if (type != DHCP_ACK && type != 0) {
                        LOG_W("release dhcp connect error:%d", type);
                    }
                    LOG_D("config ip start");
                    w5500_writes(SUB_ADDR, w5500_ptr->net_conf.sub, 4); /*子网掩码*/
                    w5500_writes(GAR_ADDR, w5500_ptr->net_conf.gw, 4); /*网关*/
                    w5500_writes(SIPR_ADDR, w5500_ptr->net_conf.ip, 4); /*IP配置*/
                    LOG_I("<DHCP GET IP OK>");
                    LOG_I("IP:%d.%d.%d.%d", w5500_ptr->net_conf.ip[0], w5500_ptr->net_conf.ip[1],
                          w5500_ptr->net_conf.ip[2], w5500_ptr->net_conf.ip[3]);
                    return true;
                } else {
                    LOG_W("state : DHCP_RET_CONFLICT");
                }
            } else if (type == DHCP_NAK) {
                LOG_W("send_DHCP_REQUEST is DHCP_NAK ");
            }
        }
    }
    return false;
}


uint8_t check_leasedIP(SOCKET s) {
    LOG_D("<Check the IP Conflict %d.%d.%d.%d: ", GET_SIP[0], GET_SIP[1], GET_SIP[2], GET_SIP[3]);
    if (sendto(s, (uint8_t *) IP_CONFLICT_STR, strlen(IP_CONFLICT_STR), GET_SIP, 5000)) {
        send_DHCP_RELEASE_DECLINE(s, 1);
        return 0;
    }
    return 1;
}

/**
 *@brief	 	解析获得的DHCP消息
 *@param		length:解析消息长度
 *@return	0:解析失败  其他:解析成功
 */
uint8_t parseDHCPMSG(SOCKET s, uint16_t length) {
    uint8_t svr_addr[6];
    uint16_t svr_port;
    uint16_t len;
    uint8_t *p;
    uint8_t *e;
    uint8_t type;
    uint8_t opt_len = 0;

    len = recvfrom(s, (uint8_t *) pRIPMSG, length, svr_addr, &svr_port);

    LOG_D("DHCP_SIP:%u.%u.%u.%u", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
    LOG_D("DHCP_RIP:%u.%u.%u.%u", DHCP_REAL_SIP[0], DHCP_REAL_SIP[1], DHCP_REAL_SIP[2], DHCP_REAL_SIP[3]);
    LOG_D("svr_addr:%u.%u.%u.%u", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3]);

    if (pRIPMSG->op != DHCP_BOOTREPLY || svr_port != DHCP_SERVER_PORT) {
        LOG_D("DHCP : NO DHCP MSG");
        return 0;
    }
    if (memcmp(pRIPMSG->chaddr, SRC_MAC_ADDR, 6) != 0 || pRIPMSG->xid != htonl(DHCP_XID)) {
        LOG_W("No My DHCP Message. This message is ignored.");
        LOG_W("\tSRC_MAC_ADDR(%02X.%02X.%02X.%02X.%02X.%02X)",
              SRC_MAC_ADDR[0], SRC_MAC_ADDR[1], SRC_MAC_ADDR[2],
              SRC_MAC_ADDR[3], SRC_MAC_ADDR[4], SRC_MAC_ADDR[5]);
        LOG_W(", pRIPMSG->chaddr(%02X.%02X.%02X.", (char) pRIPMSG->chaddr[0], (char) pRIPMSG->chaddr[1],
              (char) pRIPMSG->chaddr[2]);
        LOG_W("%02X.%02X.%02X)", pRIPMSG->chaddr[3], pRIPMSG->chaddr[4], pRIPMSG->chaddr[5]);
        LOG_W("\tpRIPMSG->xid(%08X), DHCP_XID(%08X)", pRIPMSG->xid, (DHCP_XID));
        LOG_W("\tpRIMPMSG->yiaddr:%d.%d.%d.%d", pRIPMSG->yiaddr[0], pRIPMSG->yiaddr[1], pRIPMSG->yiaddr[2],
              pRIPMSG->yiaddr[3]);
        return 0;
    }

    if (*((uint32_t *) DHCP_SIP) != 0x00000000) {
        if (*((uint32_t *) DHCP_REAL_SIP) != *((uint32_t *) svr_addr) &&
            *((uint32_t *) DHCP_SIP) != *((uint32_t *) svr_addr)) {
            LOG_D("Another DHCP sever send a response message. This is ignored.");
            LOG_D("\tIP:%u.%u.%u.%u", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3]);
            return 0;
        }
    }
    memcpy(GET_SIP, pRIPMSG->yiaddr, 4);

    LOG_D("DHCP MSG received");
    LOG_D("yiaddr : %u.%u.%u.%u", GET_SIP[0], GET_SIP[1], GET_SIP[2], GET_SIP[3]);
    type = 0;
    p = (uint8_t *) (&pRIPMSG->op);
    p = p + 240;
    e = p + (len - 240);
    LOG_D("p : %08X  e : %08X  len : %d", (uint32_t) p, (uint32_t) e, len);
    while (p < e) {
        switch (*p++) {
            case endOption:
                return type;
            case padOption:
                break;
            case dhcpMessageType:
                opt_len = *p++;
                type = *p;
                LOG_D("dhcpMessageType : %02X", type);
                break;

            case subnetMask:
                opt_len = *p++;
                memcpy(GET_SN_MASK, p, 4);
                break;

            case routersOnSubnet:
                opt_len = *p++;
                memcpy(GET_GW_IP, p, 4);
                break;

            case dns:
                opt_len = *p++;
                memcpy(GET_DNS_IP, p, 4);
                break;

            case dhcpIPaddrLeaseTime:
                opt_len = *p++;
                dhcp_lease_time = ntohl(*((uint32_t *) p));
                break;

            case dhcpServerIdentifier:
                opt_len = *p++;
                if (*((uint32_t *) DHCP_SIP) == 0 ||
                    *((uint32_t *) DHCP_REAL_SIP) == *((uint32_t *) svr_addr) ||
                    *((uint32_t *) DHCP_SIP) == *((uint32_t *) svr_addr)) {
                    memcpy(DHCP_SIP, p, 4);
                    memcpy(DHCP_REAL_SIP, svr_addr, 4); // Copy the real ip address of my DHCP server
                    LOG_D("My dhcpServerIdentifier : %u.%u.%u.%u",
                          DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
                    LOG_D("My DHCP server real IP address :%u.%u.%u.%u",
                          DHCP_REAL_SIP[0], DHCP_REAL_SIP[1], DHCP_REAL_SIP[2], DHCP_REAL_SIP[3]);
                } else {
                    LOG_D("Another dhcpServerIdentifier : MY(%u.%u.%u.%u) Another(%u.%u.%u.%u)",
                          DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3],
                          svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3]);
                }
                break;
            default:
                opt_len = *p++;
                break;
        } // switch
        p += opt_len;
    } // while
    return 0;
}


/**
 *@brief		发送DISCOVER信息给DHCP服务器
 *@param		无
 *@return	无
 */
void send_DHCP_DISCOVER(SOCKET s) {
    uint8_t ip[4] = {255, 255, 255, 255};
    uint16_t i = 0;
    // the host name modified
    uint8_t host_name[12];
    memset((void *) pRIPMSG, 0, sizeof(RIP_MSG)); /*清空pRIPMSG的 sizeof(RIP_MSG)	个空间*/
    pRIPMSG->op = DHCP_BOOTREQUEST;
    pRIPMSG->htype = DHCP_HTYPE10MB;
    pRIPMSG->hlen = DHCP_HLENETHERNET;
    pRIPMSG->hops = DHCP_HOPS;
    pRIPMSG->xid = htonl(DHCP_XID);
    pRIPMSG->secs = htons(DHCP_SECS);
    pRIPMSG->flags = htons(DHCP_FLAGSBROADCAST);
    /*mac地址*/
    memcpy(pRIPMSG->chaddr, SRC_MAC_ADDR, 6);
    /* MAGIC_COOKIE */
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 24) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 16) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 8) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) (MAGIC_COOKIE & 0xFF);

    /* Option Request Param. */
    pRIPMSG->OPT[i++] = dhcpMessageType;
    pRIPMSG->OPT[i++] = 0x01;
    pRIPMSG->OPT[i++] = DHCP_DISCOVER;

    /*Client identifier*/
    pRIPMSG->OPT[i++] = dhcpClientIdentifier;
    pRIPMSG->OPT[i++] = 0x07;
    pRIPMSG->OPT[i++] = 0x01;

    memcpy(pRIPMSG->OPT + i, SRC_MAC_ADDR, 6);
    i += 6;
    // host name
    pRIPMSG->OPT[i++] = hostName;
    // set the host name
    sprintf((char *) host_name, "%.4s-%02X%02X%02X", DEVICE_ID,
            SRC_MAC_ADDR[3], SRC_MAC_ADDR[4], SRC_MAC_ADDR[5]);

    pRIPMSG->OPT[i++] = (uint8_t) strlen((char *) host_name);

    strcpy((char *) (&(pRIPMSG->OPT[i])), (char *) host_name);

    i += (uint16_t) strlen((char *) host_name);

    pRIPMSG->OPT[i++] = dhcpParamRequest;
    pRIPMSG->OPT[i++] = 0x06;
    pRIPMSG->OPT[i++] = subnetMask;
    pRIPMSG->OPT[i++] = routersOnSubnet;
    pRIPMSG->OPT[i++] = dns;
    pRIPMSG->OPT[i++] = domainName;
    pRIPMSG->OPT[i++] = dhcpT1value;
    pRIPMSG->OPT[i++] = dhcpT2value;
    pRIPMSG->OPT[i++] = endOption;
    /* send broadcasting packet */
    sendto(s, (uint8_t *) pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
    LOG_D("sent DHCP_DISCOVER");
}

void send_DHCP_REQUEST(SOCKET s, uint8_t pkt_type) {
    uint8_t ip[4], host_name[12];
    uint16_t i = 0;
    memset((void *) pRIPMSG, 0, sizeof(RIP_MSG));
    pRIPMSG->op = DHCP_BOOTREQUEST;
    pRIPMSG->htype = DHCP_HTYPE10MB;
    pRIPMSG->hlen = DHCP_HLENETHERNET;
    pRIPMSG->hops = DHCP_HOPS;
    pRIPMSG->xid = htonl(DHCP_XID);
    pRIPMSG->secs = htons(DHCP_SECS);

    if (pkt_type < STATE_DHCP_LEASED)
        pRIPMSG->flags = htons(DHCP_FLAGSBROADCAST);
    else {
        pRIPMSG->flags = 0; // For Unicast
        memcpy(pRIPMSG->ciaddr, GET_SIP, 4);
    }

    memcpy(pRIPMSG->chaddr, SRC_MAC_ADDR, 6);

    /* MAGIC_COOKIE */
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 24) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 16) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 8) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) (MAGIC_COOKIE & 0xFF);

    /* Option Request Param. */
    pRIPMSG->OPT[i++] = dhcpMessageType;
    pRIPMSG->OPT[i++] = 0x01;
    pRIPMSG->OPT[i++] = DHCP_REQUEST;

    pRIPMSG->OPT[i++] = dhcpClientIdentifier;
    pRIPMSG->OPT[i++] = 0x07;
    pRIPMSG->OPT[i++] = 0x01;
    memcpy(pRIPMSG->OPT + i, SRC_MAC_ADDR, 6);
    i += 6;
    if (pkt_type < STATE_DHCP_LEASED) {
        pRIPMSG->OPT[i++] = dhcpRequestedIPaddr;
        pRIPMSG->OPT[i++] = 0x04;
        memcpy(pRIPMSG->OPT + i, GET_SIP, 4);
        i += 4;
        pRIPMSG->OPT[i++] = dhcpServerIdentifier;
        pRIPMSG->OPT[i++] = 0x04;
        memcpy(pRIPMSG->OPT + i, DHCP_SIP, 4);
        i += 4;
    }
    // host name
    pRIPMSG->OPT[i++] = hostName;
    // set the host name
    sprintf((char *) host_name, (char *) "%.4s-%02X%02X%02X", DEVICE_ID, SRC_MAC_ADDR[3], SRC_MAC_ADDR[4],
            SRC_MAC_ADDR[5]);
    pRIPMSG->OPT[i++] = (uint8_t) strlen((char *) host_name);
    strcpy((char *) &(pRIPMSG->OPT[i]), (char *) host_name);
    i += strlen((char *) host_name);
    pRIPMSG->OPT[i++] = dhcpParamRequest;
    pRIPMSG->OPT[i++] = 0x08;
    pRIPMSG->OPT[i++] = subnetMask;
    pRIPMSG->OPT[i++] = routersOnSubnet;
    pRIPMSG->OPT[i++] = dns;
    pRIPMSG->OPT[i++] = domainName;
    pRIPMSG->OPT[i++] = dhcpT1value;
    pRIPMSG->OPT[i++] = dhcpT2value;
    pRIPMSG->OPT[i++] = performRouterDiscovery;
    pRIPMSG->OPT[i++] = staticRoute;
    pRIPMSG->OPT[i++] = endOption;
    /* send broadcasting packet */
    if (pkt_type < STATE_DHCP_LEASED)
        memset(ip, 0xFF, 4);
    else
        memcpy(ip, DHCP_SIP, 4);
    sendto(s, (uint8_t *) pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
    LOG_D("sent DHCP_REQUEST");
}

void send_DHCP_RELEASE_DECLINE(SOCKET s, char msgtype) {
    uint16_t i = 0;
    uint8_t ip[4];
    memset((void *) pRIPMSG, 0, sizeof(RIP_MSG));
    pRIPMSG->op = DHCP_BOOTREQUEST;
    pRIPMSG->htype = DHCP_HTYPE10MB;
    pRIPMSG->hlen = DHCP_HLENETHERNET;
    pRIPMSG->hops = DHCP_HOPS;
    pRIPMSG->xid = htonl(DHCP_XID);
    pRIPMSG->secs = htons(DHCP_SECS);
    pRIPMSG->flags = 0; // DHCP_FLAGSBROADCAST;
    memcpy(pRIPMSG->chaddr, SRC_MAC_ADDR, 6);

    /* MAGIC_COOKIE */
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 24) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 16) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) ((MAGIC_COOKIE >> 8) & 0xFF);
    pRIPMSG->OPT[i++] = (uint8_t) (MAGIC_COOKIE & 0xFF);

    /* Option Request Param. */
    pRIPMSG->OPT[i++] = dhcpMessageType;
    pRIPMSG->OPT[i++] = 0x01;
    pRIPMSG->OPT[i++] = ((!msgtype) ? DHCP_RELEASE : DHCP_DECLINE);

    pRIPMSG->OPT[i++] = dhcpClientIdentifier;
    pRIPMSG->OPT[i++] = 0x07;
    pRIPMSG->OPT[i++] = 0x01;
    memcpy(pRIPMSG->OPT + i, SRC_MAC_ADDR, 6);
    i += 6;
    pRIPMSG->OPT[i++] = dhcpServerIdentifier;
    pRIPMSG->OPT[i++] = 0x04;
    pRIPMSG->OPT[i++] = DHCP_SIP[0];
    pRIPMSG->OPT[i++] = DHCP_SIP[1];
    pRIPMSG->OPT[i++] = DHCP_SIP[2];
    pRIPMSG->OPT[i++] = DHCP_SIP[3];

    if (msgtype) {
        pRIPMSG->OPT[i++] = dhcpRequestedIPaddr;
        pRIPMSG->OPT[i++] = 0x04;
        pRIPMSG->OPT[i++] = GET_SIP[0];
        pRIPMSG->OPT[i++] = GET_SIP[1];
        pRIPMSG->OPT[i++] = GET_SIP[2];
        pRIPMSG->OPT[i++] = GET_SIP[3];
        LOG_D("sent DHCP_DECLINE\r\n");
    } else {
        LOG_D("sent DHCP_RELEASE");
    }

    pRIPMSG->OPT[i++] = endOption;

    if (msgtype)
        memset(ip, 0xFF, 4);
    else
        memcpy(ip, DHCP_SIP, 4);
    // printf("send dhcp decline\r\n");
    sendto(s, (uint8_t *) pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
}


测试

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

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

#if APP_CONFIG_W5500_DHCP
#define DBG_ENABLE
#define DBG_SECTION_NAME "w5500"
#define DBG_LEVEL W5500_DBG_LEVEL

#include "sys_dbg.h"
#include "w5500_dhcp.h"

#define W5500_CS stm_port_define(B,12)
#define W5500_RST stm_port_define(B,10)
static SPI_HandleTypeDef *w5500_spi = NULL;

static 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_rx == NULL) {
        HAL_SPI_Transmit(w5500_spi, p_tx, len, 10);
    } else {
        if (p_tx == NULL) {
            p_tx = p_rx;
        }
        HAL_SPI_TransmitReceive(w5500_spi, p_tx, p_rx, len, 10);
    }

}

static void W5500_RST_HIGH(void) { stm_pin_high(GPIOB, GPIO_PIN_10); }

static void W5500_RST_LOW(void) { stm_pin_low(GPIOB, GPIO_PIN_10); }

static void W5500_CS_LOW(void) { stm_pin_low(GPIOB, GPIO_PIN_12); }

static void W5500_CS_HIGH(void) { stm_pin_high(GPIOB, GPIO_PIN_12); }

static void W5500_Driver_MspInit(void) {
    stm32_pin_mode(W5500_CS, pin_mode_output);  /*CS*/
    stm32_pin_mode(W5500_RST, pin_mode_output); /*RST*/
    stm_pin_low(W5500_RST);
    stm_pin_low(W5500_CS);
    /*初始化SPI外设*/
    /*W5500 支持 SPI 模式 0 及模式 3..MOSI 和 MISO 信号无论是接收或发送,均遵从从最高标志位(MSB)到最低标志位(LSB)的传输序列。*/
    bsp_SpiHandleInit(w5500_spi, SPI_BAUDRATEPRESCALER_4, 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, 199, 12},
//                .gw={192, 168, 199, 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,
        }
};


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));
    dhcp_config_registry(&w5500_conf);
    w5500_conf.net_conf_init = dhcp_init;/*使用dhcp init*/
}

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");
    uint16_t try_cnt = 0;
    while (!do_dhcp(0, 0x1000)) {
        if (try_cnt > 20) {
            LOG_D("try timeout");
            break;
        }
        try_cnt++;
    }

}

app_init_export(w5500_net_conf, w5500_pre_init, w5500_init, w5500_after_init);

#endif





结果

在这里插入图片描述在这里插入图片描述

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

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

相关文章

π141E30S 200Mbps四通道数字隔离器兼容代替NSi8141S0

π141E30S荣湃深力科 200Mbps四通道数字隔离器兼容代替NSi8141S0 π141E30S数字隔离器具有出色的性能特 征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器。 在不需要调制和解调的情况下&#xff0c;实现电压信号跨越隔离介质精 准传输。 π141E30S传输通道…

利用ffmpeg使用脚本+excel批量合成视频

起因是忘了是什么时候&#xff0c;下载的视频是被切割的一个一个的&#xff0c;所以网上找了方法&#xff0c;利用ffmpeg批量进行了批量合成&#xff0c;这里记录一下&#xff0c;并用gpt解释一下脚本含义。 1、文件名批量转mp4格式 如果文件名不规范&#xff0c;可以利用exce…

spark Structured Streaming checkpoint参数优化

目录 1 问题描述2 分析 checkpointLocation 配置 2.1 checkpointLocation 在源码调用链2.2 MetadataLog&#xff08;元数据日志接口&#xff09;3 分析 checkpointLocation 目录内容 3.1 offsets 目录3.2 commitLog 目录3.3 metadata 目录3.4 sources 目录3.5 sinks 目录4 解决…

跨站脚本攻击XSS

​​​​​​1、漏洞原理及防御 XSS又叫CSS (CrossSiteScript),因为与层叠样式表(css)重名,所以叫Xss&#xff0c;中文名叫跨站脚本攻击。 xss攻击&#xff0c;主要就是攻击者通过“html注入”篡改了网页&#xff0c;插入了恶意的脚本&#xff0c;从而在用户浏览网页时&#…

迅为龙芯3A5000_7A2000COMe_模块和主板

龙芯 3A50007A2000 COME 采用全国产龙芯 3A5000 处理器&#xff0c;基于龙芯自主指令系统 (LoongArche)的 LA464 微结构&#xff0c;并进一步提升频率&#xff0c;降低功耗&#xff0c;优化性能。桥片采用龙芯 7A2000&#xff0c;支持 PCIE 3.0、USB 3.0 和 SATA 3.0、显示接口…

单独编译 Android 固件-打包 update.img-iTOP-RK3588开发板

进入到 3588-android12 文件夹&#xff0c;输入以下命令设置 java 版本为 1.8 版本&#xff0c;如下图所示: source javaenv.sh java -version 输入以下命令使能编译环境: source build/envsetup.sh lunch rk3588_s-userdebug 执行完上述命令&#xff0c;如果需要编译 uboo…

如何破解滑动验证码?

本文通过自动化查询域名或公司的备案信息&#xff0c;来演示其中图片滑动验证码的破解方式&#xff0c;以此来思考验证码的安全性问题&#xff0c;思考如何设计出安全性更高的验证码。 注意&#xff1a;破解验证码进行网络内容抓取可能是一种违规行为&#xff0c;可以以此进行验…

西门子PLC硬件编程需要注意的几个要点

往往一个好的编程程序习惯可以让事情事半功倍。用正确的逻辑思维和方法去写程序&#xff0c;一方面可以减少出错&#xff0c;另一方面就是方便检查程序里出现的bug。下面就为大家盘点一下&#xff0c;西门子PLC的一些硬件编程的好习惯。 1、关于选型 项目开始需要统计出IO点表…

Linux嵌入式项目-智能家居

一、资料下载 二、框架知识 三、MQTT通信协议 1、上位机APP主要工作 1.wait for msg / while(1)订阅等待消息 2.处理消息 客户端创建了两个线程&#xff0c;一个线程用于发布消息&#xff0c;一个线程用于监听订阅消息 &#xff08;那我的仿真系统也可以啊&#xff0c;一个…

《AutoSar实战》DIO配置

文章目录 前言一、配置过程1&#xff0c;选择引脚2&#xff0c;DIO模块配置1&#xff09;新建DioChannel 3&#xff0c;PORT模块配置4&#xff0c;保存并生成DIO&#xff0c;PORT模块 二、实现并验证1&#xff0c;调用函数接口2&#xff0c;示波器测量周期 总结 ->返回总目录…

富士施乐/Fuji Xerox SC2022 CPS DA 彩色激光复印机不能扫描的解决方法

一台富士施乐/Fuji Xerox SC2022 CPS DA 彩色激光复印机用网线连接的&#xff0c;有分配的IP地址&#xff0c;有三台电脑连接&#xff0c;可打印&#xff0c;但是不能扫描。 驱动也没问题&#xff0c;找了一台电脑先删除了打印机&#xff0c;在官网下载了驱动重新安装&#xff…

【Spring学习一】简单认识Spring是什么?——框架

目录 1、为什么要学习Spring&#xff1f; 2、Spring是什么&#xff1f; 1、IoC是什么&#xff1f; 2、进一步通过代码演示理解IoC 3、怎么理解容器&#xff1f; 4、知道DI与IoC的区别&#xff1f; 1、为什么要学习Spring&#xff1f; 我们常说的Spring 指的是 Spring Fra…

Microsoft 已经发布了7月份的产品安全问题修复报告。

&#x1f525;Microsoft 已经发布了7月份的产品安全问题修复报告。我们建议您关注趋势性漏洞&#xff0c;即那些已经或即将被攻击者积极利用的漏洞。 7月份报告中的两个危险漏洞&#xff1a; CVE-2023-32049和CVE-2023-35311。 CVE-2023-32049漏洞允许网络犯罪分子绕过Window…

卫星图片的Classification_model

Tensorflow版本&#xff1a;2.6.0 使用的是CNN神经网络&#xff0c;网络结构在最后给出 飞机和湖泊的卫星图片二分类网络 数据集请点击链接&#xff1a;https://www.kaggle.com/datasets/yo7oyo/lake-plane-binaryclass 数据集的构成&#xff1a;airplane: 700 张&#xff0c; …

着眼未来砥砺前行,知了汇智携西南交大学生走进企业参观学习

随着数字化转型推进的深入&#xff0c;企业对数字化人才的需求量大幅增长&#xff0c;人才需求结构也发生显著在变化。为加强学生与企业的接触&#xff0c;拓展专业视野&#xff0c;对接行业需求&#xff0c;激发学生对所学专业的兴趣&#xff0c;明确自己学习的目标&#xff0…

NC19 连续子数组的最大和

import java.util.*; public class Solution {public int FindGreatestSumOfSubArray(int[] array) {//记录到下标i为止的最大连续子数组和int[] dp new int[array.length]; dp[0] array[0];int maxsum dp[0];for(int i 1; i < array.length; i){//状态转移&#xff1a;…

优雅实现垂直SeekBar:不继承Seekbar、不自定义View

目录 0 前言 关于自定义View 1 实现竖直SeekBar 1.1 XML布局解析 1.1.1 套一层FrameLayout 1.1.2 SeekBar去除左右间距 1.1.3 SeekBar高度无法设置 1.1.4 SeekBar背景设置 1.1.5 底部View尺寸和距底部距离不硬编码 1.2 自定义样式属性与主题 1.2.1 自定义样式属性 …

应急管理大屏助力暴雨天气下的水灾防范

随着气候变化和城市化进程的加剧&#xff0c;暴雨天气引发的水灾风险日益凸显。在面对这种自然灾害时&#xff0c;如何高效、及时地应对、减轻损失成为了当务之急。水灾应急管理平台的可视化大屏为相关部门和决策者提供了实时、全面的信息展示和决策支持&#xff0c;大大提升了…

每天5个好用的实用工具链接分享(第1弹)

每天5个好用的实用工具链接分享&#xff08;第1弹&#xff09; 1、免费PPT模板网站2、科研狗租用GPU跑模型网站3、在线正则测试网站4、免费数据集下载网站5、在线curl命令转代码网站6、号外 1、免费PPT模板网站 【链接】&#xff1a;https://www.ypppt.com/ 【网站名】&#x…

性能测试工具 Jmeter 做 Http 接口测试 :编写自定义函数

目录 一、 前言 二、 编写自定义函数的步骤 1. 新建一个工程&#xff0c;导入 jmeter jar 包。 2. 新建 package&#xff1a;stressTest.functions 3. 新建一个类继承 AbstractFunction&#xff0c;重写以下方法&#xff1a; 4. 打包 5. 将打出来的 jar 包拷贝至 jmeter…