esp_modem: Refactor the modem to a standalone managed component

This commit is contained in:
David Cermak
2020-11-18 21:20:35 +01:00
parent 5565a09ed1
commit c8e89098bd
63 changed files with 5081 additions and 2180 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,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := ap-to-pppos
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,11 @@
# PPPoS simple client example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## 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.
## How to use this example
See the README.md file in the upper level `pppos` directory for more information about the PPPoS examples.

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "ap2pppos_example_main.c"
"modem_board.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,26 @@
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.
endmenu

View File

@ -0,0 +1,193 @@
/* 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 "esp_modem.h"
#include "lwip/lwip_napt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.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-2-pppos";
static EventGroupHandle_t event_group = NULL;
static const int CONNECT_BIT = BIT0;
static const int DISCONNECT_BIT = BIT1;
static void on_modem_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));
}
} else if (event_base == ESP_MODEM_EVENT) {
ESP_LOGD(TAG, "Modem event! %d", event_id);
}
}
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);
}
esp_modem_dce_t *sim7600_board_create(esp_modem_dce_config_t *config);
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);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
event_group = xEventGroupCreate();
// init the DTE
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
dte_config.event_task_stack_size = 4096;
dte_config.rx_buffer_size = 16384;
dte_config.tx_buffer_size = 2048;
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("internet23");
dce_config.populate_command_list = true;
esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP();
// Initialize esp-modem units, DTE, DCE, ppp-netif
esp_modem_dte_t *dte = esp_modem_dte_new(&dte_config);
esp_modem_dce_t *dce = sim7600_board_create(&dce_config);
esp_netif_t *ppp_netif = esp_netif_new(&ppp_netif_config);
assert(ppp_netif);
ESP_ERROR_CHECK(esp_modem_set_event_handler(dte, on_modem_event, ESP_EVENT_ANY_ID, dte));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_modem_event, dte));
ESP_ERROR_CHECK(esp_modem_default_attach(dte, dce, ppp_netif));
ESP_ERROR_CHECK(esp_modem_default_start(dte)); // use retry
ESP_ERROR_CHECK(esp_modem_start_ppp(dte));
/* Wait for the first connection */
EventBits_t bits;
do {
bits = xEventGroupWaitBits(event_group, (CONNECT_BIT | DISCONNECT_BIT), pdTRUE, pdFALSE, portMAX_DELAY);
if (bits&DISCONNECT_BIT) {
}
} while ((bits&CONNECT_BIT) == 0);
/* Init the AP with NAT enabled */
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 recovery if disconnection of some kind registered */
while (DISCONNECT_BIT&xEventGroupWaitBits(event_group, DISCONNECT_BIT, pdTRUE, pdFALSE, portMAX_DELAY)) {
// restart the modem PPP mode
ESP_ERROR_CHECK(esp_modem_stop_ppp(dte));
ESP_ERROR_CHECK(esp_modem_start_ppp(dte));
}
}

View File

@ -0,0 +1,8 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#

View File

@ -0,0 +1,7 @@
version: "0.0.2"
targets:
- esp32
description: pppos_client to AP
dependencies:
espressif/esp_modem:
version: "~0.0.2"

View File

