Page 1 of 1

4G PPPoS Internet forward or NAT to W5500 SPI Ethernet Port with DHCP

Posted: Sat Apr 13, 2024 1:20 pm
by gidlstar
Good day,
I am trying to forward or NAT internet coming from a 4g module PPPoS (with ESP_MODEM component) to a SPI Ethernet module (W5500). So basically the ap_to_ppp example just instead of the wifi it should use the ethernet.

The follwoing works:
- Internet connection on ESP via 4G
- ap_to_ppp example works perfectly
- Internet connection on ESP via W5500 (did it to test the hardware setup), IP gets received from the DHCP Server in the Network
- ESP DHCP Server on W5500, the connected client can ping the IP address of the ESP W5500 interface

Not working:
when I swap the wifi hotspot on the ap_to_ppp example with the w5500 ethernet interface the client can't connect to internet (it can ping the esp W5500 interface though). I tried with manual DNS Settings on the client or ping an IP in the internet (8.8.8.8).

Does anyone have an idea what I am doing wrong?

Any help is much appreciated, I starting to get desperate here :(. Thank you very much!

Code: Select all

/*
 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

/*
 *  softAP to PPPoS Example
*/
#include <string.h>
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_idf_version.h"
#include "nvs_flash.h"
#include "lwip/netif.h"
#include "lwip/lwip_napt.h"
#include "esp_modem_api.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "network_dce.h"

#include "esp_mac.h"
#include "dhcpserver/dhcpserver.h"

#include "driver/gpio.h"


#include <stdio.h>
#include "esp_eth.h"
#include "sdkconfig.h"
#include "driver/spi_master.h"

#include "ethernet_init.h"




#include "nvs.h"

#include "esp_netif.h"
#include "esp_event.h"




#include "ethernet_init.h"





#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_WIFI_CHANNEL   CONFIG_ESP_WIFI_CHANNEL
#define EXAMPLE_MAX_STA_CONN       CONFIG_ESP_MAX_STA_CONN


esp_modem_dce_t *dce;

static const char *TAG = "ap_to_pppos";

static EventGroupHandle_t event_group = NULL;
static const int CONNECT_BIT = BIT0;
static const int DISCONNECT_BIT = BIT1;

static void on_ip_event(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data){
    ESP_LOGD(TAG, "IP event! %" PRId32, event_id);
    if (event_id == IP_EVENT_PPP_GOT_IP) {
        esp_netif_dns_info_t dns_info;
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        esp_netif_t *netif = event->esp_netif;

        ESP_LOGI(TAG, "Modem Connect to PPP Server");
        ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
        ESP_LOGI(TAG, "IP          : " IPSTR, IP2STR(&event->ip_info.ip));
        ESP_LOGI(TAG, "Netmask     : " IPSTR, IP2STR(&event->ip_info.netmask));
        ESP_LOGI(TAG, "Gateway     : " IPSTR, IP2STR(&event->ip_info.gw));
        esp_netif_get_dns_info(netif, 0, &dns_info);
        ESP_LOGI(TAG, "Name Server1: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
        esp_netif_get_dns_info(netif, 1, &dns_info);
        ESP_LOGI(TAG, "Name Server2: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
        ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
        xEventGroupSetBits(event_group, CONNECT_BIT);

        ESP_LOGI(TAG, "GOT ip event!!!");
    } else if (event_id == IP_EVENT_PPP_LOST_IP) {
        ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
        xEventGroupSetBits(event_group, DISCONNECT_BIT);
    } else if (event_id == IP_EVENT_GOT_IP6) {
        ESP_LOGI(TAG, "GOT IPv6 event!");
        ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
        ESP_LOGI(TAG, "Got IPv6 address " IPV6STR, IPV62STR(event->ip6_info.ip));
    }
}

static esp_err_t set_dhcps_dns(esp_netif_t *netif, uint32_t addr)
{
    esp_netif_dns_info_t dns;
    dns.ip.u_addr.ip4.addr = addr;
    dns.ip.type = IPADDR_TYPE_V4;
    dhcps_offer_t dhcps_dns_value = OFFER_DNS;

    ESP_LOGW(TAG, "in function dhcp bevor important");


    ESP_ERROR_CHECK(esp_netif_dhcps_option(netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_dns_value, sizeof(dhcps_dns_value)));

    ESP_LOGW(TAG, "in function after dhcp options");

    ESP_ERROR_CHECK(esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns));

    ESP_LOGW(TAG, "in function dns set");

    return ESP_OK;
}

static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data){
    if (event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *) event_data;
        ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data;
        ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
}

void wifi_init_softap(void){
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                    ESP_EVENT_ANY_ID,
                    &wifi_event_handler,
                    NULL,
                    NULL));

    wifi_config_t wifi_config = {
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
            .channel = EXAMPLE_ESP_WIFI_CHANNEL,
            .password = EXAMPLE_ESP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_STA_CONN,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        },
    };
    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}


