esp_modem: Moved to component folder

This commit is contained in:
David Čermák
2021-05-19 23:00:28 +08:00
committed by David Cermak
parent 61f264f97a
commit 90641c89eb
133 changed files with 21 additions and 21 deletions

View File

@ -0,0 +1,8 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "../..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ap-to-pppos)

View File

@ -0,0 +1,17 @@
# AP to PPPoS example
## Overview
This example focuses on the networking part, enables forwarding packets between network interfaces. It creates a WiFi soft AP, which uses NAT to forward packets to and from the PPP network
interface.
### Specific network DCE
Note, that this example could use of a minimal Network DCE, defined in the `network_dce.cpp` file.
Please set `EXAMPLE_USE_MINIMAL_DCE` to `y` in order to demonstrate this functionality.
By default, this example simply connects to the PPP server using a supported device with C-API modem interface.
This example however, doesn't rely on sending specific AT commands, just the bare minimum to setup the cellular network.
Thus, if the `EXAMPLE_USE_MINIMAL_DCE` option is enabled, we directly inherit from the `ModuleIf` and implement only the basic commands.
Also, to demonstrate the dce_factory functionality, a new `NetDCE_Factory` is implemented for creating the network module and the DCE.

View File

@ -0,0 +1,9 @@
if(CONFIG_EXAMPLE_USE_MINIMAL_DCE)
set(NETWORK_DCE "network_dce.cpp")
else()
set(NETWORK_DCE "network_dce.c")
endif()
idf_component_register(SRCS "ap_to_pppos.c"
${NETWORK_DCE}
INCLUDE_DIRS ".")

View File

@ -0,0 +1,47 @@
menu "Example Configuration"
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
config ESP_WIFI_CHANNEL
int "WiFi Channel"
range 1 13
default 1
help
WiFi channel (network channel) for the example to use.
config ESP_MAX_STA_CONN
int "Maximal STA connections"
default 4
help
Max number of the STA connects to AP.
config EXAMPLE_MODEM_PPP_APN
string "Set MODEM APN"
default "internet"
help
Set APN (Access Point Name), a logical name to choose data network
config EXAMPLE_SIM_PIN
string "Set SIM PIN"
default "1234"
help
Pin to unlock the SIM
config EXAMPLE_USE_MINIMAL_DCE
bool "Use minimal network DCE"
default n
help
Define a specific network only DCE class and
create it using DCE factory
endmenu

View File

