host_network_split__power_save

Example of the component espressif/esp_hosted v2.1.5
# Network Split with Host Deep Sleep Example

This example shows how to use two powerful ESP-Hosted features together: **Network Split** and **Host Deep Sleep**. These features allow a host MCU to save power by sleeping while the slave device keeps the network connection alive and only wakes the host when necessary.

## What This Example Does

**Network Split** - Smart traffic routing:
- Host handles important traffic (ports 49152-61439)  
- Slave handles background traffic (ports 61440-65535)
- No unnecessary host wake-ups


**Host Deep Sleep** - Ultra-low power mode:
- Host can sleep while slave stays connected to WiFi
- Slave wakes host only for important traffic
- Wake-up can also be triggered by commands or MQTT messages

## Supported Platforms and Transports

### Supported Co-processors

| Co-Processors Supported | ESP32-C5 | ESP32-C6/C61 | ESP32 | ESP32-S2 | ESP32-S3 |
| :---------------------- | :------- | :----------- | :---- | :------- | :------- |

### Supported Host MCUs

| Hosts Supported | ESP32-P4 | ESP32-H2 | Any other MCU hosts |
| :-------------- | :------- | :------- | :------------------ |

### Supported Transport Interfaces

| Transport Interface | SDIO | SPI Full-Duplex | SPI Half-Duplex | UART |
| :------------------ | :--- | :-------------- | :-------------- | :--- |

## Example Hardware Used

This example is designed for the **ESP32-P4-Function-EV-Board** with its built-in ESP32-C6.

**Default setup:**
- **Host**: ESP32-P4 (handles important network traffic)
- **Slave**: ESP32-C6 (maintains WiFi and handles background traffic)  
- **Connection**: SDIO (pre-wired on the board)
- **Wake-up wire**: Already connected between GPIO2 (slave) and GPIO6 (host)

All listed items in default setup are customizable to suit specific use cases and requirements.


## Flash the Slave (ESP32-C6)

The slave needs ESP-Hosted firmware with Network Split and Host Power Save enabled.

With below additional configuration, Flash the slave using setup instructions, see: [Slave Example Guide](../../slave/README.md)


#### Slave Side Configuration:

Using `idf.py menuconfig`, Enable:

```
# Minimal slave config
Example Configuration
├── [*] Enable Network Split
└── [*] Allow host to power save
```

**Advanced slave settings** (optional):
```
Example Configuration
└── Network Split Configuration
    ├── Host Static Port Forwarding
    │   ├── TCP dst: 22,80,443,8080,8554
    │   └── UDP dst: 53,123
    ├── Port Ranges
    │   ├── Host: 49152–61439
    │   └── Slave: 61440–65535
    └── Host power save config
        ├── Allow host to enter deep sleep
        ├── Slave out: Host wakeup GPIO (2)
        └── Host Wakeup GPIO Level (High)
```

Continue to build and flash slave using [Slave Example Guide](../../slave/README.md)


## Flash the Host (ESP32-P4)

The host needs ESP-Hosted firmware with Network Split and Host Power Save configured.

**Essential host configuration:**
1. Set target: `idf.py set-target esp32p4`

2. Network split and Host power save is pre-configured in this example.
(Optionally) customise the configuration using `idf.py menuconfig`
```
Component config
└── ESP-Hosted config
    ├── [*] Enable Network Split
    │    └── Network Split Configuration
    │        └── Port Ranges
    │            ├── Host: 49152–61439
    │            └── Slave: 61440–65535
    └── [*] Enable Host Power Save
         └── Host Power Save Configuration
            [*] Allow host to enter deep sleep.
             └── Deep Sleep Configuration
                 ├── Host Wakeup GPIO (6)
                 └── Host wakeup GPIO active low
```

3. Build and flash: `idf.py build && idf.py -p <HOST_PORT> flash monitor`

## Testing the Example

### Basic Power Save Test
1. Wait for both devices to connect to WiFi
2. Connect to AP using command, `sta_connect <SSID> <Password>`
3. On host console: type `host-power-save` 
4. Host goes to sleep, slave stays connected
5. On slave console: type `wake-up-host` to wake the host

### Smart Wake-up Test
1. Put host to sleep using `host-power-save`
2. Send dummy TCP/UDP packet to the device IP in host ports (49152–61439)  → host wakes automatically
3. Send dummy TCP/UDP packet to the device IP in slave ports (61440-65535) → slave handles without waking host

##### Sample program to test Network based `Smart Wake-up Test`

<summary>C program to send UDP packet:</br></br>send_udp_pkt.c</summary>
<details>

```c
// SPDX-License-Identifier: Apache-2.0
// Copyright 2015-2025 Espressif Systems (Shanghai) PTE LTD

/* This is just sample program to send sample udp packet */

/*
====================================================================
                 send_udp_pkt.c
====================================================================
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <IP> <PORT>\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *ip = argv[1];
    int port = atoi(argv[2]);
    const char *msg = "Hello, UDP!";

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        perror("socket");
        return EXIT_FAILURE;
    }

    // Non-blocking mode
    int flags = fcntl(sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flags | O_NONBLOCK);

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
    };
    inet_pton(AF_INET, ip, &addr.sin_addr);

    ssize_t sent = sendto(sock, msg, strlen(msg), 0,
                         (struct sockaddr *)&addr, sizeof(addr));

    if (sent < 0) {
        if (errno == EWOULDBLOCK || errno == EAGAIN) {
            fprintf(stderr, "sendto would block, try again later\n");
        } else {
            perror("sendto");
        }
    } else {
        printf("Sent %zd bytes to %s:%d\n", sent, ip, port);
    }

    close(sock);
    return EXIT_SUCCESS;
}
```
</details>


<summary>Shell script to trigger wake-up: </br></br>send_udp_pkt.sh</summary>
<details>

```bash
#!/bin/bash

# Simple script to build and run send_udp_pkt.c

#====================================================================
#                 send_udp_pkt.sh
#====================================================================
# Check if IP address is provided
if [ $# -eq 0 ]; then
    echo "❌ Error: IP address is required!"
    echo "Usage: $0 <ip_address> [port]"
    echo "Example: $0 192.168.1.100 60000"
    exit 1
fi

IP_ADDRESS="$1"
DEFAULT_PORT="60000"

# Check if port is provided as second argument
if [ $# -ge 2 ]; then
    PORT="$2"
else
    PORT="$DEFAULT_PORT"
    echo "No port specified, using default port: $DEFAULT_PORT"
fi

echo "===== Network Split Host Wakeup with UDP Packet Tool ====="
echo "Target: $IP_ADDRESS:$PORT"
echo "Building and running network wakeup utility..."

# Compile the program
gcc -o send_udp_pkt send_udp_pkt.c -pthread

# Check if compilation succeeded
if [ $? -ne 0 ]; then
    echo "❌ Compilation failed!"
    exit 1
fi

echo "✅ Build successful!"
echo "Starting network wakeup utility..."
echo "-------------------------------------------"

# Run the program with IP address and port
./send_udp_pkt $IP_ADDRESS $PORT

# Capture result
RESULT=$?
if [ $RESULT -eq 0 ]; then
    echo "-------------------------------------------"
    echo "✅ Network wakeup packet sent successfully to $IP_ADDRESS:$PORT!"
else
    echo "-------------------------------------------"
    echo "❌ Network wakeup failed with code: $RESULT"
fi

exit $RESULT
```
</details>

Create both files in some temporary directory and run:
```bash
bash send_udp_pkt.sh <device_ip_address> 62000 # Send packet to slave port             --> ❌ No host wake up

bash send_udp_pkt.sh <device_ip_address> 123   # Send packet to host reserved udp port ==> ✅ host wake up
```

> [!TIP]
>
> You can design your packet routing & filtering as per application application use-case and deploy in slave firmware.
> Refer to the https://github.com/espressif/esp-hosted-mcu/blob/663d6631af6e7a6735755e2247ab60363fda87c8/slave/main/lwip_filter.c#L349

### Performance Test
1. Run iPerf server: `iperf -s -p 5001`
2. From another device: `iperf -c <device_ip> -p 5001`
3. Watch logs to see which device handles the traffic
For more details on iperf tests, refer [iperf test](README_iperf.md)

## Customizing for Other Hardware

#### Different Transport (e.g., SPI instead of SDIO)

**Slave side:**
```
Example Configuration
└── Bus Config in between Host and Co-processor
    └── Transport layer
        └── (X) SPI Full-duplex
```

**Host side:**
```
Component config
└── ESP-Hosted config
    └── Transport layer
        └── (X) SPI Full-duplex
```

Configure the specific GPIO pins for the chosen transport bus and Host wake up GPIO pin

#### Different MCU Combination
1. Change `idf.py set-target` to your MCU
2. Update GPIO pins in menuconfig to match your wiring
3. Make sure wake-up GPIO on host supports deep sleep wake-up

## Troubleshooting

**Host won't wake up:**
- Check GPIO wire connection between slave GPIO2 and host GPIO6
- Verify host GPIO6 supports RTC wake-up
- Check GPIO level settings match on both sides

**WiFi connection fails:**
- Double-check WiFi credentials in both devices
- Make sure both devices use the same WiFi settings

**Traffic not splitting correctly:**
- Check port range settings in slave menuconfig
- Monitor logs to see packet routing decisions
- Verify Network Split is enabled on slave

## References

- [Network Split Documentation](../../docs/feature_network_split.md)
- [Host Power Save Documentation](../../docs/feature_host_power_save.md)
- [ESP32-P4-Function-EV-Board Guide](../../docs/esp32_p4_function_ev_board.md)
- [Slave Example Guide](../../slave/README.md)
- [Main ESP-Hosted Documentation](../../README.md)


To create a project from this example, run:

idf.py create-project-from-example "espressif/esp_hosted=2.1.5:host_network_split__power_save"

or download archive (~12.47 KB)