Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

esp_ppp

ESP-IDF firmware that turns an ESP32 into a WiFi-to-PPP gateway: it joins a WiFi network as a station and offers that connection to another MCU as a standard PPP server over UART, NAT'ing the MCU's traffic onto the WiFi link.

This can be used to provide WiFi capabilities to the MiSTle FPGA Companion via USB through a ESP32.

Built on Espressif's eppp_link component, configured for a real PPP netif (CONFIG_EPPP_LINK_USES_PPP=y) rather than its lighter proprietary framing, so the peer side can be any standard PPP client (lwIP ppp, Linux pppd, etc.) — not necessarily another eppp_link device.

Requirements

Build

1. Install ESP-IDF

If you don't already have ESP-IDF >= 5.2 installed, follow Espressif's Get Started guide, or in short:

git clone -b v5.4.1 --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh esp32

Each new shell needs the IDF environment loaded before using idf.py:

. $HOME/esp-idf/export.sh

2. Configure

From this project's directory:

idf.py set-target esp32
idf.py menuconfig   # set WiFi SSID/password under "esp_ppp Configuration"

The component manager fetches eppp_link (and its dependencies) into managed_components/ automatically the first time you build; no manual step is required.

3. Build, flash, monitor

idf.py build
idf.py -p /dev/ttyUSB0 flash monitor

Replace /dev/ttyUSB0 with the ESP32's serial port (omit -p to let idf.py auto-detect it). On Linux you may need to add your user to the dialout group (or uucp on some distros) to access the port without sudo:

sudo usermod -aG dialout $USER   # then log out/in for it to take effect

Use Ctrl+] to exit the serial monitor.

Wiring

Connect the ESP32's PPP UART to the peer MCU (cross TX/RX, common ground):

ESP32 Peer MCU
TX (default GPIO1) RX
RX (default GPIO3) TX
GND GND

Pins, UART port and baudrate are configurable under idf.py menuconfig -> esp_ppp Configuration. Default baudrate is 115200; lower it if the wiring/link is unreliable.

The default UART port (0) is the same UART used for the console/log output and for flashing, i.e. the board's built-in USB-serial adapter. That's convenient because it means no extra wiring is needed to talk PPP to the ESP32 (see Testing with a Linux PC below), but it also means log output and PPP framing will collide on the wire unless you either move the console to a different UART (idf.py menuconfig -> Component config -> ESP System Settings -> Channel for console output) or move the PPP link to a different UART/pins instead.

WiFi credentials

The WiFi SSID/password set via idf.py menuconfig are only compiled-in defaults ("changeme" / "changeme" out of the box). At runtime the firmware actually manages credentials like this:

  1. On boot, it tries to load a previously saved SSID/password from NVS (flash), namespace wifi_cfg.
  2. If none are stored yet (first boot), it prints No WiFi config present. and prompts for an SSID and password over the serial console instead of using the compiled-in defaults.
  3. It then attempts to connect, retrying up to CONFIG_ESP_PPP_WIFI_MAXIMUM_RETRY times (set under idf.py menuconfig -> esp_ppp Configuration). If it still fails, it prints Failed to connect to "<ssid>". and prompts again for a new SSID/password, repeating until a connection succeeds.
  4. Once connected with credentials that were entered interactively (as opposed to ones freshly loaded from NVS), it saves them to NVS so they're used automatically on subsequent boots.

The credential prompt (--- WiFi setup ---) reads from the same serial port as the console/log output (idf.py monitor): type the SSID, press Enter, then type the password (echoed as * characters), press Enter. Backspace/delete is supported while typing.

Status LED

An LED on GPIO10 (active low) reflects WiFi/PPP connection state:

State LED behavior
Waiting for credentials input / connect retries exhausted Fast blink (100 ms)
WiFi connected, waiting for PPP client to dial in Slow blink (500 ms)
PPP client connected (IP_EVENT_PPP_GOT_IP) Solid on
PPP link lost (IP_EVENT_PPP_LOST_IP) Back to slow blink

Peer MCU configuration

The ESP32 acts as PPP server with a fixed address scheme:

  • Server (ESP32) address: 192.168.11.1
  • Client (peer MCU) address: 192.168.11.2
  • No PPP authentication (no PAP/CHAP)

Configure the peer's PPP client to use those addresses (or accept them via IPCP negotiation) and route default traffic over the PPP link. The ESP32 does not negotiate a DNS server address, so the peer should use a fixed public resolver (e.g. 8.8.8.8) or IP literals.

app_main.c's eppp_listen() call blocks until the peer dials in, then enables NAPT on the PPP netif so all of the peer's traffic is translated onto the WiFi connection.

Testing with a Linux PC

You don't need real peer-MCU firmware to try this out — a Linux PC can act as the PPP client itself, using the standard pppd daemon over a serial link.

1. Connect the PC to the ESP32's PPP UART

If the PPP UART is still on its default pins/port (UART0, GPIO1/3), it's the same port as the board's built-in USB-serial adapter — just plug the ESP32 into the PC and note the device node (typically /dev/ttyUSB0 or /dev/ttyACM0). In that case, first move the ESP-IDF console off UART0 (idf.py menuconfig -> Component config -> ESP System Settings -> Channel for console output), otherwise log messages will corrupt the PPP stream.

Alternatively, configure the PPP link on a separate UART (e.g. GPIO17/18) and wire that to a separate 3.3V USB-to-TTL adapter (cross TX/RX, common ground) as described under Wiring — this keeps the console available on the original port for debugging.

2. Install pppd

sudo apt install ppp

3. Flash and start the ESP32, then dial in from the PC

Flash and reset the ESP32 as usual (see Build above) and wait for WiFi to connect; idf.py monitor (if the console is still reachable) should print waiting for PPP client on UART....

Then, on the PC, bring up pppd as the client, using the fixed address scheme the firmware expects:

sudo pppd /dev/ttyACM0 115200 192.168.11.2:192.168.11.1 noauth local nodetach debug nocrtscts
  • Replace /dev/ttyUSB0 and 115200 with your actual device node and the configured baudrate.
  • 192.168.11.2:192.168.11.1 fixes the PC's own PPP address and the ESP32's address, matching what the firmware hard-codes.
  • local tells pppd to ignore modem control lines, since this is a direct wired link, not a modem.
  • nodetach debug keep pppd in the foreground and log the negotiation; drop them for normal use.

A ppp0 interface should come up on the PC once negotiation succeeds, and the ESP32 should log PPP client connected, NAT to WiFi enabled.

4. Verify the link and the NAT gateway

Check the link itself:

ping 192.168.11.1

Check that NAT onto the WiFi network works, without disturbing the PC's own default route:

sudo ip route add 8.8.8.8 via 192.168.11.1 dev ppp0
ping 8.8.8.8

To instead route all of the PC's traffic through the ESP32 (fully exercising it as an internet gateway), add defaultroute to the pppd command line in step 3.

5. Tear down

sudo kill %pppd   # or Ctrl+C the foreground pppd

About

ESP32 based PPPoS WiFi server

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages