Wiznet makers

Grace_Koo

Published January 31, 2025 ©

0 UCC

10 WCC

0 VAR

0 Contests

0 Followers

0 Following

Building a TCP Multi-Socket Server with W55RP20 & W5500

Building a TCP Multi-Socket Server with W55RP20 & W5500

COMPONENTS Hardware components

WIZnet - W55RP20-EVB-Pico

x 1

Software Apps and online services

microsoft - VS Code

x 1


PROJECT DESCRIPTION

In this WCC, we will use the TCP server multi-socket example. WIZnet's W5500 chip can open up to 8 sockets, while the W5100S can open up to 4 sockets. The w55rp20, which we’re using today, also allows up to 8 sockets.

Use Cases for Multiple TCP Sockets

1. Handling Multiple Clients Simultaneously

  • Each client needs an independent communication channel with the server.
  • ex) Chat applications, multiplayer games, web servers.

2. Separation of Data Types

  • Different sockets can handle control signals (e.g., commands) and data streams (e.g., file transfer) separately for better organization.
  • ex) Video conferencing apps (control vs. media streams).

3. Error Isolation

  • Problems in one socket (e.g., a failed client connection) won't affect other connections.
  • ex) IoT systems with multiple devices sending data to a server.

4. Scalability for Large User Bases

  • Servers need multiple sockets to support thousands of concurrent users or devices.
  • ex) Large-scale web platforms, cloud services, or game servers.

https://github.com/WIZnet-ioNIC/WIZnet-PICO-C/tree/main/examples/tcp_server_multi_socket

I will use the example from the above link to establish communication between the W55RP20-EVB-Pico and W5500-EVB-Pico.

The example in the above link demonstrates a TCP loopback server capable of opening multiple sockets. However, in this WCC, I will slightly modify the approach:

the W55RP20 will function as a TCP server, capable of opening up to eight multi-sockets, while the W5500 will act as a TCP client, connecting to the W55RP20 for communication.

Among the multiple sockets, socket 0 will be responsible for transmitting messages regarding the status of the multi-sockets, while the remaining sockets will operate as loopback servers.

 

Let's start by setting up the server.

When you first run the tcp_server_multi_socket example, you will see that sockets 0 to 7 are in the listen state, as shown in the following output.

In this basic example, immediately after a specific socket connection is established, we check how many sockets are actively communicating.

The number of sockets that are in the established state is sent to socket 0. Note that since socket numbers are assigned sequentially in this example, the first client that connects to the server will be assigned to socket 0.

Additionally, a message is also sent when a socket is closed, as shown in the following modification.

 

The TCP client using the W5500 was tested by removing only the part of the example that sends messages in a loopback.

https://github.com/WIZnet-ioNIC/WIZnet-PICO-C/tree/main/examples/loopback

The following is the execution screen. In addition to the W5500, the TCP client was tested by creating two additional clients using Hercules.

When the client is first executed, it connects to the server, and the following screen is displayed. 

TCP server's screen (W55RP20)

In the client screen, the message "0sn is connected. total:1socket" is shown, indicating that socket 0 has been connected to the server and a total of one socket is in the established state.

TCP client 0's screen (W5500)

 

The following is the screen showing another client connecting and then closing. Each client sent one message before disconnecting.

TCP server's screen (W55RP20)

The client on socket 0 receives the status messages as follows.

TCP client 0's screen (W5500)

Sockets other than socket 0 operate in loopback mode as follows.

Other TCP clients's screen

  • The following is the code for the TCP server.
#include <stdio.h>
#include <string.h>
#include "port_common.h"
#include "wizchip_conf.h"
#include "w5x00_spi.h"
#include "socket.h"

/* Clock */
#define PLL_SYS_KHZ (133 * 1000)

/* Buffer */
#define ETHERNET_BUF_MAX_SIZE (1024 * 2) // Send and receive cache size
#define _LOOPBACK_DEBUG_

#define _SOCKETS_5100S 4
#define _SOCKETS_5500 8

wiz_NetInfo net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x11}, // Define MAC variables
    .ip = {192, 168, 11, 33},                    // Define IP variables
    .sn = {255, 255, 255, 0},                    // Define subnet variables
    .gw = {192, 168, 11, 1},                     // Define gateway variables
    .dns = {168, 126, 63, 1},                    // Define DNS  variables
    .dhcp = NETINFO_STATIC};                     // Define the DNCP mode

static uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {
    0,
};
static uint16_t local_port = 8000; // Local port

static void set_clock_khz(void);
int32_t loopback_tcps_multi_socket(uint8_t *buf, uint16_t port);

int main()
{
    set_clock_khz();

    /*mcu init*/
    stdio_init_all(); // Initialize the main control peripheral.
    wizchip_spi_initialize();
    wizchip_cris_initialize();
    wizchip_reset();
    wizchip_initialize(); // spi initialization
    wizchip_check();

    network_initialize(net_info);

    print_network_information(net_info); // Read back the configuration information and print it

    while (true)
    {
        loopback_tcps_multi_socket(ethernet_buf, local_port);
    }
}