void start_network(void){
    EventBits_t bits = 0;
    while ((bits & CONNECT_BIT) == 0) {
        if (!modem_check_sync()) {
            ESP_LOGE(TAG, "Modem does not respond, maybe in DATA mode? ...exiting network mode");
            modem_stop_network();
            if (!modem_check_sync()) {
                ESP_LOGE(TAG, "Modem does not respond to AT ...restarting");
                modem_reset();
                ESP_LOGI(TAG, "Restarted");
            }
            continue;
        }
        if (!modem_check_signal()) {
            ESP_LOGI(TAG, "Poor signal ...will check after 5s");
            vTaskDelay(pdMS_TO_TICKS(5000));
            continue;
        }
        if (!modem_start_network()) {
            ESP_LOGE(TAG, "Modem could not enter network mode ...will retry after 10s");
            vTaskDelay(pdMS_TO_TICKS(10000));
            continue;
        }
        bits = xEventGroupWaitBits(event_group, (DISCONNECT_BIT | CONNECT_BIT), pdTRUE, pdFALSE, pdMS_TO_TICKS(30000));
        if (bits & DISCONNECT_BIT) {
            ESP_LOGE(TAG, "Modem got disconnected ...retrying");
            modem_stop_network();
        }
    }
}

/** Event handler for IP_EVENT_ETH_GOT_IP */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data){
    ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
    const esp_netif_ip_info_t *ip_info = &event->ip_info;

    ESP_LOGI(TAG, "Ethernet Got IP Address");
    ESP_LOGI(TAG, "~~~~~~~~~~~");
    ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
    ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
    ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
    ESP_LOGI(TAG, "~~~~~~~~~~~");
}