@ -0,0 +1,183 @@
/* softAP to PPPoS Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/lwip_napt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "network_dce.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
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)
{
if (event_base == IP_EVENT) {
ESP_LOGD(TAG, "IP event! %d", 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_ERROR_CHECK(esp_netif_dhcps_option(netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_dns_value, sizeof(dhcps_dns_value)));
ESP_ERROR_CHECK(esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns));
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 app_main(void)
{
// 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);
// 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);
// 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();
}
}
}

View File

@ -0,0 +1,56 @@
/* softAP to PPPoS Example (network_dce)
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "esp_netif.h"
#include "esp_modem_api.h"
static esp_modem_dce_t *dce = NULL;
esp_err_t modem_init_network(esp_netif_t *netif)
{
// setup the DCE
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
dce = esp_modem_new(&dte_config, &dce_config, netif);
if (!dce) {
return ESP_FAIL;
}
// configure the PIN
bool pin_ok = false;
if (esp_modem_read_pin(dce, &pin_ok) == ESP_OK && pin_ok == false) {
if (esp_modem_set_pin(dce, CONFIG_EXAMPLE_SIM_PIN) == ESP_OK) {
vTaskDelay(pdMS_TO_TICKS(1000));
} else {
abort();
}
}
return ESP_OK;
}
void modem_deinit_network(void)
{
if (dce) {
esp_modem_destroy(dce);
dce = NULL;
}
}
void modem_start_network()
{
esp_modem_set_mode(dce, ESP_MODEM_MODE_DATA);
}
void modem_stop_network()
{
esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
}

View File

@ -0,0 +1,176 @@
/* softAP to PPPoS Example (network_dce)
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_factory.hpp"
#include <memory>
#include <utility>
#include "network_dce.h"
using namespace esp_modem;
using namespace esp_modem::dce_factory;
class NetModule;
typedef DCE_T<NetModule> NetDCE;
/**
* @brief Local network object used to setup PPP network
*/
class PPPNetwork {
public:
esp_err_t init(esp_netif_t *netif, const std::string& apn, const std::string &pin_number);
void deinit();
NetDCE * get_dce();
private:
NetDCE *dce;
};
/**
* @brief The PPP network is a singleton, allocate statically here
*/
static PPPNetwork ppp_network;
/**
* @brief Custom factory for creating NetDCE and NetModule
*/
class NetDCE_Factory: public Factory {
public:
template <typename T, typename ...Args>
static DCE_T<T>* create(const config *cfg, Args&&... args)
{
return build_generic_DCE<T>(cfg, std::forward<Args>(args)...);
}
template <typename T, typename ...Args>
static std::shared_ptr<T> create_module(const config *cfg, Args&&... args)
{
return build_shared_module<T>(cfg, std::forward<Args>(args)...);
}
};
/**
* @brief This is an example of implementing minimal network module functionality
*
* This does only include those AT commands, that are needed for setting the network up
* and also initialization part (set pin, ...)
*/
class NetModule: public ModuleIf {
public:
explicit NetModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config *cfg):
dte(std::move(dte)), apn(std::string(cfg->apn)) {}
bool setup_data_mode() override
{
PdpContext pdp(apn);
if (set_pdp_context(pdp) != command_result::OK)
return false;
return true;
}
bool set_mode(modem_mode mode) override
{
if (mode == modem_mode::DATA_MODE) {
if (set_data_mode() != command_result::OK)
return resume_data_mode() == command_result::OK;
return true;
}
if (mode == modem_mode::COMMAND_MODE) {
return set_command_mode() == command_result::OK;
}
return false;
}
bool init(const std::string& pin)
{
// switch to command mode (in case we were in PPP mode)
static_cast<void>(set_command_mode()); // ignore the potential failure, as we might be in command mode after startup
bool is_pin_ok;
if (read_pin(is_pin_ok) != command_result::OK)
return false;
if (!is_pin_ok) {
if (set_pin(pin) != command_result::OK)
return false;
vTaskDelay(pdMS_TO_TICKS(1000));
if (read_pin(is_pin_ok) != command_result::OK || !is_pin_ok)
return false;
}
return true;
}
private:
std::shared_ptr<DTE> dte;
std::string apn;
[[nodiscard]] command_result set_pdp_context(PdpContext& pdp) { return dce_commands::set_pdp_context(dte.get(),pdp); }
[[nodiscard]] command_result set_pin(const std::string &pin) { return dce_commands::set_pin(dte.get(), pin); }
[[nodiscard]] command_result read_pin(bool& pin_ok) { return dce_commands::read_pin(dte.get(), pin_ok); }
[[nodiscard]] command_result set_data_mode() { return dce_commands::set_data_mode(dte.get()); }
[[nodiscard]] command_result resume_data_mode() { return dce_commands::resume_data_mode(dte.get()); }
[[nodiscard]] command_result set_command_mode() { return dce_commands::set_command_mode(dte.get()); }
};
esp_err_t PPPNetwork::init(esp_netif_t *netif, const std::string& apn, const std::string &pin_number)
{
// configure
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
dte_config.uart_config.rx_buffer_size = 16384;
dte_config.uart_config.tx_buffer_size = 2048;
esp_modem_dce_config dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(apn.c_str());
// create DTE and minimal network DCE
auto uart_dte = create_uart_dte(&dte_config);
// create the specific device (and initialize it)
auto dev = NetDCE_Factory::create_module<NetModule>(&dce_config, uart_dte, netif);
if (!dev->init(pin_number))
return ESP_FAIL;
// now create the DCE from our already existent device
dce = NetDCE_Factory::create<NetModule>(&dce_config, uart_dte, netif, dev);
if (dce == nullptr)
return ESP_FAIL;
return ESP_OK;
}
void PPPNetwork::deinit()
{
free(dce);
dce = nullptr;
}
NetDCE *PPPNetwork::get_dce()
{
return dce;
}
/**
* @brief Implement the C-API for the AP-2-PPP functionality
*/
extern "C" esp_err_t modem_init_network(esp_netif_t *netif)
{
return ppp_network.init(netif, CONFIG_EXAMPLE_MODEM_PPP_APN, CONFIG_EXAMPLE_SIM_PIN);
}
extern "C" void modem_start_network()
{
ppp_network.get_dce()->set_mode(esp_modem::modem_mode::DATA_MODE);
}
extern "C" void modem_stop_network()
{
ppp_network.get_dce()->set_mode(esp_modem::modem_mode::COMMAND_MODE);
}
extern "C" void modem_deinit_network()
{
ppp_network.deinit();
}

View File

@ -0,0 +1,47 @@
/* softAP to PPPoS Example (network_dce)
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef _NETWORK_DCE_H_
#define _NETWORK_DCE_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize a singleton covering the PPP network provided by the connected modem device
*
* @param netif Already created network interface in PPP mode
*
* @return ESP_OK on success
*/
esp_err_t modem_init_network(esp_netif_t *netif);
/**
* @brief Destroys the single network DCE
*/
void modem_deinit_network();
/**
* @brief Starts the PPP network
*/
void modem_start_network();
/**
* @brief Stops the PPP network
*/
void modem_stop_network();
#ifdef __cplusplus
}
#endif
#endif //_NETWORK_DCE_H_

View File

@ -0,0 +1,8 @@
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_PAP_SUPPORT=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
CONFIG_LWIP_PPP_ENABLE_IPV6=n
CONFIG_UART_ISR_IN_IRAM=y
# Enable NAPT
CONFIG_LWIP_IP_FORWARD=y
CONFIG_LWIP_IPV4_NAPT=y