static void set_clock_khz(void)
{
    // set a system clock frequency in khz
    set_sys_clock_khz(PLL_SYS_KHZ, true);

    // configure the specified clock
    clock_configure(
        clk_peri,
        0,                                                // No glitchless mux
        CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
        PLL_SYS_KHZ * 1000,                               // Input frequency
        PLL_SYS_KHZ * 1000                                // Output (must be same as no divider)
    );
}

int32_t loopback_tcps_multi_socket(uint8_t *buf, uint16_t port)
{
    static uint8_t sn = 0;
    int32_t ret;
    uint16_t size = 0, sentsize = 0;
    uint8_t destip[4];
    uint16_t destport;
    uint8_t state_buf[1024];
    int cnt = 0;

    switch (getSn_SR(sn))
    {
    case SOCK_ESTABLISHED:
        if (getSn_IR(sn) & Sn_IR_CON)
        {
            getSn_DIPR(sn, destip);
            destport = getSn_DPORT(sn);

            printf("%d:Connected - %d.%d.%d.%d : %d\r\n", sn, destip[0], destip[1], destip[2], destip[3], destport);
            setSn_IR(sn, Sn_IR_CON);

            if (_WIZCHIP_ == W5500)
            {
                for (int i = 0; i < _SOCKETS_5500; i++)
                {
                    if (SOCK_ESTABLISHED == getSn_SR(i))
                    {
                        cnt++;
                    }
                }
                memset(state_buf, 0, sizeof(state_buf));
                snprintf((char *)state_buf, sizeof(state_buf), "**%dsn is Connected. **total:%dsockets\r\n", sn, cnt);
                send(0, state_buf, sizeof(state_buf));
            }
            else if (_WIZCHIP_ == W5100S)
            {
                for (int i = 0; i < _SOCKETS_5100S; i++)
                {
                    if (SOCK_ESTABLISHED == getSn_SR(i))
                    {
                        cnt++;
                    }
                }
                memset(state_buf, 0, sizeof(state_buf));
                snprintf((char *)state_buf, sizeof(state_buf), "**%dsn is Connected. **total:%dsockets\r\n", sn, cnt);
                send(0, state_buf, sizeof(state_buf));
            }
        }
        if (sn != 0 && (size = getSn_RX_RSR(sn)) > 0) // Don't need to check SOCKERR_BUSY because it doesn't not occur.
        {
            if (size > ETHERNET_BUF_MAX_SIZE)
                size = ETHERNET_BUF_MAX_SIZE;
            ret = recv(sn, buf, size);
            if (ret <= 0)
                return ret; // check SOCKERR_BUSY & SOCKERR_XXX. For showing the occurrence of SOCKERR_BUSY.
            size = (uint16_t)ret;
            buf[size] = 0x00;

            sentsize = 0;
            while (size != sentsize)
            {
                ret = send(sn, buf + sentsize, size - sentsize);
                if (ret < 0)
                {
                    close(sn);
                    return ret;
                }
                sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
            }
            getSn_DIPR(sn, destip);
            destport = getSn_DPORT(sn);
            printf("socket%d from:%d.%d.%d.%d port: %d  message:%s\r\n", sn, destip[0], destip[1], destip[2], destip[3], destport, buf);
        }
        break;
    case SOCK_CLOSE_WAIT:
#ifdef _LOOPBACK_DEBUG_
        // printf("%d:CloseWait\r\n",sn);
#endif
        if ((ret = disconnect(sn)) != SOCK_OK)
            return ret;
#ifdef _LOOPBACK_DEBUG_
        memset(state_buf, 0, sizeof(state_buf));
        snprintf((char *)state_buf, sizeof(state_buf), "**%d:Socket Closed\r\n", sn);
        send(0, state_buf, sizeof(state_buf));
        printf("%d:Socket Closed\r\n", sn);
#endif
        break;
    case SOCK_INIT:
#ifdef _LOOPBACK_DEBUG_
        printf("%d:Listen, TCP server loopback, port [%d]\r\n", sn, port);
#endif
        if ((ret = listen(sn)) != SOCK_OK)
            return ret;
        break;
    case SOCK_CLOSED:
#ifdef _LOOPBACK_DEBUG_
        // printf("%d:TCP server loopback start\r\n",sn);
#endif
        if ((ret = socket(sn, Sn_MR_TCP, port, Sn_MR_ND)) != sn)
            return ret;
#ifdef _LOOPBACK_DEBUG_
            // printf("%d:Socket opened\r\n",sn);
#endif
        break;
    default:
        break;
    }
#if (_WIZCHIP_ == W5100S)
    if (sn < _SOCKETS_5100S)
    {
        sn++;
    }
    else
    {
        sn = 0;
    }
#elif (_WIZCHIP_ == W5500)
    if (sn < _SOCKETS_5500)
    {
        sn++;
    }
    else
    {
        sn = 0;
    }
#endif

    return 1;
}
Documents
  • example : tcp_server_multi_socket

Comments Write