void app_main(void){

     gpio_config_t io_conf;

    // GSM Reset Pin
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pin_bit_mask = (1ULL << 25);
    io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    gpio_config(&io_conf);
    gpio_set_level(25, 0); 

    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pin_bit_mask = (1ULL << 34);
    io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    gpio_config(&io_conf);

    ESP_LOGE(TAG, "GSM Reset On");
    gpio_set_level(25, 1); 
    vTaskDelay(100 / portTICK_PERIOD_MS);
    ESP_LOGE(TAG, "GSM Reset Off");
    gpio_set_level(25, 0); 
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    while (1){
        if (gpio_get_level (34) == 0){
            vTaskDelay (1000/portTICK_PERIOD_MS);

        }else{
            vTaskDelay (2000/portTICK_PERIOD_MS);
            break;
        }
    }

    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    // Initialize esp_netif and default event loop
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    event_group = xEventGroupCreate();

    // Initialize lwip network interface in PPP mode
    esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP();
    esp_netif_t *ppp_netif = esp_netif_new(&ppp_netif_config);
    assert(ppp_netif);

    // Initialize the PPP network and register for IP event
    ESP_ERROR_CHECK(modem_init_network(ppp_netif));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event, NULL));

    // Start the PPP network and wait for connection
    modem_start_network();
    EventBits_t bits;
    do {
        bits = xEventGroupWaitBits(event_group, (CONNECT_BIT | DISCONNECT_BIT), pdTRUE, pdFALSE, portMAX_DELAY);
        if (bits & DISCONNECT_BIT) {
            ESP_LOGW(TAG, "Modem got disconnected from the PPP server: retrying...");
            modem_stop_network();
            modem_start_network();
        }
    } while ((bits & CONNECT_BIT) == 0);







    // ETH with DHCP - inet not working
    uint8_t eth_port_cnt = 0;
    esp_eth_handle_t *eth_handles;
    ESP_ERROR_CHECK(ethernet_init_all(&eth_handles, &eth_port_cnt));

    const esp_netif_ip_info_t my_ap_ip = {
        .ip = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) },
        .gw = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) },
        .netmask = { .addr = ESP_IP4TOADDR( 255, 255, 255, 0) },
    };

    const esp_netif_inherent_config_t eth_behav_cfg = {
            .get_ip_event = IP_EVENT_ETH_GOT_IP,
            .lost_ip_event = 0,
            .flags = ESP_NETIF_DHCP_SERVER | ESP_NETIF_FLAG_AUTOUP,
            .ip_info = (esp_netif_ip_info_t*)& my_ap_ip,
            .if_key = "ETHDHCPS",
            .if_desc = "eth",
            .route_prio = 50
    };

    esp_netif_config_t my_eth_cfg = { .base = &eth_behav_cfg, .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH };
    esp_netif_t *eth_netif = esp_netif_new(& my_eth_cfg);
    assert(eth_netif);
 
    esp_netif_dns_info_t dns;
    ESP_ERROR_CHECK(esp_netif_get_dns_info(ppp_netif, ESP_NETIF_DNS_MAIN, &dns));

    set_dhcps_dns(eth_netif, dns.ip.u_addr.ip4.addr);
    
    ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0])));
    
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));

    // Start Ethernet driver state machine
    for (int i = 0; i < eth_port_cnt; i++) {
        ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
    }





/*
    // Initialize the AP and setup the NAT
    esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap();
    assert(ap_netif);
    esp_netif_dns_info_t dns;
    ESP_ERROR_CHECK(esp_netif_get_dns_info(ppp_netif, ESP_NETIF_DNS_MAIN, &dns));
    set_dhcps_dns(ap_netif, dns.ip.u_addr.ip4.addr);

    wifi_init_softap();
    ip_napt_enable(_g_esp_netif_soft_ap_ip.ip.addr, 1);
*/


//    if(esp_netif_is_netif_up(ap_netif) == ESP_OK){
    if(esp_netif_is_netif_up(eth_netif) == ESP_OK){
         ESP_LOGW(TAG, "alt_netif is up");
    }else{
        ESP_LOGW(TAG, "alt_netif is down");
    }

    if(esp_netif_is_netif_up(ppp_netif) == ESP_OK){
         ESP_LOGW(TAG, "ppp_netif is up");
    }else{
        ESP_LOGW(TAG, "ppp_netif is down");
    }

    ESP_LOGW(TAG, "bevore napt");
    vTaskDelay (5000/portTICK_PERIOD_MS);
    ESP_LOGW(TAG, "afeter break");



//    esp_netif_napt_enable(ap_netif);
    ip_napt_enable(my_ap_ip.ip.addr, 1);



ESP_LOGW(TAG, "after everything");

    // Provide a recovery if disconnection of some kind registered
    while (true) {
        bits = xEventGroupWaitBits(event_group, DISCONNECT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
        if (bits & DISCONNECT_BIT) {
            ESP_LOGW(TAG, "Modem got disconnected from the PPP server: restarting the network...");
            modem_stop_network();
            modem_start_network();
        }
    }

    
}