mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-18 04:52:18 +02:00
esp-modem: C++ rework
This commit is contained in:
@ -7,7 +7,8 @@ set(srcs "src/esp_modem.c"
|
|||||||
"src/esp_modem_recov_helper.c"
|
"src/esp_modem_recov_helper.c"
|
||||||
"src/esp_sim800.c"
|
"src/esp_sim800.c"
|
||||||
"src/esp_sim7600.c"
|
"src/esp_sim7600.c"
|
||||||
"src/esp_bg96.c")
|
"src/esp_bg96.c"
|
||||||
|
"src/esp_modem_dte.cpp")
|
||||||
|
|
||||||
set(include_dirs "include")
|
set(include_dirs "include")
|
||||||
|
|
||||||
@ -20,3 +21,5 @@ idf_component_register(SRCS "${srcs}"
|
|||||||
INCLUDE_DIRS "${include_dirs}"
|
INCLUDE_DIRS "${include_dirs}"
|
||||||
PRIV_INCLUDE_DIRS private_include
|
PRIV_INCLUDE_DIRS private_include
|
||||||
REQUIRES driver)
|
REQUIRES driver)
|
||||||
|
|
||||||
|
target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17)
|
@ -277,7 +277,9 @@ void app_main(void)
|
|||||||
|
|
||||||
// init the DTE
|
// init the DTE
|
||||||
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||||
|
dte_config.pattern_queue_size = 100;
|
||||||
dte_config.event_task_stack_size = 4096;
|
dte_config.event_task_stack_size = 4096;
|
||||||
|
dte_config.event_task_priority = 15;
|
||||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("internet");
|
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("internet");
|
||||||
dce_config.populate_command_list = true;
|
dce_config.populate_command_list = true;
|
||||||
esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP();
|
esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP();
|
||||||
|
10
esp_modem/examples/simple_cxx_client/CMakeLists.txt
Normal file
10
esp_modem/examples/simple_cxx_client/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 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 "../..")
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(simple_cxx_client)
|
||||||
|
|
||||||
|
|
9
esp_modem/examples/simple_cxx_client/Makefile
Normal file
9
esp_modem/examples/simple_cxx_client/Makefile
Normal 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 := pppos_client
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
10
esp_modem/examples/simple_cxx_client/README.md
Normal file
10
esp_modem/examples/simple_cxx_client/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# PPPoS simple client example
|
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This example shows how to act as a MQTT client after the PPPoS channel created by using [ESP-MQTT](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/protocols/mqtt.html) APIs.
|
||||||
|
|
||||||
|
## How to use this example
|
||||||
|
|
||||||
|
See the README.md file in the upper level `pppos` directory for more information about the PPPoS examples.
|
2
esp_modem/examples/simple_cxx_client/main/CMakeLists.txt
Normal file
2
esp_modem/examples/simple_cxx_client/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "simple_client.cpp"
|
||||||
|
INCLUDE_DIRS ".")
|
143
esp_modem/examples/simple_cxx_client/main/Kconfig.projbuild
Normal file
143
esp_modem/examples/simple_cxx_client/main/Kconfig.projbuild
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
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 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_MODEM_LEGACY_API
|
||||||
|
bool "Use Modem legacy API"
|
||||||
|
default y
|
||||||
|
select MODEM_LEGACY_API
|
||||||
|
help
|
||||||
|
Set this to true to use backward compatible API to the original modem
|
||||||
|
component in example/protocol folder in IDFv4.2 and below
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_PPP_AUTH_USERNAME
|
||||||
|
string "Set username for authentication"
|
||||||
|
default "espressif"
|
||||||
|
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||||
|
help
|
||||||
|
Set username for PPP Authentication.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_PPP_AUTH_PASSWORD
|
||||||
|
string "Set password for authentication"
|
||||||
|
default "esp32"
|
||||||
|
depends on !EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||||
|
help
|
||||||
|
Set password for PPP Authentication.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_PPP_AUTH_NONE
|
||||||
|
bool "Skip PPP authentication"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Set to true for the PPP client to skip authentication
|
||||||
|
|
||||||
|
config EXAMPLE_SEND_MSG
|
||||||
|
bool "Short message (SMS)"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Select this, the modem will send a short message before power off.
|
||||||
|
|
||||||
|
if EXAMPLE_SEND_MSG
|
||||||
|
config EXAMPLE_SEND_MSG_PEER_PHONE_NUMBER
|
||||||
|
string "Peer Phone Number (with area code)"
|
||||||
|
default "+8610086"
|
||||||
|
help
|
||||||
|
Enter the peer phone number that you want to send message to.
|
||||||
|
endif
|
||||||
|
|
||||||
|
menu "UART Configuration"
|
||||||
|
config EXAMPLE_MODEM_UART_TX_PIN
|
||||||
|
int "TXD Pin Number"
|
||||||
|
default 25
|
||||||
|
range 0 31
|
||||||
|
help
|
||||||
|
Pin number of UART TX.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_RX_PIN
|
||||||
|
int "RXD Pin Number"
|
||||||
|
default 26
|
||||||
|
range 0 31
|
||||||
|
help
|
||||||
|
Pin number of UART RX.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_RTS_PIN
|
||||||
|
int "RTS Pin Number"
|
||||||
|
default 27
|
||||||
|
range 0 31
|
||||||
|
help
|
||||||
|
Pin number of UART RTS.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_CTS_PIN
|
||||||
|
int "CTS Pin Number"
|
||||||
|
default 23
|
||||||
|
range 0 31
|
||||||
|
help
|
||||||
|
Pin number of UART CTS.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE
|
||||||
|
int "UART Event Task Stack Size"
|
||||||
|
range 2000 6000
|
||||||
|
default 2048
|
||||||
|
help
|
||||||
|
Stack size of UART event task.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY
|
||||||
|
int "UART Event Task Priority"
|
||||||
|
range 3 22
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
Priority of UART event task.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE
|
||||||
|
int "UART Event Queue Size"
|
||||||
|
range 10 40
|
||||||
|
default 30
|
||||||
|
help
|
||||||
|
Length of UART event queue.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_PATTERN_QUEUE_SIZE
|
||||||
|
int "UART Pattern Queue Size"
|
||||||
|
range 10 40
|
||||||
|
default 20
|
||||||
|
help
|
||||||
|
Length of UART pattern queue.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_TX_BUFFER_SIZE
|
||||||
|
int "UART TX Buffer Size"
|
||||||
|
range 256 2048
|
||||||
|
default 512
|
||||||
|
help
|
||||||
|
Buffer size of UART TX buffer.
|
||||||
|
|
||||||
|
config EXAMPLE_MODEM_UART_RX_BUFFER_SIZE
|
||||||
|
int "UART RX Buffer Size"
|
||||||
|
range 256 2048
|
||||||
|
default 1024
|
||||||
|
help
|
||||||
|
Buffer size of UART RX buffer.
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
endmenu
|
347
esp_modem/examples/simple_cxx_client/main/simple_client.cpp
Normal file
347
esp_modem/examples/simple_cxx_client/main/simple_client.cpp
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
/* 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 <string.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_netif_ppp.h"
|
||||||
|
#include "mqtt_client.h"
|
||||||
|
#include "esp_modem.h"
|
||||||
|
#include "esp_modem_netif.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "cxx_include/esp_modem_dte.hpp"
|
||||||
|
#include "cxx_include/uart_terminal.hpp"
|
||||||
|
|
||||||
|
#define BROKER_URL "mqtt://mqtt.eclipse.org"
|
||||||
|
|
||||||
|
static const char *TAG = "pppos_example";
|
||||||
|
static EventGroupHandle_t event_group = NULL;
|
||||||
|
static const int CONNECT_BIT = BIT0;
|
||||||
|
static const int STOP_BIT = BIT1;
|
||||||
|
static const int GOT_DATA_BIT = BIT2;
|
||||||
|
|
||||||
|
#if CONFIG_EXAMPLE_SEND_MSG
|
||||||
|
/**
|
||||||
|
* @brief This example will also show how to send short message using the infrastructure provided by esp modem library.
|
||||||
|
* @note Not all modem support SMG.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static esp_err_t example_default_handle(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
|
||||||
|
err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t example_handle_cmgs(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
|
||||||
|
err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, MODEM_STATE_FAIL);
|
||||||
|
} else if (!strncmp(line, "+CMGS", strlen("+CMGS"))) {
|
||||||
|
err = ESP_OK;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MODEM_SMS_MAX_LENGTH (128)
|
||||||
|
#define MODEM_COMMAND_TIMEOUT_SMS_MS (120000)
|
||||||
|
#define MODEM_PROMPT_TIMEOUT_MS (10)
|
||||||
|
|
||||||
|
static esp_err_t example_send_message_text(modem_dce_t *user_dce, const char *phone_num, const char *text)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t *dce = &user_dce->parent;
|
||||||
|
modem_dte_t *dte = dce->dte;
|
||||||
|
dce->handle_line = example_default_handle;
|
||||||
|
/* Set text mode */
|
||||||
|
if (dte->send_cmd(dte, "AT+CMGF=1\r", MODEM_COMMAND_TIMEOUT_DEFAULT) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "send command failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (dce->state != MODEM_STATE_SUCCESS) {
|
||||||
|
ESP_LOGE(TAG, "set message format failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "set message format ok");
|
||||||
|
/* Specify character set */
|
||||||
|
dce->handle_line = example_default_handle;
|
||||||
|
if (dte->send_cmd(dte, "AT+CSCS=\"GSM\"\r", MODEM_COMMAND_TIMEOUT_DEFAULT) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "send command failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (dce->state != MODEM_STATE_SUCCESS) {
|
||||||
|
ESP_LOGE(TAG, "set character set failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "set character set ok");
|
||||||
|
/* send message */
|
||||||
|
char command[MODEM_SMS_MAX_LENGTH] = {0};
|
||||||
|
int length = snprintf(command, MODEM_SMS_MAX_LENGTH, "AT+CMGS=\"%s\"\r", phone_num);
|
||||||
|
/* set phone number and wait for "> " */
|
||||||
|
dte->send_wait(dte, command, length, "\r\n> ", MODEM_PROMPT_TIMEOUT_MS);
|
||||||
|
/* end with CTRL+Z */
|
||||||
|
snprintf(command, MODEM_SMS_MAX_LENGTH, "%s\x1A", text);
|
||||||
|
dce->handle_line = example_handle_cmgs;
|
||||||
|
if (dte->send_cmd(dte, command, MODEM_COMMAND_TIMEOUT_SMS_MS) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "send command failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (dce->state != MODEM_STATE_SUCCESS) {
|
||||||
|
ESP_LOGE(TAG, "send message failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "send message ok");
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void modem_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||||
|
{
|
||||||
|
switch (event_id) {
|
||||||
|
case ESP_MODEM_EVENT_PPP_START:
|
||||||
|
ESP_LOGI(TAG, "Modem PPP Started");
|
||||||
|
break;
|
||||||
|
case ESP_MODEM_EVENT_PPP_STOP:
|
||||||
|
ESP_LOGI(TAG, "Modem PPP Stopped");
|
||||||
|
xEventGroupSetBits(event_group, STOP_BIT);
|
||||||
|
break;
|
||||||
|
case ESP_MODEM_EVENT_UNKNOWN:
|
||||||
|
ESP_LOGW(TAG, "Unknown line received: %s", (char *)event_data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
|
||||||
|
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||||
|
{
|
||||||
|
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
|
||||||
|
esp_mqtt_client_handle_t client = event->client;
|
||||||
|
int msg_id;
|
||||||
|
switch (event->event_id) {
|
||||||
|
case MQTT_EVENT_CONNECTED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||||
|
msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0);
|
||||||
|
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_DISCONNECTED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_SUBSCRIBED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
|
||||||
|
msg_id = esp_mqtt_client_publish(client, "/topic/esp-pppos", "esp32-pppos", 0, 0, 0);
|
||||||
|
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_UNSUBSCRIBED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_PUBLISHED:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_DATA:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||||
|
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||||
|
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||||
|
xEventGroupSetBits(event_group, GOT_DATA_BIT);
|
||||||
|
break;
|
||||||
|
case MQTT_EVENT_ERROR:
|
||||||
|
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGI(TAG, "MQTT other event id: %d", event->event_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_ppp_changed(void *arg, esp_event_base_t event_base,
|
||||||
|
int32_t event_id, void *event_data)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "PPP state changed event %d", event_id);
|
||||||
|
if (event_id == NETIF_PPP_ERRORUSER) {
|
||||||
|
/* User interrupted event from esp-netif */
|
||||||
|
esp_netif_t *netif = (esp_netif_t *)event_data;
|
||||||
|
ESP_LOGI(TAG, "User interrupted event from netif:%p", netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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! %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, ESP_NETIF_DNS_MAIN, &dns_info);
|
||||||
|
ESP_LOGI(TAG, "Name Server1: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
|
||||||
|
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_BACKUP, &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");
|
||||||
|
} 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 void modem_test_app(esp_modem_dte_config_t *dte_config, esp_modem_dce_config_t *dce_config, esp_netif_config_t *ppp_config);
|
||||||
|
|
||||||
|
extern "C" void app_main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Init and register system/core components */
|
||||||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event, NULL));
|
||||||
|
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL));
|
||||||
|
|
||||||
|
event_group = xEventGroupCreate();
|
||||||
|
|
||||||
|
/* Configure the DTE */
|
||||||
|
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||||
|
/* setup UART specific configuration based on kconfig options */
|
||||||
|
dte_config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN;
|
||||||
|
dte_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN;
|
||||||
|
dte_config.rts_io_num = CONFIG_EXAMPLE_MODEM_UART_RTS_PIN;
|
||||||
|
dte_config.cts_io_num = CONFIG_EXAMPLE_MODEM_UART_CTS_PIN;
|
||||||
|
dte_config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE;
|
||||||
|
dte_config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE;
|
||||||
|
dte_config.pattern_queue_size = CONFIG_EXAMPLE_MODEM_UART_PATTERN_QUEUE_SIZE;
|
||||||
|
dte_config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE;
|
||||||
|
dte_config.event_task_stack_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE;
|
||||||
|
dte_config.event_task_priority = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY;
|
||||||
|
dte_config.line_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE / 2;
|
||||||
|
|
||||||
|
/* 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();
|
||||||
|
|
||||||
|
/* Run the modem demo app */
|
||||||
|
return modem_test_app(&dte_config, &dce_config,&netif_ppp_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static void modem_test_app(esp_modem_dte_config_t *dte_config, esp_modem_dce_config_t *dce_config, esp_netif_config_t *ppp_config)
|
||||||
|
{
|
||||||
|
/* create dte object */
|
||||||
|
esp_modem_dte_t *dte; // = esp_modem_dte_new(dte_config);
|
||||||
|
// assert(dte != NULL);
|
||||||
|
// dte_config->line_buffer_size = 1000000;
|
||||||
|
uint8_t data[32] = {};
|
||||||
|
int actual_len = 0;
|
||||||
|
auto ddd = create_dte(dte_config);
|
||||||
|
ddd->set_mode(dte_mode::UNDEF);
|
||||||
|
ddd->send_command("AT\r", [&](uint8_t *data, size_t len) {
|
||||||
|
std::string response((char*)data, len);
|
||||||
|
ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data);
|
||||||
|
std::cout << response << std::endl;
|
||||||
|
return true;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// auto uart = create_uart_terminal(dte_config);
|
||||||
|
// uart->set_data_cb([&](size_t len){
|
||||||
|
// actual_len = uart->read(data, 32);
|
||||||
|
// ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)data);
|
||||||
|
// });
|
||||||
|
// uart->write((uint8_t*)"AT\r",3);
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
// int len = uart->read(data, 32);
|
||||||
|
// ESP_LOGI(TAG, "len=%d data %s", len, (char*)data);
|
||||||
|
// vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
// len = uart->read(data, 32);
|
||||||
|
ESP_LOGI(TAG, "len=%d data %s", actual_len, (char*)data);
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* create dce object */
|
||||||
|
#if CONFIG_EXAMPLE_MODEM_DEVICE_SIM800
|
||||||
|
dce_config->device = ESP_MODEM_DEVICE_SIM800;
|
||||||
|
#elif CONFIG_EXAMPLE_MODEM_DEVICE_BG96
|
||||||
|
dce_config->device = ESP_MODEM_DEVICE_BG96;
|
||||||
|
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600
|
||||||
|
dce_config->device = ESP_MODEM_DEVICE_SIM7600;
|
||||||
|
#else
|
||||||
|
#error "Unsupported DCE"
|
||||||
|
#endif
|
||||||
|
esp_modem_dce_t *dce = esp_modem_dce_new(dce_config);
|
||||||
|
assert(dce != NULL);
|
||||||
|
|
||||||
|
/* create netif object */
|
||||||
|
esp_netif_t *esp_netif = esp_netif_new(ppp_config);
|
||||||
|
assert(esp_netif);
|
||||||
|
#if !defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_NONE) && (defined(CONFIG_LWIP_PPP_PAP_SUPPORT) || defined(CONFIG_LWIP_PPP_CHAP_SUPPORT))
|
||||||
|
#if CONFIG_LWIP_PPP_PAP_SUPPORT
|
||||||
|
esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_PAP;
|
||||||
|
#elif CONFIG_LWIP_PPP_CHAP_SUPPORT
|
||||||
|
esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_CHAP;
|
||||||
|
#else
|
||||||
|
#error "Unsupported AUTH Negotiation"
|
||||||
|
#endif
|
||||||
|
esp_netif_ppp_set_auth(esp_netif, auth_type, CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME, CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD);
|
||||||
|
#endif
|
||||||
|
/* Register event handler */
|
||||||
|
ESP_ERROR_CHECK(esp_modem_set_event_handler(dte, modem_event_handler, ESP_EVENT_ANY_ID, NULL));
|
||||||
|
|
||||||
|
/* attach the DCE, DTE, netif to initialize the modem */
|
||||||
|
ESP_ERROR_CHECK(esp_modem_default_attach(dte, dce, esp_netif));
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ESP_ERROR_CHECK(esp_modem_default_start(dte));
|
||||||
|
/* Start PPP mode */
|
||||||
|
ESP_ERROR_CHECK(esp_modem_start_ppp(dte));
|
||||||
|
/* Wait for IP address */
|
||||||
|
xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
|
/* Config MQTT */
|
||||||
|
esp_mqtt_client_config_t mqtt_config = { };
|
||||||
|
mqtt_config.uri = BROKER_URL;
|
||||||
|
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
|
||||||
|
esp_mqtt_client_register_event(mqtt_client, MQTT_EVENT_ANY, mqtt_event_handler, NULL);
|
||||||
|
esp_mqtt_client_start(mqtt_client);
|
||||||
|
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
|
||||||
|
esp_mqtt_client_destroy(mqtt_client);
|
||||||
|
|
||||||
|
/* Exit PPP mode */
|
||||||
|
ESP_ERROR_CHECK(esp_modem_stop_ppp(dte));
|
||||||
|
|
||||||
|
xEventGroupWaitBits(event_group, STOP_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
|
||||||
|
ESP_LOGI(TAG, "Restart after 60 seconds");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default destroy all modem sub-units attached to it (DTE, DCE, netif) */
|
||||||
|
ESP_ERROR_CHECK(esp_modem_default_destroy(dte));
|
||||||
|
}
|
8
esp_modem/examples/simple_cxx_client/sdkconfig.defaults
Normal file
8
esp_modem/examples/simple_cxx_client/sdkconfig.defaults
Normal 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
|
86
esp_modem/include/cxx_include/esp_modem_dte.hpp
Normal file
86
esp_modem/include/cxx_include/esp_modem_dte.hpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#ifndef SIMPLE_CXX_CLIENT_ESP_MODEM_DTE_HPP
|
||||||
|
#define SIMPLE_CXX_CLIENT_ESP_MODEM_DTE_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <exception>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "terminal_objects.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum class terminal_error {
|
||||||
|
BUFFER_OVERFLOW,
|
||||||
|
CHECKSUM_ERROR,
|
||||||
|
UNEXPECTED_CONTROL_FLOW,
|
||||||
|
};
|
||||||
|
|
||||||
|
class terminal {
|
||||||
|
public:
|
||||||
|
virtual ~terminal() = default;
|
||||||
|
void set_data_cb(std::function<void(size_t len)> f) { on_data = std::move(f); }
|
||||||
|
void set_error_cb(std::function<void(terminal_error)> f) { on_error = std::move(f); }
|
||||||
|
virtual int write(uint8_t *data, size_t len) = 0;
|
||||||
|
virtual int read(uint8_t *data, size_t len) = 0;
|
||||||
|
virtual void start() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::function<void(size_t len)> on_data;
|
||||||
|
std::function<void(terminal_error)> on_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class dte_adapter: public terminal {
|
||||||
|
public:
|
||||||
|
dte_adapter(std::unique_ptr<terminal> terminal):
|
||||||
|
original_dte(std::move(terminal)) {}
|
||||||
|
~dte_adapter() override = default;
|
||||||
|
int write(uint8_t *data, size_t len) override { return original_dte->write(data, len); }
|
||||||
|
int read(uint8_t *data, size_t len) override { return original_dte->read(data, len); }
|
||||||
|
private:
|
||||||
|
std::unique_ptr<terminal> original_dte;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum class dte_mode {
|
||||||
|
UNDEF,
|
||||||
|
COMMAND_MODE,
|
||||||
|
DATA_MODE
|
||||||
|
};
|
||||||
|
|
||||||
|
const int DTE_BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
|
struct dte_data {
|
||||||
|
uint8_t *data;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::function<bool(uint8_t *data, size_t len)> got_line_cb;
|
||||||
|
|
||||||
|
class dte {
|
||||||
|
public:
|
||||||
|
explicit dte(std::unique_ptr<terminal> terminal);
|
||||||
|
~dte() = default;
|
||||||
|
// void set_line_cb(got_line f) { on_line_cb = std::move(f); }
|
||||||
|
|
||||||
|
void set_mode(dte_mode m) { term->start(); mode = m; }
|
||||||
|
bool send_command(const std::string& command, got_line_cb got_line, uint32_t time_ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const size_t GOT_LINE = BIT0;
|
||||||
|
size_t buffer_size;
|
||||||
|
size_t consumed;
|
||||||
|
std::unique_ptr<uint8_t[]> buffer;
|
||||||
|
std::unique_ptr<terminal> term;
|
||||||
|
got_line_cb on_line;
|
||||||
|
dte_mode mode;
|
||||||
|
signal_group signal;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SIMPLE_CXX_CLIENT_ESP_MODEM_DTE_HPP
|
84
esp_modem/include/cxx_include/terminal_objects.hpp
Normal file
84
esp_modem/include/cxx_include/terminal_objects.hpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// Created by david on 2/26/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SIMPLE_CXX_CLIENT_TERMINAL_OBJECTS_HPP
|
||||||
|
#define SIMPLE_CXX_CLIENT_TERMINAL_OBJECTS_HPP
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
|
||||||
|
|
||||||
|
class esp_err_exception: virtual public std::exception {
|
||||||
|
public:
|
||||||
|
explicit esp_err_exception(esp_err_t err): esp_err(err) {}
|
||||||
|
explicit esp_err_exception(std::string msg): esp_err(ESP_FAIL), message(std::move(msg)) {}
|
||||||
|
explicit esp_err_exception(std::string msg, esp_err_t err): esp_err(err), message(std::move(msg)) {}
|
||||||
|
virtual esp_err_t get_err_t() { return esp_err; }
|
||||||
|
~esp_err_exception() noexcept override = default;
|
||||||
|
virtual const char* what() const noexcept {
|
||||||
|
return message.c_str();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
esp_err_t esp_err;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void throw_if_false(bool condition, std::string message)
|
||||||
|
{
|
||||||
|
if (!condition) {
|
||||||
|
throw(esp_err_exception(std::move(message)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void throw_if_esp_fail(esp_err_t err, std::string message)
|
||||||
|
{
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
throw(esp_err_exception(std::move(message), err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void throw_if_esp_fail(esp_err_t err)
|
||||||
|
{
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
throw(esp_err_exception(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct signal_group {
|
||||||
|
explicit signal_group(): event_group(nullptr)
|
||||||
|
{
|
||||||
|
event_group = xEventGroupCreate();
|
||||||
|
throw_if_false(event_group != nullptr, "create signal event group failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(uint32_t bits)
|
||||||
|
{
|
||||||
|
xEventGroupSetBits(event_group, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wait(uint32_t flags, uint32_t time_ms) // waiting for all and clearing if set
|
||||||
|
{
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(event_group, flags, pdTRUE, pdTRUE, pdMS_TO_TICKS(time_ms));
|
||||||
|
return bits & flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_any(uint32_t flags)
|
||||||
|
{
|
||||||
|
return xEventGroupGetBits(event_group) & flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wait_any(uint32_t flags, uint32_t time_ms) // waiting for any bit, not clearing them
|
||||||
|
{
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(event_group, flags, pdFALSE, pdFALSE, pdMS_TO_TICKS(time_ms));
|
||||||
|
return bits & flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
~signal_group()
|
||||||
|
{
|
||||||
|
if (event_group) vEventGroupDelete(event_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventGroupHandle_t event_group;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //SIMPLE_CXX_CLIENT_TERMINAL_OBJECTS_HPP
|
17
esp_modem/include/cxx_include/uart_terminal.hpp
Normal file
17
esp_modem/include/cxx_include/uart_terminal.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by david on 2/25/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SIMPLE_CXX_CLIENT_UART_TERMINAL_HPP
|
||||||
|
#define SIMPLE_CXX_CLIENT_UART_TERMINAL_HPP
|
||||||
|
|
||||||
|
#include "cxx_include/esp_modem_dte.hpp"
|
||||||
|
#include "esp_modem_dte_config.h"
|
||||||
|
|
||||||
|
std::unique_ptr<terminal> create_uart_terminal(const struct dte_config *config);
|
||||||
|
|
||||||
|
class dte;
|
||||||
|
|
||||||
|
std::unique_ptr<dte> create_dte(const struct dte_config *config);
|
||||||
|
|
||||||
|
#endif //SIMPLE_CXX_CLIENT_UART_TERMINAL_HPP
|
@ -19,6 +19,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "driver/uart.h"
|
#include "driver/uart.h"
|
||||||
|
#include "esp_modem_dte_config.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Forward declare DTE and DCE objects
|
* @brief Forward declare DTE and DCE objects
|
||||||
@ -52,21 +53,15 @@ typedef enum {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Modem flow control type
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
ESP_MODEM_FLOW_CONTROL_NONE = 0,
|
|
||||||
ESP_MODEM_FLOW_CONTROL_SW,
|
|
||||||
ESP_MODEM_FLOW_CONTROL_HW
|
|
||||||
} esp_modem_flow_ctrl_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ESP Modem DTE Configuration
|
* @brief ESP Modem DTE Configuration
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct dte_config
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
uart_port_t port_num; /*!< UART port number */
|
uart_port_t port_num; /*!< UART port number */
|
||||||
uart_word_length_t data_bits; /*!< Data bits of UART */
|
uart_word_length_t data_bits; /*!< Data bits of UART */
|
||||||
uart_stop_bits_t stop_bits; /*!< Stop bits of UART */
|
uart_stop_bits_t stop_bits; /*!< Stop bits of UART */
|
||||||
@ -84,7 +79,9 @@ typedef struct {
|
|||||||
uint32_t event_task_stack_size; /*!< UART Event Task Stack size */
|
uint32_t event_task_stack_size; /*!< UART Event Task Stack size */
|
||||||
int event_task_priority; /*!< UART Event Task Priority */
|
int event_task_priority; /*!< UART Event Task Priority */
|
||||||
int line_buffer_size; /*!< Line buffer size for command mode */
|
int line_buffer_size; /*!< Line buffer size for command mode */
|
||||||
} esp_modem_dte_config_t;
|
}
|
||||||
|
#endif
|
||||||
|
esp_modem_dte_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ESP Modem DTE Default Configuration
|
* @brief ESP Modem DTE Default Configuration
|
||||||
|
39
esp_modem/include/esp_modem_dte_config.h
Normal file
39
esp_modem/include/esp_modem_dte_config.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Created by david on 2/24/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SIMPLE_CXX_CLIENT_ESP_MODEM_DTE_CONFIG_H
|
||||||
|
#define SIMPLE_CXX_CLIENT_ESP_MODEM_DTE_CONFIG_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modem flow control type
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ESP_MODEM_FLOW_CONTROL_NONE = 0,
|
||||||
|
ESP_MODEM_FLOW_CONTROL_SW,
|
||||||
|
ESP_MODEM_FLOW_CONTROL_HW
|
||||||
|
} esp_modem_flow_ctrl_t;
|
||||||
|
|
||||||
|
struct dte_config {
|
||||||
|
uart_port_t port_num; /*!< UART port number */
|
||||||
|
uart_word_length_t data_bits; /*!< Data bits of UART */
|
||||||
|
uart_stop_bits_t stop_bits; /*!< Stop bits of UART */
|
||||||
|
uart_parity_t parity; /*!< Parity type */
|
||||||
|
esp_modem_flow_ctrl_t flow_control; /*!< Flow control type */
|
||||||
|
int baud_rate; /*!< Communication baud rate */
|
||||||
|
int tx_io_num; /*!< TXD Pin Number */
|
||||||
|
int rx_io_num; /*!< RXD Pin Number */
|
||||||
|
int rts_io_num; /*!< RTS Pin Number */
|
||||||
|
int cts_io_num; /*!< CTS Pin Number */
|
||||||
|
int rx_buffer_size; /*!< UART RX Buffer Size */
|
||||||
|
int tx_buffer_size; /*!< UART TX Buffer Size */
|
||||||
|
int pattern_queue_size; /*!< UART Pattern Queue Size */
|
||||||
|
int event_queue_size; /*!< UART Event Queue Size */
|
||||||
|
uint32_t event_task_stack_size; /*!< UART Event Task Stack size */
|
||||||
|
int event_task_priority; /*!< UART Event Task Priority */
|
||||||
|
int line_buffer_size; /*!< Line buffer size for command mode */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SIMPLE_CXX_CLIENT_ESP_MODEM_DTE_CONFIG_H
|
334
esp_modem/src/esp_modem_dte.cpp
Normal file
334
esp_modem/src/esp_modem_dte.cpp
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
//
|
||||||
|
// Created by david on 2/24/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "cxx_include/esp_modem_dte.hpp"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
#include "esp_modem.h"
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
#include "esp_modem_dte_internal.h"
|
||||||
|
#include "esp_modem_dte_config.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#define ESP_MODEM_EVENT_QUEUE_SIZE (16)
|
||||||
|
#define MIN_PATTERN_INTERVAL (9)
|
||||||
|
#define MIN_POST_IDLE (0)
|
||||||
|
#define MIN_PRE_IDLE (0)
|
||||||
|
|
||||||
|
|
||||||
|
static const char *TAG = "dte_uart";
|
||||||
|
|
||||||
|
//class uart_terminal;
|
||||||
|
|
||||||
|
//class dte {
|
||||||
|
//public:
|
||||||
|
// esp_err_t init(std::unique_ptr<terminal> t);
|
||||||
|
//
|
||||||
|
//private:
|
||||||
|
// std::unique_ptr<terminal> m_terminal;
|
||||||
|
//
|
||||||
|
//};
|
||||||
|
|
||||||
|
struct uart_task {
|
||||||
|
explicit uart_task(size_t stack_size, size_t priority, void* task_param, TaskFunction_t task_function):
|
||||||
|
task_handle(nullptr)
|
||||||
|
{
|
||||||
|
BaseType_t ret = xTaskCreate(task_function, "uart_task", stack_size, task_param, priority, &task_handle);
|
||||||
|
throw_if_false(ret == pdTRUE, "create uart event task failed");
|
||||||
|
}
|
||||||
|
~uart_task()
|
||||||
|
{
|
||||||
|
if (task_handle) vTaskDelete(task_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskHandle_t task_handle; /*!< UART event task handle */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct uart_event_loop {
|
||||||
|
explicit uart_event_loop(): event_loop_hdl(nullptr)
|
||||||
|
{
|
||||||
|
esp_event_loop_args_t loop_args = {};
|
||||||
|
loop_args.queue_size = ESP_MODEM_EVENT_QUEUE_SIZE;
|
||||||
|
loop_args.task_name = nullptr;
|
||||||
|
throw_if_esp_fail(esp_event_loop_create(&loop_args, &event_loop_hdl), "create event loop failed");
|
||||||
|
}
|
||||||
|
void run() { esp_event_loop_run(event_loop_hdl, pdMS_TO_TICKS(0)); }
|
||||||
|
|
||||||
|
~uart_event_loop() { if (event_loop_hdl) esp_event_loop_delete(event_loop_hdl); }
|
||||||
|
|
||||||
|
esp_event_loop_handle_t event_loop_hdl;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uart_resource {
|
||||||
|
explicit uart_resource(const struct dte_config *config);
|
||||||
|
|
||||||
|
~uart_resource();
|
||||||
|
|
||||||
|
bool get_event(uart_event_t& event, uint32_t time_ms)
|
||||||
|
{
|
||||||
|
return xQueueReceive(event_queue, &event, pdMS_TO_TICKS(time_ms));
|
||||||
|
}
|
||||||
|
void reset_events()
|
||||||
|
{
|
||||||
|
uart_flush_input(port);
|
||||||
|
xQueueReset(event_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_port_t port; /*!< UART port */
|
||||||
|
QueueHandle_t event_queue; /*!< UART event queue handle */
|
||||||
|
// esp_modem_on_receive receive_cb; /*!< ptr to data reception */
|
||||||
|
// void *receive_cb_ctx; /*!< ptr to rx fn context data */
|
||||||
|
int line_buffer_size; /*!< line buffer size in command mode */
|
||||||
|
int pattern_queue_size; /*!< UART pattern queue size */
|
||||||
|
};
|
||||||
|
|
||||||
|
class uart_terminal: public terminal {
|
||||||
|
public:
|
||||||
|
explicit uart_terminal(const struct dte_config *config):
|
||||||
|
uart(config), event_loop(), signal(),
|
||||||
|
task_handle(config->event_task_stack_size, config->event_task_priority, this, s_task) {}
|
||||||
|
|
||||||
|
~uart_terminal() override = default;
|
||||||
|
void start() override
|
||||||
|
{
|
||||||
|
signal.set(TASK_START);
|
||||||
|
}
|
||||||
|
void stop() override
|
||||||
|
{
|
||||||
|
signal.set(TASK_STOP);
|
||||||
|
}
|
||||||
|
// { ESP_LOGE(TAG, "uart_terminal destruct"); }
|
||||||
|
|
||||||
|
int write(uint8_t *data, size_t len) override;
|
||||||
|
int read(uint8_t *data, size_t len) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void s_task(void * task_param)
|
||||||
|
{
|
||||||
|
auto t = static_cast<uart_terminal*>(task_param);
|
||||||
|
t->task();
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
void task();
|
||||||
|
|
||||||
|
const size_t TASK_INIT = BIT0;
|
||||||
|
const size_t TASK_START = BIT1;
|
||||||
|
const size_t TASK_STOP = BIT2;
|
||||||
|
|
||||||
|
|
||||||
|
uart_resource uart;
|
||||||
|
uart_event_loop event_loop;
|
||||||
|
signal_group signal;
|
||||||
|
uart_task task_handle;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uart_resource::~uart_resource()
|
||||||
|
{
|
||||||
|
if (port >= UART_NUM_0 && port < UART_NUM_MAX) {
|
||||||
|
uart_driver_delete(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uart_resource::uart_resource(const struct dte_config *config):
|
||||||
|
port(-1)
|
||||||
|
// buffer(std::make_unique<uint8_t[]>(config->line_buffer_size))
|
||||||
|
{
|
||||||
|
esp_err_t res;
|
||||||
|
|
||||||
|
line_buffer_size = config->line_buffer_size;
|
||||||
|
|
||||||
|
/* TODO: Bind methods */
|
||||||
|
|
||||||
|
/* Config UART */
|
||||||
|
uart_config_t uart_config = {};
|
||||||
|
uart_config.baud_rate = config->baud_rate;
|
||||||
|
uart_config.data_bits = config->data_bits;
|
||||||
|
uart_config.parity = config->parity;
|
||||||
|
uart_config.stop_bits = config->stop_bits;
|
||||||
|
uart_config.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
|
||||||
|
: UART_HW_FLOWCTRL_DISABLE;
|
||||||
|
uart_config.source_clk = UART_SCLK_REF_TICK;
|
||||||
|
|
||||||
|
throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
|
||||||
|
|
||||||
|
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||||
|
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
|
||||||
|
config->rts_io_num, config->cts_io_num);
|
||||||
|
} else {
|
||||||
|
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
|
||||||
|
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||||
|
}
|
||||||
|
throw_if_esp_fail(res, "config uart gpio failed");
|
||||||
|
/* Set flow control threshold */
|
||||||
|
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||||
|
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
|
||||||
|
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
|
||||||
|
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8);
|
||||||
|
}
|
||||||
|
throw_if_esp_fail(res, "config uart flow control failed");
|
||||||
|
/* Install UART driver and get event queue used inside driver */
|
||||||
|
res = uart_driver_install(config->port_num, config->rx_buffer_size, config->tx_buffer_size,
|
||||||
|
config->event_queue_size, &(event_queue), 0);
|
||||||
|
throw_if_esp_fail(res, "install uart driver failed");
|
||||||
|
throw_if_esp_fail(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed");
|
||||||
|
|
||||||
|
/* Set pattern interrupt, used to detect the end of a line. */
|
||||||
|
// res = uart_enable_pattern_det_baud_intr(config->port_num, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
||||||
|
/* Set pattern queue size */
|
||||||
|
// pattern_queue_size = config->pattern_queue_size;
|
||||||
|
// res |= uart_pattern_queue_reset(config->port_num, config->pattern_queue_size);
|
||||||
|
/* Starting in command mode -> explicitly disable RX interrupt */
|
||||||
|
// uart_disable_rx_intr(config->port_num);
|
||||||
|
uart_set_rx_full_threshold(config->port_num, 64);
|
||||||
|
throw_if_esp_fail(res, "config uart pattern failed");
|
||||||
|
/* mark UART as initialized */
|
||||||
|
port = config->port_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<terminal> create_uart_terminal(const struct dte_config *config)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
auto term = std::make_unique<uart_terminal>(config);
|
||||||
|
term->start();
|
||||||
|
return term;
|
||||||
|
} catch (std::bad_alloc& e) {
|
||||||
|
ESP_LOGE(TAG, "Out of memory");
|
||||||
|
return nullptr;
|
||||||
|
} catch (esp_err_exception& e) {
|
||||||
|
esp_err_t err = e.get_err_t();
|
||||||
|
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
|
||||||
|
ESP_LOGE(TAG, "%s", e.what());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<dte> create_dte(const struct dte_config *config)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
auto term = std::make_unique<dte>(std::make_unique<uart_terminal>(config));
|
||||||
|
// term->start();
|
||||||
|
return term;
|
||||||
|
} catch (std::bad_alloc& e) {
|
||||||
|
ESP_LOGE(TAG, "Out of memory");
|
||||||
|
return nullptr;
|
||||||
|
} catch (esp_err_exception& e) {
|
||||||
|
esp_err_t err = e.get_err_t();
|
||||||
|
ESP_LOGE(TAG, "Error occurred during UART term init: %d", err);
|
||||||
|
ESP_LOGE(TAG, "%s", e.what());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void uart_terminal::task()
|
||||||
|
{
|
||||||
|
uart_event_t event;
|
||||||
|
size_t len;
|
||||||
|
signal.set(TASK_INIT);
|
||||||
|
signal.wait_any(TASK_START | TASK_STOP, portMAX_DELAY);
|
||||||
|
if (signal.is_any(TASK_STOP)) {
|
||||||
|
return; // deletes the static task
|
||||||
|
}
|
||||||
|
while(signal.is_any(TASK_START)) {
|
||||||
|
event_loop.run();
|
||||||
|
if (uart.get_event(event, 100)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case UART_DATA:
|
||||||
|
ESP_LOGI(TAG, "UART_DATA");
|
||||||
|
uart_get_buffered_data_len(uart.port, &len);
|
||||||
|
ESP_LOGI(TAG, "UART_DATA len=%d, on_data=%d", len, (bool)on_data);
|
||||||
|
if (len && on_data) {
|
||||||
|
on_data(len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UART_FIFO_OVF:
|
||||||
|
ESP_LOGW(TAG, "HW FIFO Overflow");
|
||||||
|
uart.reset_events();
|
||||||
|
break;
|
||||||
|
case UART_BUFFER_FULL:
|
||||||
|
ESP_LOGW(TAG, "Ring Buffer Full");
|
||||||
|
uart.reset_events();
|
||||||
|
break;
|
||||||
|
case UART_BREAK:
|
||||||
|
ESP_LOGW(TAG, "Rx Break");
|
||||||
|
break;
|
||||||
|
case UART_PARITY_ERR:
|
||||||
|
ESP_LOGE(TAG, "Parity Error");
|
||||||
|
break;
|
||||||
|
case UART_FRAME_ERR:
|
||||||
|
ESP_LOGE(TAG, "Frame Error");
|
||||||
|
break;
|
||||||
|
case UART_PATTERN_DET:
|
||||||
|
ESP_LOGI(TAG, "UART_PATTERN_DET");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "unknown uart event type: %d", event.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ESP_LOGI(TAG, "uart_event_task_entry");
|
||||||
|
// vTaskDelay(pdMS_TO_TICKS(200));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uart_terminal::read(uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
size_t length = 0;
|
||||||
|
uart_get_buffered_data_len(uart.port, &length);
|
||||||
|
if (length > 0) {
|
||||||
|
return uart_read_bytes(uart.port, data, length, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uart_terminal::write(uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
return uart_write_bytes(uart.port, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
dte::dte(std::unique_ptr<terminal> terminal):
|
||||||
|
buffer_size(DTE_BUFFER_SIZE), consumed(0),
|
||||||
|
buffer(std::make_unique<uint8_t[]>(buffer_size)),
|
||||||
|
term(std::move(terminal)), mode(dte_mode::UNDEF) {}
|
||||||
|
|
||||||
|
|
||||||
|
bool dte::send_command(const std::string& command, got_line_cb got_line, uint32_t time_ms)
|
||||||
|
{
|
||||||
|
term->write((uint8_t *)command.c_str(), command.length());
|
||||||
|
term->set_data_cb([&](size_t len){
|
||||||
|
auto data_to_read = std::min(len, buffer_size - consumed);
|
||||||
|
auto data = buffer.get() + consumed;
|
||||||
|
auto actual_len = term->read(data, data_to_read);
|
||||||
|
consumed += actual_len;
|
||||||
|
if (memchr(data, '\n', actual_len)) {
|
||||||
|
ESP_LOGI("in the lambda", "FOUND");
|
||||||
|
if (got_line(buffer.get(), consumed)) {
|
||||||
|
signal.set(GOT_LINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGI("in the lambda", "len=%d data %s", len, (char*)buffer.get());
|
||||||
|
});
|
||||||
|
auto res = signal.wait(GOT_LINE, time_ms);
|
||||||
|
consumed = 0;
|
||||||
|
return res;
|
||||||
|
}
|
Reference in New Issue
Block a user