W5500 Development Notes | 02 - use W5500 Socket API to establish TCP server and TCP client

Series articles

1, Realization idea

W5500 is a hardware TCP/IP protocol stack internally. External (MCU) only provides the ability to operate sockets. Internally, it supports 8 independent sockets, and each socket is controlled through Socket n register area (0 ≤ n ≤ 7).

Therefore, when writing the network application based on Socket, it can be realized according to the idea of querying the Socket status register to realize a state machine.

The W5500 driver library provides the read macro of Socket status register:

/**
 * @ingroup Socket_register_access_function
 * @brief Get @ref Sn_SR register
 * @param (uint8_t)sn Socket number. It should be <b>0 ~ 7</b>.
 * @return uint8_t. Value of @ref Sn_SR.
 */
#define getSn_SR(sn) \
		WIZCHIP_READ(Sn_SR(sn))

The W5500 driver library also provides macro definitions for the read out status values:

/* Sn_SR values */
#define SOCK_CLOSED                  0x00
#define SOCK_INIT                    0x13
#define SOCK_LISTEN                  0x14
#define SOCK_SYNSENT                 0x15 	// The temporary status when the Socket n status changes. A connection request has been sent to the other party
#define SOCK_SYNRECV                 0x16 	// The temporary state when the Socket n state changes. The connection request packet is successfully received
#define SOCK_ESTABLISHED             0x17	
#define SOCK_FIN_WAIT                0x18 	// The temporary state when the Socket n state changes. The socket is closing
#define SOCK_CLOSING                 0x1A 	// The temporary state when the Socket n state changes. The socket is closing
#define SOCK_TIME_WAIT               0x1B 	// The temporary state when the Socket n state changes. The socket is closing
#define SOCK_CLOSE_WAIT              0x1C
#define SOCK_LAST_ACK                0x1D 	// The temporary state when the Socket n state changes. When the socket is in the passive closed state, it is waiting to respond to the disconnection request

2, Implementation of TCP server

1. Realize functions

Implement a TCP server, which can receive the request of TCP client, print after receiving the client data, and send back the received data.

2. TCP server state machine

3. Implementation code

Write demo file_ server. c:

#include "socket.h"
#include <stdio.h>

#define DATA_BUF_SIZE			2048
static uint8_t recv_buf[DATA_BUF_SIZE];

