Merge branch 'feature/esp_netif_ppp_params' into 'master'

Examples: Add esp_modem example to experimental cxx components

Closes IDF-1923, IDFGH-217, IDFGH-2608, IDFGH-4838, IDFGH-1229, IDFGH-3848, and IDFGH-3809

See merge request espressif/esp-idf!13161
This commit is contained in:
David Čermák 2021-09-07 18:16:13 +00:00
commit 25e14bd8d9
15 changed files with 445 additions and 6 deletions

View File

@ -38,6 +38,11 @@ typedef struct esp_netif_ppp_config {
*/
#define NETIF_PP_PHASE_OFFSET (0x100)
/** @brief event id offset for internal errors
*
*/
#define NETIF_PPP_INTERNAL_ERR_OFFSET (0x200)
/** @brief event ids for different PPP related events
*
*/
@ -68,6 +73,7 @@ typedef enum {
NETIF_PPP_PHASE_RUNNING = NETIF_PP_PHASE_OFFSET + 10,
NETIF_PPP_PHASE_TERMINATE = NETIF_PP_PHASE_OFFSET + 11,
NETIF_PPP_PHASE_DISCONNECT = NETIF_PP_PHASE_OFFSET + 12,
NETIF_PPP_CONNECT_FAILED = NETIF_PPP_INTERNAL_ERR_OFFSET + 0,
} esp_netif_ppp_status_event_t;
/** @brief definitions of different authorisation types
@ -89,7 +95,8 @@ typedef enum {
* @param[in] user User name
* @param[in] passwd Password
*
* @return ESP_OK on success, ESP_ERR_ESP_NETIF_INVALID_PARAMS if netif null or not PPP
* @return ESP_OK on success,
* ESP_ERR_ESP_NETIF_INVALID_PARAMS if the supplied netif is not of PPP type, or netif is null
*/
esp_err_t esp_netif_ppp_set_auth(esp_netif_t *netif, esp_netif_auth_type_t authtype, const char *user, const char *passwd);
@ -98,10 +105,20 @@ esp_err_t esp_netif_ppp_set_auth(esp_netif_t *netif, esp_netif_auth_type_t autht
* @param[in] esp_netif Handle to esp-netif instance
* @param[in] config Pointer to PPP netif configuration structure
*
* @return ESP_OK on success, ESP_ERR_ESP_NETIF_INVALID_PARAMS if netif null or not PPP
* @return ESP_OK on success,
* ESP_ERR_ESP_NETIF_INVALID_PARAMS if the supplied netif is not of PPP type, or netif is null
*/
esp_err_t esp_netif_ppp_set_params(esp_netif_t *netif, const esp_netif_ppp_config_t *config);
/** @brief Gets parameters configured in the supplied esp-netif.
*
* @param[in] esp_netif Handle to esp-netif instance
* @param[out] config Pointer to PPP netif configuration structure
*
* @return ESP_OK on success,
* ESP_ERR_ESP_NETIF_INVALID_PARAMS if the supplied netif is not of PPP type, or netif is null
*/
esp_err_t esp_netif_ppp_get_params(esp_netif_t *netif, esp_netif_ppp_config_t *config);
#ifdef __cplusplus
}

View File

@ -786,7 +786,7 @@ esp_err_t esp_netif_start(esp_netif_t *esp_netif)
if (_IS_NETIF_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
// No need to start PPP interface in lwip thread
esp_err_t ret = esp_netif_start_ppp(esp_netif->related_data);
esp_err_t ret = esp_netif_start_ppp(esp_netif);
if (ret == ESP_OK) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
}

View File

@ -296,8 +296,9 @@ netif_related_data_t * esp_netif_new_ppp(esp_netif_t *esp_netif, const esp_netif
return (netif_related_data_t *)ppp_obj;
}
esp_err_t esp_netif_start_ppp(netif_related_data_t *netif_related)
esp_err_t esp_netif_start_ppp(esp_netif_t *esp_netif)
{
netif_related_data_t *netif_related = esp_netif->related_data;
lwip_peer2peer_ctx_t *ppp_ctx = (lwip_peer2peer_ctx_t *)netif_related;
assert(ppp_ctx->base.netif_type == PPP_LWIP_NETIF);
@ -305,6 +306,9 @@ esp_err_t esp_netif_start_ppp(netif_related_data_t *netif_related)
esp_err_t err = pppapi_connect(ppp_ctx->ppp, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: PPP connection cannot be started", __func__);
if (ppp_ctx->ppp_error_event_enabled) {
esp_event_post(NETIF_PPP_STATUS, NETIF_PPP_CONNECT_FAILED, esp_netif, sizeof(esp_netif), 0);
}
return ESP_FAIL;
}
return ESP_OK;
@ -343,10 +347,26 @@ void esp_netif_destroy_ppp(netif_related_data_t *netif_related)
esp_err_t esp_netif_ppp_set_params(esp_netif_t *netif, const esp_netif_ppp_config_t *config)
{
if (netif == NULL || netif->related_data == NULL || config == NULL ||
((struct lwip_peer2peer_ctx *)netif->related_data)->base.netif_type != PPP_LWIP_NETIF) {
return ESP_ERR_INVALID_ARG;
}
struct lwip_peer2peer_ctx *obj = (struct lwip_peer2peer_ctx *)netif->related_data;
obj->ppp_phase_event_enabled = config->ppp_phase_event_enabled;
obj->ppp_error_event_enabled = config->ppp_error_event_enabled;
return ESP_OK;
}
esp_err_t esp_netif_ppp_get_params(esp_netif_t *netif, esp_netif_ppp_config_t *config)
{
if (netif == NULL || netif->related_data == NULL || config == NULL ||
((struct lwip_peer2peer_ctx *)netif->related_data)->base.netif_type != PPP_LWIP_NETIF) {
return ESP_ERR_INVALID_ARG;
}
struct lwip_peer2peer_ctx *obj = (struct lwip_peer2peer_ctx *)netif->related_data;
config->ppp_phase_event_enabled = obj->ppp_phase_event_enabled;
config->ppp_error_event_enabled = obj->ppp_error_event_enabled;
return ESP_OK;
}
#endif /* CONFIG_ESP_NETIF_TCPIP_LWIP */

View File

@ -32,12 +32,12 @@ netif_related_data_t * esp_netif_new_ppp(esp_netif_t *esp_netif, const esp_netif
/**
* @brief Creates new PPP related structure
*
* @param[in] netif_related pointer to internal ppp context instance
* @param[in] esp_netif pointer esp-netif instance
*
* @return
* - ESP_OK on success
*/
esp_err_t esp_netif_start_ppp(netif_related_data_t *netif_related);
esp_err_t esp_netif_start_ppp(esp_netif_t *esp_netif);
/**
* @brief Data path API to input incoming packets to PPP

View File

@ -0,0 +1,8 @@
# The following 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 $ENV{IDF_PATH}/examples/cxx/experimental/experimental_cpp_component)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(simple_cxx_ppp_client)

View File

@ -0,0 +1,18 @@
| Supported Targets | ESP32 | ESP32-S2 |
| ----------------- | ----- | -------- |
# Simple example of esp_modem component
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview
This example demonstrates the use of the [esp-modem component](https://components.espressif.com/component/espressif/esp_modem) to connect to a network and send some AT commands.
It uses modem CMUX mode so that commands and network could be used at the same time.
## About the esp_modem
Please check the component [README](managed_components/espressif__esp_modem/README.md)
Or refer to the component's [documentation](managed_components/espressif__esp_modem/docs/html/index.html)

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "simple_client.cpp" "simple_mqtt_client.cpp"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,42 @@
menu "Example Configuration"
choice EXAMPLE_MODEM_DEVICE
prompt "Choose supported modem device (DCE)"
default EXAMPLE_MODEM_DEVICE_BG96
help
Select modem device connected to the ESP DTE.
config EXAMPLE_MODEM_DEVICE_SIM800
bool "SIM800"
help
SIMCom SIM800L is a GSM/GPRS module.
It supports Quad-band 850/900/1800/1900MHz.
config EXAMPLE_MODEM_DEVICE_BG96
bool "BG96"
help
Quectel BG96 is a series of LTE Cat M1/Cat NB1/EGPRS module.
config EXAMPLE_MODEM_DEVICE_SIM7600
bool "SIM7600"
help
SIM7600 is a Multi-Band LTE-TDD/LTE-FDD/HSPA+ and GSM/GPRS/EDGE module.
endchoice
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_NEED_SIM_PIN
bool "SIM PIN needed"
default n
help
Enable to set SIM PIN before starting the example
config EXAMPLE_SIM_PIN
string "Set SIM PIN"
default "1234"
depends on EXAMPLE_NEED_SIM_PIN
help
Pin to unlock the SIM
endmenu

View File

@ -0,0 +1,7 @@
targets:
- esp32
- esp32s2
description: cmux example of esp_modem
dependencies:
espressif/esp_modem:
version: "0.1.9"

View File

@ -0,0 +1,137 @@
/* PPPoS Client 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 <cstring>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_netif.h"
#include "esp_log.h"
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
#include "esp_event_cxx.hpp"
#include "simple_mqtt_client.hpp"
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
using namespace esp_modem;
using namespace idf::event;
constexpr auto TAG = "cmux_example";
extern "C" void app_main(void)
{
/* Init and register system/core components */
auto loop = std::make_shared<ESPEventLoop>();
ESP_ERROR_CHECK(esp_netif_init());
/* Configure the DTE */
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
/* Configure the DCE */
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
/* Configure the PPP netif */
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
/* Create the DTE, PPP and DCE objects */
auto uart_dte = create_uart_dte(&dte_config);
assert(uart_dte);
esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config);
assert(esp_netif);
#if CONFIG_EXAMPLE_MODEM_DEVICE_BG96 == 1
std::unique_ptr<DCE> dce = create_BG96_dce(&dce_config, uart_dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM800 == 1
std::unique_ptr<DCE> dce = create_SIM800_dce(&dce_config, uart_dte, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
std::unique_ptr<DCE> dce = create_SIM7600_dce(&dce_config, uart_dte, esp_netif);
#else
#error "Unsupported device"
#endif
assert(dce);
/* Setup basic operation mode for the DCE (pin if used, CMUX mode) */
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
bool pin_ok = true;
if (dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
if (dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK) {
vTaskDelay(pdMS_TO_TICKS(1000)); // Need to wait for some time after unlocking the SIM
} else {
ESP_LOGE(TAG, "Failed to set PIN... exiting");
return;
}
}
#endif
if (dce->set_mode(esp_modem::modem_mode::CMUX_MODE) && dce->set_mode(esp_modem::modem_mode::DATA_MODE)) {
ESP_LOGI(TAG, "Modem has correctly entered multiplexed command/data mode");
} else {
ESP_LOGE(TAG, "Failed to configure desired mode... exiting");
return;
}
/* Read some data from the modem */
std::string str;
while (dce->get_operator_name(str) != esp_modem::command_result::OK) {
// Getting operator name could fail... retry after 500 ms
vTaskDelay(pdMS_TO_TICKS(500));
}
ESP_LOGI(TAG, "Operator name: %s", str.c_str());
/* Try to connect to the network and publish an mqtt topic */
ESPEventHandlerSync event_handler(loop);
event_handler.listen_to(ESPEvent(IP_EVENT, ESPEventID(ESP_EVENT_ANY_ID)));
auto result = event_handler.wait_event_for(std::chrono::milliseconds(60000));
if (result.timeout) {
ESP_LOGE(TAG, "Cannot get IP within specified timeout... exiting");
return;
} else if (result.event.id == ESPEventID(IP_EVENT_PPP_GOT_IP)) {
auto *event = (ip_event_got_ip_t *)result.ev_data;
ESP_LOGI(TAG, "Got IP address");
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));
/* When connected to network, subscribe and publish some MQTT data */
MqttClient mqtt(BROKER_URL);
event_handler.listen_to(MqttClient::get_event(MqttClient::Event::CONNECT));
event_handler.listen_to(MqttClient::get_event(MqttClient::Event::DATA));
auto reg = loop->register_event(MqttClient::get_event(MqttClient::Event::DATA),
[&mqtt](const ESPEvent &event, void *data) {
ESP_LOGI(TAG, " TOPIC: %s", mqtt.get_topic(data).c_str());
ESP_LOGI(TAG, " DATA: %s", mqtt.get_data(data).c_str());
});
mqtt.connect();
while (true) {
result = event_handler.wait_event_for(std::chrono::milliseconds(60000));
if (result.event == MqttClient::get_event(MqttClient::Event::CONNECT)) {
mqtt.subscribe("/topic/esp-modem");
mqtt.publish("/topic/esp-modem", "Hello modem");
continue;
} else if (result.event == MqttClient::get_event(MqttClient::Event::DATA)) {
ESP_LOGI(TAG, "Data received");
break; /* Continue with CMUX example after getting data from MQTT */
} else {
break;
}
}
} else if (result.event.id == ESPEventID(IP_EVENT_PPP_LOST_IP)) {
ESP_LOGE(TAG, "PPP client has lost connection... exiting");
return;
}
/* Again reading some data from the modem */
if (dce->get_imsi(str) == esp_modem::command_result::OK) {
ESP_LOGI(TAG, "Modem IMSI number: %s", str.c_str());
}
}

View File

@ -0,0 +1,101 @@
/* PPPoS Client 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 <memory>
#include "mqtt_client.h"
#include "esp_event_cxx.hpp"
#include "simple_mqtt_client.hpp"
using namespace idf::event;
/**
* Reference to the MQTT event base
*/
ESP_EVENT_DECLARE_BASE(MQTT_EVENTS);
/**
* Thin wrapper around C mqtt_client
*/
struct MqttClientHandle
{
explicit MqttClientHandle(const std::string & uri)
{
esp_mqtt_client_config_t config = { };
config.uri = uri.c_str();
client = esp_mqtt_client_init(&config);
esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, this);
}
~MqttClientHandle()
{
esp_mqtt_client_destroy(client);
}
static void mqtt_event_handler(void *args, esp_event_base_t base, int32_t id, void *data)
{
// forwards the internal event to the global ESPEvent
esp_event_post(base, id, data, sizeof(esp_mqtt_event_t), portMAX_DELAY);
}
esp_mqtt_client_handle_t client;
};
/**
* @brief Definitions of MqttClient methods
*/
MqttClient::MqttClient(const std::string & uri):
h(std::unique_ptr<MqttClientHandle>(new MqttClientHandle(uri)))
{}
void MqttClient::connect()
{
esp_mqtt_client_start(h->client);
}
idf::event::ESPEvent MqttClient::get_event(MqttClient::Event ev)
{
switch (ev) {
case Event::CONNECT: {
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_CONNECTED) };
}
case Event::DATA:
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_DATA) };
}
return { };
}
int MqttClient::publish(const std::string &topic, const std::string &data, int qos)
{
return esp_mqtt_client_publish(h->client, topic.c_str(), data.c_str(), 0, qos, 0);
}
int MqttClient::subscribe(const std::string &topic, int qos)
{
return esp_mqtt_client_subscribe(h->client, topic.c_str(), qos);
}
std::string MqttClient::get_topic(void * event_data)
{
auto event = (esp_mqtt_event_handle_t)event_data;
if (event == nullptr || event->client != h->client)
return {};
return std::string(event->topic, event->topic_len);
}
std::string MqttClient::get_data(void * event_data)
{
auto event = (esp_mqtt_event_handle_t)event_data;
if (event == nullptr || event->client != h->client)
return {};
return std::string(event->data, event->data_len);
}
MqttClient::~MqttClient() = default;