@ -0,0 +1,162 @@
/* softAP to PPPoS Example (modem_board)
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 <stdlib.h>
#include <string.h>
#include "esp_log.h"
#include "esp_modem_recov_helper.h"
#include "esp_modem_dce.h"
#include "esp_modem_dce_common_commands.h"
#define ESP_MODEM_EXAMPLE_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
static const char *TAG = "sim7600_board";
typedef struct {
esp_modem_dce_t parent;
esp_modem_recov_gpio_t *power_pin;
esp_modem_recov_gpio_t *reset_pin;
esp_err_t (*reset)(esp_modem_dce_t *dce);
esp_err_t (*power_down)(esp_modem_dce_t *dce);
esp_modem_recov_resend_t *re_sync;
esp_modem_recov_resend_t *re_store_profile;
} sim7600_board_t;
esp_err_t sim7600_board_handle_powerup(esp_modem_dce_t *dce, const char *line)
{
if (strstr(line, "PB DONE")) {
ESP_LOGI(TAG, "Board ready after hard reset/power-cycle");
}
return ESP_OK;
}
esp_err_t sim7600_board_deinit(esp_modem_dce_t *dce)
{
sim7600_board_t *board = __containerof(dce, sim7600_board_t, parent);
board->power_pin->destroy(board->power_pin);
board->power_pin->destroy(board->reset_pin);
esp_err_t err = esp_modem_command_list_deinit(&board->parent);
if (err == ESP_OK) {
free(dce);
}
return err;
}
esp_err_t sim7600_board_reset(esp_modem_dce_t *dce)
{
sim7600_board_t *board = __containerof(dce, sim7600_board_t, parent);
ESP_LOGI(TAG, "sim7600_board_reset!");
dce->handle_line = sim7600_board_handle_powerup;
board->power_pin->pulse(board->reset_pin);
return ESP_OK;
}
esp_err_t sim7600_board_power_up(esp_modem_dce_t *dce)
{
sim7600_board_t *board = __containerof(dce, sim7600_board_t, parent);
ESP_LOGI(TAG, "sim7600_board_power_up!");
dce->handle_line = sim7600_board_handle_powerup;
board->power_pin->pulse(board->power_pin);
return ESP_OK;
}
esp_err_t sim7600_board_power_down(esp_modem_dce_t *dce)
{
sim7600_board_t *board = __containerof(dce, sim7600_board_t, parent);
ESP_LOGI(TAG, "sim7600_board_power_down!");
/* power down sequence (typical values for SIM7600 Toff=min2.5s, Toff-status=26s) */
dce->handle_line = sim7600_board_handle_powerup;
board->power_pin->pulse_special(board->power_pin, 3000, 26000);
return ESP_OK;
}
static esp_err_t my_recov(esp_modem_recov_resend_t *retry_cmd, esp_err_t err, int timeouts, int errors)
{
esp_modem_dce_t *dce = retry_cmd->dce;
ESP_LOGI(TAG, "Current timeouts: %d and errors: %d", timeouts, errors);
if (err == ESP_ERR_TIMEOUT) {
if (timeouts < 2) {
// first timeout, try to exit data mode and sync again
dce->set_command_mode(dce, NULL, NULL);
esp_modem_dce_sync(dce, NULL, NULL);
} else if (timeouts < 3) {
// try to reset with GPIO if resend didn't help
sim7600_board_t *board = __containerof(dce, sim7600_board_t, parent);
board->reset(dce);
} else {
// otherwise power-cycle the board
sim7600_board_t *board = __containerof(dce, sim7600_board_t, parent);
board->power_down(dce);
esp_modem_dce_sync(dce, NULL, NULL);
}
} else {
// check if a PIN needs to be supplied in case of a failure
bool ready = false;
esp_modem_dce_read_pin(dce, NULL, &ready);
if (!ready) {
esp_modem_dce_set_pin(dce, "1234", NULL);
}
vTaskDelay(1000 / portTICK_RATE_MS);
esp_modem_dce_read_pin(dce, NULL, &ready);
if (!ready) {
return ESP_FAIL;
}
}
return ESP_OK;
}
static DEFINE_RETRY_CMD(re_sync_fn, re_sync, sim7600_board_t)
static DEFINE_RETRY_CMD(re_store_profile_fn, re_store_profile, sim7600_board_t)
esp_err_t sim7600_board_start_up(esp_modem_dce_t *dce)
{
// sim7600_board_t *board = __containerof(dce, sim7600_board_t, parent);
ESP_MODEM_EXAMPLE_CHECK(re_sync_fn(dce, NULL, NULL) == ESP_OK, "sending sync failed", err);
ESP_MODEM_EXAMPLE_CHECK(dce->set_echo(dce, (void*)false, NULL) == ESP_OK, "set_echo failed", err);
ESP_MODEM_EXAMPLE_CHECK(dce->set_flow_ctrl(dce, (void*)ESP_MODEM_FLOW_CONTROL_NONE, NULL) == ESP_OK, "set_flow_ctrl failed", err);
ESP_MODEM_EXAMPLE_CHECK(dce->store_profile(dce, NULL, NULL) == ESP_OK, "store_profile failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}
esp_modem_dce_t *sim7600_board_create(esp_modem_dce_config_t *config)
{
sim7600_board_t *board = calloc(1, sizeof(sim7600_board_t));
ESP_MODEM_EXAMPLE_CHECK(board, "failed to allocate board-sim7600 object", err);
ESP_MODEM_EXAMPLE_CHECK(esp_modem_dce_init(&board->parent, config) == ESP_OK, "Failed to init sim7600", err);
/* power on sequence (typical values for SIM7600 Ton=500ms, Ton-status=16s) */
board->power_pin = esp_modem_recov_gpio_new( /*gpio_num*/ 12, /*inactive_level*/ 1, /*active_width*/
500, /*inactive_width*/ 16000);
/* reset sequence (typical values for SIM7600 Treset=200ms, wait 10s after reset */
board->reset_pin = esp_modem_recov_gpio_new( /*gpio_num*/ 13, /*inactive_level*/ 1, /*active_width*/
200, /*inactive_width*/ 10000);
board->parent.deinit = sim7600_board_deinit;
board->reset = sim7600_board_reset;
board->power_down = sim7600_board_power_down;
board->re_sync = esp_modem_recov_resend_new(&board->parent, board->parent.sync, my_recov, 5, 1);
board->parent.start_up = sim7600_board_start_up;
board->re_store_profile = esp_modem_recov_resend_new(&board->parent, board->parent.store_profile, my_recov, 2, 3);
board->parent.store_profile = re_store_profile_fn;
return &board->parent;
err:
return NULL;
}

View File

@ -0,0 +1,12 @@
# Override some defaults to enable PPP
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_PAP_SUPPORT=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
# Do not enable IPV6 in dte<->dce link local
CONFIG_LWIP_PPP_ENABLE_IPV6=n
# Disable legacy API
CONFIG_MODEM_LEGACY_API=n
# Enable NAPT
CONFIG_LWIP_IP_FORWARD=y
CONFIG_LWIP_IPV4_NAPT=y