int tcp_server(uint8_t sn, uint16_t port)
{
    int8_t ret;
    uint8_t dest_ip[4];
    uint16_t dest_port;
    uint16_t size = 0;
    
    switch (getSn_SR(sn)) {
    
        case SOCK_CLOSED:
            /* open socket */
            printf("TCP server start\r\n");
            if ((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) {
                printf("socket %d open fail\r\n", sn);
                return ret;
            }
            printf("socket %d open success\r\n", sn);
            break;
        
        case SOCK_INIT:
            /* waiting for a client to connect */
            printf("listen %d port...\r\n", port);
            if ((ret = listen(sn)) != SOCK_OK) {
                printf("%d:listen fail\r\n", sn);
                return ret;
            }
            printf("%d:listen success\r\n", sn);
            break;
        case SOCK_ESTABLISHED:
            /* socket has been established */
            if(getSn_IR(sn) & Sn_IR_CON) {
                getSn_DIPR(sn, dest_ip);
                dest_port = getSn_DPORT(sn);
                printf("%d:a client connect success, %d.%d.%d.%d:%d\r\n", sn, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
                
                setSn_IR(sn,Sn_IR_CON);
            }
            
            // get the size of recv data in recv buffer
            if ((size = getSn_RX_RSR(sn)) > 0) {
                if (size > DATA_BUF_SIZE) {
                    size = DATA_BUF_SIZE;
                }
                
                //recv data
                ret = recv(sn, recv_buf, DATA_BUF_SIZE);     
                if (ret <= 0) {
                    printf("%d:recv fail\r\n", sn);
                    return ret;
                } else {
                    // The actual received size
                    size = (uint16_t)ret;
                    printf("%d:recv size:%d\r\n", sn, size);
                    recv_buf[size] = '\0';
                    printf("%d:recv data:[%s]\r\n", sn, recv_buf);
                }
                
                //send resp data
                ret = send(sn, recv_buf, size);
                if (ret <= 0) {
                    printf("%d:send fail\r\n", sn);
                    
                    //close the socket
                    close(sn);
       
                    return ret;
                } else {
                    // The actual sent size
                    size = (uint16_t)ret;
                    printf("%d:send size:%d\r\n", sn, size);
                    recv_buf[size] = '\0';
                    printf("%d:send data:[%s]\r\n", sn, recv_buf);
                }   
            }
            break;
            
        case SOCK_CLOSE_WAIT:
            /* closing the socket */
            if ((ret = disconnect(sn)) != SOCK_OK) {
                printf("%d:disconnect fail\r\n", sn);
                return ret;
            }
            printf("%d: socket is closed\r\n", sn);
            break;
        
        default:
            break;
    }
    
    return 0;
}

4. Achieve results

Add the prepared demo file to the project in main The test function is declared in C:

extern int tcp_server(uint8_t sn, uint16_t port);

Because the implementation of the function is a state machine, it is called in while(1):

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
	/* USER CODE END WHILE */
	
	/* USER CODE BEGIN 3 */
	tcp_server(0, 8000);
}
/* USER CODE END 3 */

Compile, download to the development board, and use the serial port assistant to view the results:

Run socket debugging assistant on PC to establish a tcp client connection development board:

After connecting the TCP client, you can see the information printed out by the development board:

Then send information in the network debugging assistant:

It can be seen that after the network debugging assistant sends it, it receives the message sent back by the development board, and the log can also be seen on the development board:

When the TCP client is disconnected, check the serial port log of the development board:

3, Implementation of TCP client

1. Realize functions

Implement a TCP client, which can initiate the request of TCP client, first send data to the server, then receive the data sent back by the server, and then print.

2. TCP client state machine

3. Implementation code

Write demo file_ client. c:

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

#define DEFAULT_PORT            6000
#define DATA_BUF_SIZE			2048
static uint8_t send_buf[DATA_BUF_SIZE];
static uint8_t recv_buf[DATA_BUF_SIZE];

int tcp_client(uint8_t sn, uint8_t *dest_ip, uint16_t dest_port)
{
    int8_t ret;
    uint16_t recv_size = 0;
    uint16_t send_size = 0;
    
    switch (getSn_SR(sn)) {
    
        case SOCK_CLOSED:
            /* open socket */
            printf("TCP client start\r\n");
            if ((ret = socket(sn, Sn_MR_TCP, DEFAULT_PORT, 0x00)) != sn) {
                printf("socket %d open fail\r\n", sn);
                return ret;
            }
            printf("socket %d open success\r\n", sn);
            break;
        
        case SOCK_INIT:
            /* connect server */
            printf("try to connect %d.%d.%d.%d:%d...\r\n", dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
            if ((ret = connect(sn, dest_ip, dest_port)) != SOCK_OK) {
                return ret;
            }
            break;
        case SOCK_ESTABLISHED:
            /* socket has been established */
            if(getSn_IR(sn) & Sn_IR_CON) {
                printf("%d:Connected to - %d.%d.%d.%d : %d\r\n",sn, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], dest_port);
                setSn_IR(sn,Sn_IR_CON);
            }
            
             // get the size of recv data in recv buffer
            if ((recv_size = getSn_RX_RSR(sn)) > 0) {
                if (recv_size > DATA_BUF_SIZE) {
                    recv_size = DATA_BUF_SIZE;
                }
                
                //recv data
                ret = recv(sn, recv_buf, DATA_BUF_SIZE);     
                if (ret <= 0) {
                    printf("%d:recv fail\r\n", sn);
                    return ret;
                } else {
                    // The actual received size
                    recv_size = (uint16_t)ret;
                    printf("%d:recv size:%d\r\n", sn, recv_size);
                    recv_buf[recv_size] = '\0';
                    printf("%d:recv data:[%s]\r\n", sn, recv_buf);
                }
                
                  //send data
                strcpy((char*)send_buf, "Hello, Server!");
                ret = send(sn, send_buf, strlen((char*)send_buf));
                if (ret <= 0) {
                    printf("%d:send fail\r\n", sn);

                    //close the socket
                    close(sn);

                    return ret;
                } else {
                    // The actual sent size
                    send_size = (uint16_t)ret;
                    printf("%d:send size:%d\r\n", sn, send_size);
                    //recv_buf[size] = '\0';
                    printf("%d:send data:[%s]\r\n", sn, send_buf);
                } 
            }
            break;
            
        case SOCK_CLOSE_WAIT:
            /* closing the socket */
            if ((ret = disconnect(sn)) != SOCK_OK) {
                printf("%d:disconnect fail\r\n", sn);
                return ret;
            }
            printf("%d: socket is closed\r\n", sn);
            break;
        
        default:
            break;
    }
    
    return 1;
}

In main Target address and target port defined in C:

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t dest_ip[4] = {192, 168, 10, 156};
uint16_t dest_port = 8000;

/* USER CODE END PV */

Declare test function:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern int tcp_client(uint8_t sn, uint8_t *dest_ip, uint16_t dest_port);

/* USER CODE END 0 */

Loop call in while(1):

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
	/* USER CODE END WHILE */
	
	/* USER CODE BEGIN 3 */
	tcp_client(0, dest_ip, dest_port);
}
/* USER CODE END 3 */

4. Experimental results

First, use the network debugging assistant to set up a TCP server on the computer. At port 8000:

Then compile the download program:

Send a message in the network debugging assistant, and you can see the message sent back by the development board after receiving the data:

You can also see the log on one side of the development board:

Added by cubik on Fri, 11 Feb 2022 07:07:53 +0200