View File

@ -0,0 +1,77 @@
/* PPPoS Client 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.
*/
#ifndef _SIMPLE_MQTT_CLIENT_H_
#define _SIMPLE_MQTT_CLIENT_H_
#include <string>
#include <memory>
#include "esp_event_cxx.hpp"
struct MqttClientHandle;
/**
* @brief Simple MQTT client wrapper
*/
class MqttClient {
public:
enum class Event {
CONNECT,
DATA,
};
explicit MqttClient(const std::string & uri);
~MqttClient();
/**
* @brief Start the mqtt-client
*/
void connect();
/**
* @brief Publish to topic
* @param topic Topic to publish
* @param data Data to publish
* @param qos QoS (0 by default)
* @return message id
*/
int publish(const std::string & topic, const std::string & data, int qos = 0);
/**
* @brief Subscribe to a topic
* @param topic Topic to subscribe
* @param qos QoS (0 by default)
* @return message id
*/
int subscribe(const std::string & topic, int qos = 0);
/**
* @brief Get topic from event data
* @return String topic
*/
std::string get_topic(void *);
/**
* @brief Get published data from event
* @return String representation of the data
*/
std::string get_data(void *);
/**
* @brief Convert internal MQTT event to standard ESPEvent
* @param ev internal mqtt event
* @return corresponding ESPEvent
*/
static idf::event::ESPEvent get_event(Event ev);
private:
std::unique_ptr<MqttClientHandle> h;
};
#endif //_SIMPLE_MQTT_CLIENT_H_

View File

@ -0,0 +1,8 @@
# Override some defaults to enable PPP
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_NOTIFY_PHASE_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
CONFIG_COMPILER_CXX_EXCEPTIONS=y

View File

@ -1,6 +1,7 @@
components/
common_components/
cxx/experimental/experimental_cpp_component/
cxx/experimental/esp_modem_cxx
main/
build_system/cmake/
mb_example_common/

View File

@ -2,3 +2,4 @@ build_system/cmake
temp_
examples/bluetooth/bluedroid/ble_50/
examples/cxx/experimental/blink_cxx
examples/cxx/experimental/esp_modem_cxx/