# How to Test UDP Example
## Step 1: Prepare software
The following serial terminal program and UDP test tool are required for the UDP example test, download and install from below links.
- [Tera Term][link-tera_term]
- [Hercules][link-hercules]
## Step 2: Prepare hardware
1. Connect the WIZnet Ethernet chip (W5500 or W6300) to the ESP32-S3 board over SPI, following the pin table in [Step 3](#step-3-setup-udp-example).
2. Connect an Ethernet cable from the module's RJ45 port to your PC or network.
3. Connect the ESP32-S3 board to your PC with a USB cable.
![][link-hardware]
## Step 3: Setup UDP Example
### Chip and SPI configuration
Set the target and open menuconfig:
```bash
idf.py set-target esp32s3
idf.py menuconfig
```
Select **Component config**.
![][link-config_main]
Select **WIZnet WSM Driver** under Component config.
![][link-config_component]
Choose the WIZnet chip, and check the per-socket buffer size. SPI host, clock, and pins follow the selected chip automatically. In this example, SPI2 of the ESP32-S3 is used at 33 MHz.
![][link-config_wiz_toe]
> This example ships with **W6300** selected by default (`sdkconfig.defaults`). Switch to W5500 under `Component config -> WIZnet WSM Driver -> WIZnet chip` if needed.
**W5500 wiring (standard SPI)**
| W5500 | ESP32-S3 Pin |
|-------|--------------|
| MISO | 13 |
| MOSI | 11 |
| SCLK | 12 |
| CS | 10 |
| RESET | 9 |
| INT | 14 |
**W6300 wiring (QSPI)**
| W6300 | ESP32-S3 Pin |
|---------|--------------|
| D0 (MOSI) | 11 |
| D1 (MISO) | 13 |
| D2 (IO2) | 14 *(Quad mode only)* |
| D3 (IO3) | 9 *(Quad mode only)* |
| SCLK | 12 |
| CS | 10 |
| RESET | 21 |
| INT | 8 |
### Network configuration
Network identity and ports live in `examples/udp/inc/net_config.h`, the same way as
in `examples/loopback`:
```cpp
#define NET_MAC_ADDR {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56}
#define NET_IP_ADDR {192, 168, 11, 2}
#define NET_SUBNET_MASK {255, 255, 255, 0}
#define NET_GATEWAY {192, 168, 11, 1}
#define NET_DNS_ADDR {8, 8, 8, 8}
#define WIFI_SSID "" /* empty -> Ethernet only */
#define WIFI_PASS ""
#define UDP_ECHO_PORT 5000 /* Ethernet, server role */
#define UDP_ECHO_CLIENT_PORT 50000 /* Ethernet, client role */
#define WIFI_UDP_ECHO_PORT 5001 /* Wi-Fi, server role */
#define WIFI_UDP_ECHO_CLIENT_PORT 50001 /* Wi-Fi, client role */
#define UDP_ECHO_BUF_SIZE 2048
```
`main.c` assembles a `wiz_NetInfo` from these and hands it to `wiznet_net_init()`,
which applies it to the chip with `wizchip_setnetinfo()`.
### Running on Wi-Fi at the same time (optional)
Fill in `WIFI_SSID` and the same echo engine also comes up on a Wi-Fi STA, as a
sibling task at the same level as the Ethernet one:
```cpp
udp_echo_start("eth", &net_eth_ops, UDP_ECHO_BIND_PORT, wiznet_net_is_up);
udp_echo_start("wifi", &net_wifi_ops, WIFI_UDP_ECHO_BIND_PORT, wifi_net_is_up);
```
The two interfaces use different ports because with `SOCKET_WRAP=0` (esp_eth
backend) they share one LwIP stack, where identical ports would clash on bind.
Wait for this line before testing the Wi-Fi side — the socket only opens once DHCP
has assigned an address:
```
I (xxxx) wifi: got IP 192.168.11.7
I (xxxx) udp_echo: [wifi] UDP echo on port 5001
```
Leave `WIFI_SSID` empty when committing; an empty SSID skips Wi-Fi entirely so the
example still builds and runs for everyone else.
### UDP role configuration
Select the role in menuconfig under **UDP Example Configuration -> UDP role**
(`EXAMPLE_UDP_ROLE`):
- **UDP server** — `EXAMPLE_UDP_SERVER` (default): binds `UDP_ECHO_PORT` (5000)
and echoes every datagram back to its sender.
- **UDP client** — `EXAMPLE_UDP_CLIENT`: binds `UDP_ECHO_CLIENT_PORT` (50000),
echoes the same way, and additionally logs each received payload.
Both roles are echo responders — they never initiate. That matches the ioLibrary
reference this example is ported from, where `loopback_udpc()` likewise only
opens an ephemeral port and replies; the difference between the two roles is the
local port and the logging.
### Architecture
Same layout as `examples/loopback`:
| Path | Role |
|------|------|
| `inc/net_config.h` | network identity, ports, buffer size |
| `inc/udp_echo.h` | engine API |
| `src/udp_echo.c` | backend-neutral echo engine (BSD sockets via a vtable) |
| `main/main.c` | orchestration only: bring the chip up, start the task |
The engine calls BSD sockets through the component's `net_sock_ops_t` vtable and
is handed `net_eth_ops` — the plain `lwip_*` entry points, which the `wsm_driver`
component redirects to the WIZnet hardware sockets at link time via `-Wl,--wrap`
(`CONFIG_WSM_DRIVER_SOCKET_WRAP`). Running the same engine on Wi-Fi as well is a
second `udp_echo_start()` call with `net_wifi_ops`.
## Step 4: Build
After completing the setup, build the project.
```bash
idf.py build
```
![][link-build_log]
## Step 5: Upload and Run
Flash the firmware and open the serial monitor. Replace the port with your board's serial port.
```bash
idf.py -p COMx flash monitor
```
On Linux/macOS:
```bash
idf.py -p /dev/ttyUSB0 flash monitor
```
If flashing succeeds, the assigned IP and the UDP server start logs appear in the terminal.
```
I (361) wiztoe_net: TOE up: 192.168.11.2 (WIZnet hardware TCP/IP)
I (362) udp_echo: [eth] waiting for link...
I (365) udp_echo: [eth] UDP echo on port 5000
```
![][link-run_socket_open]
Open Hercules, select the **UDP** tab, set the **Module IP** to the device IP `192.168.11.2` with **Port** `5000`, set a **Local Port**, then send a UDP datagram.
![][link-run_hercules]
The device echoes the same datagram back to your PC, confirming the UDP loopback works.
![][link-run_loopback]
## Appendix
- **UDP client role:** Select `EXAMPLE_UDP_CLIENT` in menuconfig. The device then binds port `50000` instead of `5000` and logs each datagram it echoes. Point Hercules at `192.168.11.2:50000` to exercise it.
- **W6300 QSPI mode:** Quad mode (4-bit) requires the extra D2/D3 lines wired and selected in `Component config -> WIZnet WSM Driver -> W6300 QSPI mode`. Single mode uses the same 4-wire wiring as W5500.
<!-- Link -->
[link-tera_term]: https://osdn.net/projects/ttssh2/releases/
[link-hercules]: https://www.hw-group.com/software/hercules-setup-utility
[link-hardware]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/hardware.png
[link-config_main]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/config_main.png
[link-config_component]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/config_component.png
[link-config_wiz_toe]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/config_wiz_toe.png
[link-build_log]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/build_log.png
[link-run_socket_open]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/run_socket_open.png
[link-run_hercules]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/run_hercules.png
[link-run_loopback]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/udp/run_loopback.png
To create a project from this example, run:
idf.py create-project-from-example "wiznet/wsm_driver=1.1.0:udp"