mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-16 20:12:13 +02:00
esp_modem: Refactor the modem to a standalone managed component
This commit is contained in:
90
esp_modem/.gitignore
vendored
Normal file
90
esp_modem/.gitignore
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
.config
|
||||||
|
*.o
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# gtags
|
||||||
|
GTAGS
|
||||||
|
GRTAGS
|
||||||
|
GPATH
|
||||||
|
|
||||||
|
# emacs
|
||||||
|
.dir-locals.el
|
||||||
|
|
||||||
|
# emacs temp file suffixes
|
||||||
|
*~
|
||||||
|
.#*
|
||||||
|
\#*#
|
||||||
|
|
||||||
|
# eclipse setting
|
||||||
|
.settings
|
||||||
|
|
||||||
|
# MacOS directory files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Components Unit Test Apps files
|
||||||
|
components/**/build
|
||||||
|
components/**/sdkconfig
|
||||||
|
components/**/sdkconfig.old
|
||||||
|
|
||||||
|
# Example project files
|
||||||
|
examples/**/sdkconfig
|
||||||
|
examples/**/sdkconfig.old
|
||||||
|
examples/**/build
|
||||||
|
|
||||||
|
# Doc build artifacts
|
||||||
|
docs/_build/
|
||||||
|
docs/doxygen_sqlite3.db
|
||||||
|
|
||||||
|
# Downloaded font files
|
||||||
|
docs/_static/DejaVuSans.ttf
|
||||||
|
docs/_static/NotoSansSC-Regular.otf
|
||||||
|
|
||||||
|
# Unit test app files
|
||||||
|
tools/unit-test-app/sdkconfig
|
||||||
|
tools/unit-test-app/sdkconfig.old
|
||||||
|
tools/unit-test-app/build
|
||||||
|
tools/unit-test-app/builds
|
||||||
|
tools/unit-test-app/output
|
||||||
|
tools/unit-test-app/test_configs
|
||||||
|
|
||||||
|
# Unit Test CMake compile log folder
|
||||||
|
log_ut_cmake
|
||||||
|
|
||||||
|
# test application build files
|
||||||
|
tools/test_apps/**/build
|
||||||
|
tools/test_apps/**/sdkconfig
|
||||||
|
tools/test_apps/**/sdkconfig.old
|
||||||
|
|
||||||
|
# IDF monitor test
|
||||||
|
tools/test_idf_monitor/outputs
|
||||||
|
|
||||||
|
TEST_LOGS
|
||||||
|
|
||||||
|
# gcov coverage reports
|
||||||
|
*.gcda
|
||||||
|
*.gcno
|
||||||
|
coverage.info
|
||||||
|
coverage_report/
|
||||||
|
|
||||||
|
test_multi_heap_host
|
||||||
|
|
||||||
|
# VS Code Settings
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# VIM files
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Clion IDE CMake build & config
|
||||||
|
.idea/
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Results for the checking of the Python coding style and static analysis
|
||||||
|
.mypy_cache
|
||||||
|
flake8_output.txt
|
||||||
|
|
||||||
|
# ESP-IDF default build directory name
|
||||||
|
build
|
||||||
|
|
||||||
|
# lock files for examples and components
|
||||||
|
dependencies.lock
|
@ -1,12 +1,22 @@
|
|||||||
set(srcs "src/esp_modem.c"
|
set(srcs "src/esp_modem.c"
|
||||||
"src/esp_modem_dce_service"
|
"src/esp_modem_dce_command_lib.c"
|
||||||
|
"src/esp_modem_dce_common_commands.c"
|
||||||
|
"src/esp_modem_dce.c"
|
||||||
|
"src/esp_modem_dte.c"
|
||||||
"src/esp_modem_netif.c"
|
"src/esp_modem_netif.c"
|
||||||
"src/esp_modem_compat.c"
|
"src/esp_modem_recov_helper.c"
|
||||||
"src/sim800.c"
|
"src/esp_sim800.c"
|
||||||
"src/sim7600.c"
|
"src/esp_sim7600.c"
|
||||||
"src/bg96.c")
|
"src/esp_bg96.c")
|
||||||
|
|
||||||
|
set(include_dirs "include")
|
||||||
|
|
||||||
|
if(CONFIG_MODEM_LEGACY_API)
|
||||||
|
list(APPEND srcs "src/esp_modem_compat.c")
|
||||||
|
list(APPEND include_dirs "include_compat")
|
||||||
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS "${srcs}"
|
idf_component_register(SRCS "${srcs}"
|
||||||
INCLUDE_DIRS include
|
INCLUDE_DIRS "${include_dirs}"
|
||||||
PRIV_INCLUDE_DIRS private_include
|
PRIV_INCLUDE_DIRS private_include
|
||||||
REQUIRES driver)
|
REQUIRES driver)
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
menu "ESP-MODEM"
|
menu "ESP-MODEM"
|
||||||
|
|
||||||
config EXAMPLE_COMPONENT_MODEM_APN
|
config MODEM_LEGACY_API
|
||||||
string "Set Access Point Name (APN)"
|
bool "Enable Legacy API"
|
||||||
default "CMNET"
|
default y
|
||||||
help
|
help
|
||||||
Logical name which is used to select the GGSN or the external packet data network.
|
Set to true if the original pppos_client API from the example's internal
|
||||||
|
component should be used.....
|
||||||
|
|
||||||
|
config MODEM_PPP_APN
|
||||||
|
string "Local netif hostname"
|
||||||
|
default 'internet'
|
||||||
|
depends on MODEM_LEGACY_API
|
||||||
|
help
|
||||||
|
APN (Access Point Name), a logical name of a network
|
||||||
|
the modem connects to in the PPP mode
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
74
esp_modem/README.md
Normal file
74
esp_modem/README.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# ESP MODEM
|
||||||
|
|
||||||
|
This component is used to communicate with modems in command and data modes.
|
||||||
|
It abstracts the UART I/O processing into a DTE (data terminal equipment) entity which is configured and setup separately.
|
||||||
|
On top of the DTE, the command and data processing is performed in a DCE (data communication equipment) unit.
|
||||||
|
```
|
||||||
|
+-----+
|
||||||
|
| DTE |--+
|
||||||
|
+-----+ | +-------+
|
||||||
|
+-->| |
|
||||||
|
+-----+ | |
|
||||||
|
| DTE |----->| modem |---> modem events
|
||||||
|
+-----+ | |
|
||||||
|
+->| |
|
||||||
|
+------+ | +-------+
|
||||||
|
| PPP |--+ | |
|
||||||
|
| netif|-----------------> network events
|
||||||
|
+------+ | |
|
||||||
|
| |
|
||||||
|
start-ppp----+ |
|
||||||
|
stop-ppp---------+
|
||||||
|
```
|
||||||
|
|
||||||
|
## Start-up sequence
|
||||||
|
|
||||||
|
To initialize the modem we typically:
|
||||||
|
* create DTE with desired UART parameters
|
||||||
|
* create DCE with desired command palette
|
||||||
|
* create PPP netif with desired network parameters
|
||||||
|
* attach the DTE, DCE and PPP together to start the esp-modem
|
||||||
|
* configure event handlers for the modem and the netif
|
||||||
|
|
||||||
|
Then we can start and stop PPP mode using esp-modem API, receive events from the `ESP_MODEM` base, as well as from netif (IP events).
|
||||||
|
|
||||||
|
### DTE
|
||||||
|
|
||||||
|
Responsibilities of the DTE unit are
|
||||||
|
* sending/receiving commands to/from UART
|
||||||
|
* sending/receiving data to/from UART
|
||||||
|
* changing data/command mode on physical layer
|
||||||
|
|
||||||
|
### DCE
|
||||||
|
|
||||||
|
Responsibilities of the DCE unit are
|
||||||
|
* definition of available commands
|
||||||
|
* cooperate with DTE on changing data/command mode
|
||||||
|
|
||||||
|
#### DCE configuration
|
||||||
|
|
||||||
|
DCE unit configuration structure contains:
|
||||||
|
* device -- sets up predefined commands for this specific modem device
|
||||||
|
* pdp context -- used to setup cellular network
|
||||||
|
* populate command list -- uses runtime configurable linked list of commands. New commands could be added and/or
|
||||||
|
existing commands could be modified. This might be useful for some applications, which have to (re)define
|
||||||
|
and execute multiple AT commands. For other applications, which typically just connect to network, this option
|
||||||
|
might be preferably turned off (as the consumes certain amount of data memory)
|
||||||
|
|
||||||
|
### PPP-netif
|
||||||
|
|
||||||
|
The modem-netif attaches the network interface (which was created outside of esp-modem) to the DTE and
|
||||||
|
serves as a glue layer between esp-netif and esp-modem.
|
||||||
|
|
||||||
|
### Additional units
|
||||||
|
|
||||||
|
ESP-MODEM provides also provides a helper module to define a custom retry/reset strategy using:
|
||||||
|
* a very simple GPIO pulse generator, which could be typically used to reset or power up/down the module
|
||||||
|
* a command executor abstraction, that helps with retrying sending commands in case of a failure or a timeout
|
||||||
|
and run user defined recovery actions.
|
||||||
|
|
||||||
|
## Modification of existing DCE
|
||||||
|
|
||||||
|
In order to support an arbitrary modem, device or introduce a new command we typically have to either modify the DCE,
|
||||||
|
adding a new or altering an existing command or creating a new "subclass" of the existing DCE variants.
|
||||||
|
|
8
esp_modem/examples/ap_to_pppos/CMakeLists.txt
Normal file
8
esp_modem/examples/ap_to_pppos/CMakeLists.txt
Normal 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)
|
9
esp_modem/examples/ap_to_pppos/Makefile
Normal file
9
esp_modem/examples/ap_to_pppos/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 := ap-to-pppos
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
11
esp_modem/examples/ap_to_pppos/README.md
Normal file
11
esp_modem/examples/ap_to_pppos/README.md
Normal 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.
|
3
esp_modem/examples/ap_to_pppos/main/CMakeLists.txt
Normal file
3
esp_modem/examples/ap_to_pppos/main/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
idf_component_register(SRCS "ap2pppos_example_main.c"
|
||||||
|
"modem_board.c"
|
||||||
|
INCLUDE_DIRS ".")
|
26
esp_modem/examples/ap_to_pppos/main/Kconfig.projbuild
Normal file
26
esp_modem/examples/ap_to_pppos/main/Kconfig.projbuild
Normal 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
|
193
esp_modem/examples/ap_to_pppos/main/ap2pppos_example_main.c
Normal file
193
esp_modem/examples/ap_to_pppos/main/ap2pppos_example_main.c
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
esp_modem/examples/ap_to_pppos/main/component.mk
Normal file
8
esp_modem/examples/ap_to_pppos/main/component.mk
Normal 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.
|
||||||
|
#
|
7
esp_modem/examples/ap_to_pppos/main/idf_component.yml
Normal file
7
esp_modem/examples/ap_to_pppos/main/idf_component.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
version: "0.0.2"
|
||||||
|
targets:
|
||||||
|
- esp32
|
||||||
|
description: pppos_client to AP
|
||||||
|
dependencies:
|
||||||
|
espressif/esp_modem:
|
||||||
|
version: "~0.0.2"
|
162
esp_modem/examples/ap_to_pppos/main/modem_board.c
Normal file
162
esp_modem/examples/ap_to_pppos/main/modem_board.c
Normal 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;
|
||||||
|
}
|
12
esp_modem/examples/ap_to_pppos/sdkconfig.defaults
Normal file
12
esp_modem/examples/ap_to_pppos/sdkconfig.defaults
Normal 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
|
||||||
|
|
8
esp_modem/examples/modem_console/CMakeLists.txt
Normal file
8
esp_modem/examples/modem_console/CMakeLists.txt
Normal 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 "../..")
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(modem-console)
|
11
esp_modem/examples/modem_console/Makefile
Normal file
11
esp_modem/examples/modem_console/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := modem-console
|
||||||
|
|
||||||
|
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
10
esp_modem/examples/modem_console/README.md
Normal file
10
esp_modem/examples/modem_console/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 is mainly targets experimenting with a modem device, sending custom commands and switching to PPP mode using esp-console, command line API.
|
||||||
|
|
||||||
|
## How to use this example
|
||||||
|
|
||||||
|
See the README.md file in the upper level `pppos` directory for more information about the PPPoS examples.
|
4
esp_modem/examples/modem_console/main/CMakeLists.txt
Normal file
4
esp_modem/examples/modem_console/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
idf_component_register(SRCS "modem_console_main.c"
|
||||||
|
"httpget_handle.c"
|
||||||
|
"ping_handle.c"
|
||||||
|
INCLUDE_DIRS ".")
|
4
esp_modem/examples/modem_console/main/component.mk
Normal file
4
esp_modem/examples/modem_console/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
108
esp_modem/examples/modem_console/main/httpget_handle.c
Normal file
108
esp_modem/examples/modem_console/main/httpget_handle.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/* Modem console 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_console.h"
|
||||||
|
#include "argtable3/argtable3.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_http_client.h"
|
||||||
|
|
||||||
|
static const char *TAG = "modem_console_httpget";
|
||||||
|
|
||||||
|
static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||||
|
{
|
||||||
|
switch(evt->event_id) {
|
||||||
|
case HTTP_EVENT_ERROR:
|
||||||
|
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_CONNECTED:
|
||||||
|
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_HEADER_SENT:
|
||||||
|
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_HEADER:
|
||||||
|
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_DATA:
|
||||||
|
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
|
||||||
|
if ((bool)evt->user_data &&
|
||||||
|
!esp_http_client_is_chunked_response(evt->client)) {
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP(TAG, evt->data, evt->data_len, ESP_LOG_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_FINISH:
|
||||||
|
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_DISCONNECTED:
|
||||||
|
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct arg_str *host;
|
||||||
|
struct arg_lit *hex;
|
||||||
|
struct arg_end *end;
|
||||||
|
} http_args;
|
||||||
|
|
||||||
|
static int do_http_client(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int nerrors = arg_parse(argc, argv, (void **)&http_args);
|
||||||
|
if (nerrors != 0) {
|
||||||
|
arg_print_errors(stderr, http_args.end, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
esp_http_client_config_t config = {
|
||||||
|
.event_handler = http_event_handler,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (http_args.host->count > 0) {
|
||||||
|
config.url = http_args.host->sval[0];
|
||||||
|
} else {
|
||||||
|
config.url = "http://httpbin.org/get";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (http_args.hex->count > 0) {
|
||||||
|
// show hex data from http-get
|
||||||
|
config.user_data = (void*)true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||||
|
|
||||||
|
esp_err_t err = esp_http_client_perform(client);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
|
||||||
|
esp_http_client_get_status_code(client),
|
||||||
|
esp_http_client_get_content_length(client));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void modem_console_register_http(void)
|
||||||
|
{
|
||||||
|
http_args.host = arg_str0(NULL, NULL, "<host>", "address or host-name to send GET request (defaults to http://httpbin.org/get)");
|
||||||
|
http_args.hex = arg_litn("p", "print-hex", 0, 1, "print hex output"),
|
||||||
|
http_args.end = arg_end(1);
|
||||||
|
const esp_console_cmd_t http_cmd = {
|
||||||
|
.command = "httpget",
|
||||||
|
.help = "http get command to test data mode",
|
||||||
|
.hint = NULL,
|
||||||
|
.func = &do_http_client,
|
||||||
|
.argtable = &http_args
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_console_cmd_register(&http_cmd));
|
||||||
|
}
|
307
esp_modem/examples/modem_console/main/modem_console_main.c
Normal file
307
esp_modem/examples/modem_console/main/modem_console_main.c
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
/* Modem console 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <esp_modem_dce_common_commands.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_console.h"
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "argtable3/argtable3.h"
|
||||||
|
#include "esp_modem.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
// utilities to check network connectivity
|
||||||
|
void modem_console_register_http(void);
|
||||||
|
void modem_console_register_ping(void);
|
||||||
|
|
||||||
|
static esp_modem_dce_t *s_dce = NULL;
|
||||||
|
static const char *TAG = "modem_console";
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct arg_str *command;
|
||||||
|
struct arg_int *param_int;
|
||||||
|
struct arg_str *param_str;
|
||||||
|
struct arg_str *param_pdp;
|
||||||
|
struct arg_str *param_bool;
|
||||||
|
struct arg_str *param;
|
||||||
|
struct arg_str *result;
|
||||||
|
struct arg_end *end;
|
||||||
|
} at_args;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct arg_str *param;
|
||||||
|
struct arg_end *end;
|
||||||
|
} modem_args;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct arg_str *command;
|
||||||
|
struct arg_int *timeout;
|
||||||
|
struct arg_str *pattern;
|
||||||
|
struct arg_lit *no_cr;
|
||||||
|
struct arg_end *end;
|
||||||
|
} generic_at_args;
|
||||||
|
|
||||||
|
static char s_common_in_str[100]; // used as common string input param holder
|
||||||
|
static char s_common_out_str[100]; // used as output string/command result holder
|
||||||
|
|
||||||
|
static esp_err_t handle_line_pattern(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
ESP_LOGI(TAG, "handle_line_pattern: DCE response: %s\n", line);
|
||||||
|
if (strstr(line, dce->handle_line_ctx)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_dce(int argc, char **argv)
|
||||||
|
{
|
||||||
|
// specific DCE generic command params
|
||||||
|
static bool bool_result;
|
||||||
|
static char pdp_type[10];
|
||||||
|
static char pdp_apn[10];
|
||||||
|
static esp_modem_dce_pdp_ctx_t pdp = { .type = pdp_type, .apn = pdp_apn };
|
||||||
|
static esp_modem_dce_csq_ctx_t csq;
|
||||||
|
static esp_modem_dce_cbc_ctx_t cbc;
|
||||||
|
|
||||||
|
int nerrors = arg_parse(argc, argv, (void **) &at_args);
|
||||||
|
if (nerrors != 0) {
|
||||||
|
arg_print_errors(stderr, at_args.end, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void * command_param = NULL;
|
||||||
|
void * command_result = NULL;
|
||||||
|
|
||||||
|
// parse input params
|
||||||
|
if (at_args.param_int->count > 0) {
|
||||||
|
command_param = (void*)(at_args.param_int->ival[0]);
|
||||||
|
} else if (at_args.param_bool->count > 0) {
|
||||||
|
const char * bool_in_str = at_args.param_bool->sval[0];
|
||||||
|
s_common_out_str[0] = '\0';
|
||||||
|
command_result = s_common_out_str;
|
||||||
|
if (strstr(bool_in_str,"true") || strstr(bool_in_str,"1")) {
|
||||||
|
command_param = (void*)true;
|
||||||
|
} else {
|
||||||
|
command_param = (void*)false;
|
||||||
|
}
|
||||||
|
} else if (at_args.param_pdp->count > 0) {
|
||||||
|
// parse out three comma separated sub-arguments
|
||||||
|
sscanf(at_args.param_pdp->sval[0], "%d,%s", &pdp.cid, pdp_type);
|
||||||
|
char *str_apn = strchr(pdp_type, ',');
|
||||||
|
if (str_apn) {
|
||||||
|
strncpy(pdp_apn, str_apn + 1, sizeof(pdp_apn));
|
||||||
|
str_apn[0] = '\0';
|
||||||
|
}
|
||||||
|
command_param = &pdp;
|
||||||
|
} else if (at_args.param_str->count > 0) {
|
||||||
|
strncpy(s_common_in_str, at_args.param_str->sval[0], sizeof(s_common_in_str));
|
||||||
|
command_param = s_common_in_str;
|
||||||
|
} else if (at_args.param->count > 0) { // default param is treated as string
|
||||||
|
strncpy(s_common_in_str, at_args.param->sval[0], sizeof(s_common_in_str));
|
||||||
|
command_param = s_common_in_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse output params
|
||||||
|
if (at_args.result->count > 0) {
|
||||||
|
const char *res = at_args.result->sval[0];
|
||||||
|
if (strstr(res, "csq")) {
|
||||||
|
command_result = &csq;
|
||||||
|
}else if (strstr(res, "cbc")) {
|
||||||
|
command_result = &cbc;
|
||||||
|
} else if (strstr(res, "str")) {
|
||||||
|
command_param = (void*)sizeof(s_common_out_str);
|
||||||
|
command_result = s_common_out_str;
|
||||||
|
} else if (strstr(res, "bool")) {
|
||||||
|
command_result = &bool_result;
|
||||||
|
} else {
|
||||||
|
command_param = (void*)sizeof(s_common_out_str);
|
||||||
|
command_result = s_common_out_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// by default (if no param/result provided) expect string output
|
||||||
|
if (command_param == NULL && command_result == NULL) {
|
||||||
|
s_common_out_str[0] = '\0';
|
||||||
|
command_param = (void*)sizeof(s_common_out_str);
|
||||||
|
command_result = s_common_out_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = esp_modem_command_list_run(s_dce, at_args.command->sval[0], command_param, command_result);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
printf("Command %s succeeded\n", at_args.command->sval[0]);
|
||||||
|
if (command_result == s_common_out_str && s_common_out_str[0] != '\0') {
|
||||||
|
ESP_LOGI(TAG, "Command string output: %s", s_common_out_str);
|
||||||
|
} else if (command_result == &csq) {
|
||||||
|
ESP_LOGI(TAG, "Command CSQ output: rssi:%d, ber:%d", csq.rssi, csq.ber);
|
||||||
|
} else if (command_result == &cbc) {
|
||||||
|
ESP_LOGI(TAG, "Command battery output:%d mV", cbc.battery_status);
|
||||||
|
} else if (command_result == &bool_result) {
|
||||||
|
ESP_LOGI(TAG, "Command bool output: %s", bool_result ? "true" : "false");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, "Command %s failed with %d", at_args.command->sval[0], err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int do_at_command(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int timeout = 1000;
|
||||||
|
int nerrors = arg_parse(argc, argv, (void **)&generic_at_args);
|
||||||
|
if (nerrors != 0) {
|
||||||
|
arg_print_errors(stderr, generic_at_args.end, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
esp_modem_dce_handle_line_t handle_line = esp_modem_dce_handle_response_default;
|
||||||
|
|
||||||
|
strncpy(s_common_in_str, generic_at_args.command->sval[0], sizeof(s_common_in_str) - 2);
|
||||||
|
if (generic_at_args.no_cr->count == 0) {
|
||||||
|
size_t cmd_len = strlen(generic_at_args.command->sval[0]);
|
||||||
|
s_common_in_str[cmd_len] = '\r';
|
||||||
|
s_common_in_str[cmd_len + 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_at_args.timeout->count > 0) {
|
||||||
|
timeout = generic_at_args.timeout->ival[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_at_args.pattern->count > 0) {
|
||||||
|
strncpy(s_common_out_str, generic_at_args.pattern->sval[0], sizeof(s_common_out_str));
|
||||||
|
handle_line = handle_line_pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esp_modem_dce_generic_command(s_dce, s_common_in_str, timeout, handle_line, s_common_out_str) == ESP_OK) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_modem_lifecycle(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int nerrors = arg_parse(argc, argv, (void **)&modem_args);
|
||||||
|
if (nerrors != 0) {
|
||||||
|
arg_print_errors(stderr, modem_args.end, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (modem_args.param->count > 0) {
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (strstr(modem_args.param->sval[0], "PPP")) {
|
||||||
|
err = esp_modem_start_ppp(s_dce->dte);
|
||||||
|
} else if (strstr(modem_args.param->sval[0], "CMD")) {
|
||||||
|
err = esp_modem_stop_ppp(s_dce->dte);
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
ESP_LOGI(TAG, "set_working_mode %s succeeded", at_args.param->sval[0]);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "set_working_mode %s failed with %d", at_args.param->sval[0], err);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_dce(void)
|
||||||
|
{
|
||||||
|
at_args.command = arg_str1(NULL, NULL, "<command>", "Symbolic name of DCE command");
|
||||||
|
at_args.param_int = arg_int0("i", "int", "<num>", "Input parameter of integer type");
|
||||||
|
at_args.param_str = arg_str0("s", "str", "<str>", "Input parameter of string type");
|
||||||
|
at_args.param_pdp = arg_str0("p", "pdp", "<pdp>", "Comma separated string with PDP context");
|
||||||
|
at_args.param_bool = arg_str0("b", "bool", "<true/false>", "Input parameter of bool type");
|
||||||
|
at_args.param = arg_str0(NULL, NULL, "<param>", "Default input argument treated as string");
|
||||||
|
at_args.result = arg_str0("o", "out", "<type>", "Type of output parameter");
|
||||||
|
at_args.end = arg_end(1);
|
||||||
|
const esp_console_cmd_t at_cmd = {
|
||||||
|
.command = "dce",
|
||||||
|
.help = "send symbolic command to the modem",
|
||||||
|
.hint = NULL,
|
||||||
|
.func = &do_dce,
|
||||||
|
.argtable = &at_args
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_console_cmd_register(&at_cmd));
|
||||||
|
}
|
||||||
|
static void register_at_command(void)
|
||||||
|
{
|
||||||
|
generic_at_args.command = arg_str1(NULL, NULL, "<command>", "AT command to send to the modem");
|
||||||
|
generic_at_args.timeout = arg_int0("t", "timeout", "<timeout>", "command timeout");
|
||||||
|
generic_at_args.pattern = arg_str0("p", "pattern", "<pattern>", "command response to wait for");
|
||||||
|
generic_at_args.no_cr = arg_litn("n", "no-cr", 0, 1, "not add trailing CR to the command");
|
||||||
|
generic_at_args.end = arg_end(1);
|
||||||
|
|
||||||
|
const esp_console_cmd_t at_command = {
|
||||||
|
.command = "at",
|
||||||
|
.help = "send generic AT command to the modem",
|
||||||
|
.hint = NULL,
|
||||||
|
.func = &do_at_command,
|
||||||
|
.argtable = &generic_at_args
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_console_cmd_register(&at_command));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_modem_lifecycle(void)
|
||||||
|
{
|
||||||
|
modem_args.param = arg_str1(NULL, NULL, "<mode>", "PPP or CMD");
|
||||||
|
modem_args.end = arg_end(1);
|
||||||
|
const esp_console_cmd_t modem_cmd = {
|
||||||
|
.command = "modem",
|
||||||
|
.help = "set modem mode",
|
||||||
|
.hint = NULL,
|
||||||
|
.func = &do_modem_lifecycle,
|
||||||
|
.argtable = &modem_args
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_console_cmd_register(&modem_cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_console_repl_t *s_repl = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
|
// init the DTE
|
||||||
|
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||||
|
dte_config.event_task_stack_size = 4096;
|
||||||
|
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("internet");
|
||||||
|
dce_config.populate_command_list = true;
|
||||||
|
esp_netif_config_t ppp_netif_config = ESP_NETIF_DEFAULT_PPP();
|
||||||
|
|
||||||
|
esp_modem_dte_t *dte = esp_modem_dte_new(&dte_config);
|
||||||
|
s_dce = esp_modem_dce_new(&dce_config);
|
||||||
|
assert(s_dce != NULL);
|
||||||
|
|
||||||
|
esp_netif_t *esp_netif = esp_netif_new(&ppp_netif_config);
|
||||||
|
assert(esp_netif);
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_modem_default_attach(dte, s_dce, esp_netif));
|
||||||
|
|
||||||
|
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
||||||
|
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||||
|
// init console REPL environment
|
||||||
|
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
|
||||||
|
|
||||||
|
register_dce();
|
||||||
|
register_at_command();
|
||||||
|
register_modem_lifecycle();
|
||||||
|
modem_console_register_http();
|
||||||
|
modem_console_register_ping();
|
||||||
|
|
||||||
|
// start console REPL
|
||||||
|
ESP_ERROR_CHECK(esp_console_start_repl(s_repl));
|
||||||
|
}
|
141
esp_modem/examples/modem_console/main/ping_handle.c
Normal file
141
esp_modem/examples/modem_console/main/ping_handle.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/* Ping handle 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_console.h"
|
||||||
|
#include "argtable3/argtable3.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "ping/ping_sock.h"
|
||||||
|
#include "lwip/netdb.h"
|
||||||
|
|
||||||
|
static const char *TAG = "modem_console_ping";
|
||||||
|
|
||||||
|
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
|
||||||
|
{
|
||||||
|
uint8_t ttl;
|
||||||
|
uint16_t seqno;
|
||||||
|
uint32_t elapsed_time, recv_len;
|
||||||
|
ip_addr_t target_addr;
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
|
||||||
|
ESP_LOGI(TAG, "%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n",
|
||||||
|
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
|
||||||
|
{
|
||||||
|
uint16_t seqno;
|
||||||
|
ip_addr_t target_addr;
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
|
||||||
|
ESP_LOGE(TAG, "From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
|
||||||
|
{
|
||||||
|
ip_addr_t target_addr;
|
||||||
|
uint32_t transmitted;
|
||||||
|
uint32_t received;
|
||||||
|
uint32_t total_time_ms;
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
|
||||||
|
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
|
||||||
|
uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
|
||||||
|
if (IP_IS_V4(&target_addr)) {
|
||||||
|
ESP_LOGI(TAG, "\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr)));
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "%d packets transmitted, %d received, %d%% packet loss, time %dms\n",
|
||||||
|
transmitted, received, loss, total_time_ms);
|
||||||
|
// delete the ping sessions, so that we clean up all resources and can create a new ping session
|
||||||
|
// we don't have to call delete function in the callback, instead we can call delete function from other tasks
|
||||||
|
esp_ping_delete_session(hdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct arg_dbl *timeout;
|
||||||
|
struct arg_int *count;
|
||||||
|
struct arg_str *host;
|
||||||
|
struct arg_end *end;
|
||||||
|
} ping_args;
|
||||||
|
|
||||||
|
static int do_ping_cmd(int argc, char **argv)
|
||||||
|
{
|
||||||
|
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
|
||||||
|
|
||||||
|
int nerrors = arg_parse(argc, argv, (void **)&ping_args);
|
||||||
|
if (nerrors != 0) {
|
||||||
|
arg_print_errors(stderr, ping_args.end, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ping_args.timeout->count > 0) {
|
||||||
|
config.timeout_ms = (uint32_t)(ping_args.timeout->dval[0] * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ping_args.count->count > 0) {
|
||||||
|
config.count = (uint32_t)(ping_args.count->ival[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse IP address
|
||||||
|
ip_addr_t target_addr;
|
||||||
|
struct addrinfo hint;
|
||||||
|
struct addrinfo *res = NULL;
|
||||||
|
memset(&hint, 0, sizeof(hint));
|
||||||
|
memset(&target_addr, 0, sizeof(target_addr));
|
||||||
|
/* convert domain name to IP address */
|
||||||
|
if (getaddrinfo(ping_args.host->sval[0], NULL, &hint, &res) != 0) {
|
||||||
|
printf("ping: unknown host %s\n", ping_args.host->sval[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (res->ai_family == AF_INET) {
|
||||||
|
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
|
||||||
|
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
|
||||||
|
} else {
|
||||||
|
struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
|
||||||
|
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
|
||||||
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
|
config.target_addr = target_addr;
|
||||||
|
|
||||||
|
/* set callback functions */
|
||||||
|
esp_ping_callbacks_t cbs = {
|
||||||
|
.on_ping_success = cmd_ping_on_ping_success,
|
||||||
|
.on_ping_timeout = cmd_ping_on_ping_timeout,
|
||||||
|
.on_ping_end = cmd_ping_on_ping_end,
|
||||||
|
.cb_args = NULL
|
||||||
|
};
|
||||||
|
esp_ping_handle_t ping;
|
||||||
|
esp_ping_new_session(&config, &cbs, &ping);
|
||||||
|
esp_ping_start(ping);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void modem_console_register_ping(void)
|
||||||
|
{
|
||||||
|
ping_args.timeout = arg_dbl0("W", "timeout", "<t>", "Time to wait for a response, in seconds");
|
||||||
|
ping_args.count = arg_int0("c", "count", "<n>", "Stop after sending count packets");
|
||||||
|
ping_args.host = arg_str1(NULL, NULL, "<host>", "Host address");
|
||||||
|
ping_args.end = arg_end(1);
|
||||||
|
const esp_console_cmd_t ping_cmd = {
|
||||||
|
.command = "ping",
|
||||||
|
.help = "send ICMP ECHO_REQUEST to network hosts",
|
||||||
|
.hint = NULL,
|
||||||
|
.func = &do_ping_cmd,
|
||||||
|
.argtable = &ping_args
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(esp_console_cmd_register(&ping_cmd));
|
||||||
|
}
|
8
esp_modem/examples/modem_console/sdkconfig.defaults
Normal file
8
esp_modem/examples/modem_console/sdkconfig.defaults
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
10
esp_modem/examples/pppos_client/CMakeLists.txt
Normal file
10
esp_modem/examples/pppos_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(pppos_client)
|
||||||
|
|
||||||
|
|
9
esp_modem/examples/pppos_client/Makefile
Normal file
9
esp_modem/examples/pppos_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/pppos_client/README.md
Normal file
10
esp_modem/examples/pppos_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/pppos_client/main/CMakeLists.txt
Normal file
2
esp_modem/examples/pppos_client/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "pppos_client_main.c"
|
||||||
|
INCLUDE_DIRS ".")
|
143
esp_modem/examples/pppos_client/main/Kconfig.projbuild
Normal file
143
esp_modem/examples/pppos_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
|
4
esp_modem/examples/pppos_client/main/component.mk
Normal file
4
esp_modem/examples/pppos_client/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
422
esp_modem/examples/pppos_client/main/pppos_client_main.c
Normal file
422
esp_modem/examples/pppos_client/main/pppos_client_main.c
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
/* 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"
|
||||||
|
|
||||||
|
#if defined(CONFIG_EXAMPLE_MODEM_LEGACY_API)
|
||||||
|
#include "sim800.h"
|
||||||
|
#include "bg96.h"
|
||||||
|
#include "sim7600.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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, "Unknow line received: %s", (char *)event_data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 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, 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");
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_EXAMPLE_MODEM_LEGACY_API)
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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 = {
|
||||||
|
.uri = BROKER_URL,
|
||||||
|
.event_handle = mqtt_event_handler,
|
||||||
|
};
|
||||||
|
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
#else // defined(CONFIG_EXAMPLE_MODEM_LEGACY_API)
|
||||||
|
|
||||||
|
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 */
|
||||||
|
modem_dte_t *dte = esp_modem_dte_init(dte_config);
|
||||||
|
/* Register event handler */
|
||||||
|
ESP_ERROR_CHECK(esp_modem_set_event_handler(dte, modem_event_handler, ESP_EVENT_ANY_ID, NULL));
|
||||||
|
|
||||||
|
// Init netif object
|
||||||
|
esp_netif_t *esp_netif = esp_netif_new(ppp_config);
|
||||||
|
assert(esp_netif);
|
||||||
|
|
||||||
|
void *modem_netif_adapter = esp_modem_netif_setup(dte);
|
||||||
|
esp_modem_netif_set_default_handlers(modem_netif_adapter, esp_netif);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
modem_dce_t *dce = NULL;
|
||||||
|
/* create dce object */
|
||||||
|
#if CONFIG_EXAMPLE_MODEM_DEVICE_SIM800
|
||||||
|
dce = sim800_init(dte);
|
||||||
|
#elif CONFIG_EXAMPLE_MODEM_DEVICE_BG96
|
||||||
|
dce = bg96_init(dte);
|
||||||
|
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600
|
||||||
|
dce = sim7600_init(dte);
|
||||||
|
#else
|
||||||
|
#error "Unsupported DCE"
|
||||||
|
#endif
|
||||||
|
assert(dce != NULL);
|
||||||
|
ESP_ERROR_CHECK(dce->set_flow_ctrl(dce, ESP_MODEM_FLOW_CONTROL_NONE));
|
||||||
|
ESP_ERROR_CHECK(dce->store_profile(dce));
|
||||||
|
/* Print Module ID, Operator, IMEI, IMSI */
|
||||||
|
ESP_LOGI(TAG, "Module: %s", dce->name);
|
||||||
|
ESP_LOGI(TAG, "Operator: %s", dce->oper);
|
||||||
|
ESP_LOGI(TAG, "IMEI: %s", dce->imei);
|
||||||
|
ESP_LOGI(TAG, "IMSI: %s", dce->imsi);
|
||||||
|
|
||||||
|
/* Get signal quality */
|
||||||
|
uint32_t rssi = 0, ber = 0;
|
||||||
|
ESP_ERROR_CHECK(dce->get_signal_quality(dce, &rssi, &ber));
|
||||||
|
ESP_LOGI(TAG, "rssi: %d, ber: %d", rssi, ber);
|
||||||
|
/* Get battery voltage */
|
||||||
|
uint32_t voltage = 0, bcs = 0, bcl = 0;
|
||||||
|
ESP_ERROR_CHECK(dce->get_battery_status(dce, &bcs, &bcl, &voltage));
|
||||||
|
ESP_LOGI(TAG, "Battery voltage: %d mV", voltage);
|
||||||
|
/* setup PPPoS network parameters */
|
||||||
|
#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
|
||||||
|
/* attach the modem to the network interface */
|
||||||
|
esp_netif_attach(esp_netif, modem_netif_adapter);
|
||||||
|
/* Wait for IP address */
|
||||||
|
xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
|
/* Config MQTT */
|
||||||
|
esp_mqtt_client_config_t mqtt_config = {
|
||||||
|
.uri = BROKER_URL,
|
||||||
|
.event_handle = mqtt_event_handler,
|
||||||
|
};
|
||||||
|
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
|
||||||
|
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);
|
||||||
|
#if CONFIG_EXAMPLE_SEND_MSG
|
||||||
|
const char *message = "Welcome to ESP32!";
|
||||||
|
ESP_ERROR_CHECK(example_send_message_text(dce, CONFIG_EXAMPLE_SEND_MSG_PEER_PHONE_NUMBER, message));
|
||||||
|
ESP_LOGI(TAG, "Send send message [%s] ok", message);
|
||||||
|
#endif
|
||||||
|
/* Power down module */
|
||||||
|
ESP_ERROR_CHECK(dce->power_down(dce));
|
||||||
|
ESP_LOGI(TAG, "Power down");
|
||||||
|
ESP_ERROR_CHECK(dce->deinit(dce));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Restart after 60 seconds");
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unregister events, destroy the netif adapter and destroy its esp-netif instance */
|
||||||
|
esp_modem_netif_clear_default_handlers(modem_netif_adapter);
|
||||||
|
esp_modem_netif_teardown(modem_netif_adapter);
|
||||||
|
esp_netif_destroy(esp_netif);
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(dte->deinit(dte));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CONFIG_EXAMPLE_MODEM_LEGACY_API
|
7
esp_modem/examples/pppos_client/sdkconfig.defaults
Normal file
7
esp_modem/examples/pppos_client/sdkconfig.defaults
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# 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
|
3
esp_modem/idf_component.yml
Normal file
3
esp_modem/idf_component.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version: "0.0.6"
|
||||||
|
name: esp_modem
|
||||||
|
description: esp modem
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -17,11 +17,15 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "esp_modem_dce.h"
|
|
||||||
#include "esp_modem_dte.h"
|
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "driver/uart.h"
|
#include "driver/uart.h"
|
||||||
#include "esp_modem_compat.h"
|
|
||||||
|
/**
|
||||||
|
* @brief Fowrard declare DTE and DCE objects
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_dte esp_modem_dte_t;
|
||||||
|
typedef struct esp_modem_dce esp_modem_dce_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Declare Event Base for ESP Modem
|
* @brief Declare Event Base for ESP Modem
|
||||||
@ -39,6 +43,25 @@ typedef enum {
|
|||||||
ESP_MODEM_EVENT_UNKNOWN = 4 /*!< ESP Modem Unknown Response */
|
ESP_MODEM_EVENT_UNKNOWN = 4 /*!< ESP Modem Unknown Response */
|
||||||
} esp_modem_event_t;
|
} esp_modem_event_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ESP_MODEM_DTE_TYPES DTE Types
|
||||||
|
* @brief Configuration and related types used to init and setup a new DTE object
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup ESP_MODEM_DTE_TYPES
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
*
|
*
|
||||||
@ -48,7 +71,7 @@ typedef struct {
|
|||||||
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 */
|
||||||
uart_parity_t parity; /*!< Parity type */
|
uart_parity_t parity; /*!< Parity type */
|
||||||
modem_flow_ctrl_t flow_control; /*!< Flow control type */
|
esp_modem_flow_ctrl_t flow_control; /*!< Flow control type */
|
||||||
uint32_t baud_rate; /*!< Communication baud rate */
|
uint32_t baud_rate; /*!< Communication baud rate */
|
||||||
int tx_io_num; /*!< TXD Pin Number */
|
int tx_io_num; /*!< TXD Pin Number */
|
||||||
int rx_io_num; /*!< RXD Pin Number */
|
int rx_io_num; /*!< RXD Pin Number */
|
||||||
@ -63,12 +86,6 @@ typedef struct {
|
|||||||
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;
|
} esp_modem_dte_config_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Type used for reception callback
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef esp_err_t (*esp_modem_on_receive)(void *buffer, size_t len, void *context);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ESP Modem DTE Default Configuration
|
* @brief ESP Modem DTE Default Configuration
|
||||||
*
|
*
|
||||||
@ -80,7 +97,7 @@ typedef esp_err_t (*esp_modem_on_receive)(void *buffer, size_t len, void *contex
|
|||||||
.stop_bits = UART_STOP_BITS_1, \
|
.stop_bits = UART_STOP_BITS_1, \
|
||||||
.parity = UART_PARITY_DISABLE, \
|
.parity = UART_PARITY_DISABLE, \
|
||||||
.baud_rate = 115200, \
|
.baud_rate = 115200, \
|
||||||
.flow_control = MODEM_FLOW_CONTROL_NONE,\
|
.flow_control = ESP_MODEM_FLOW_CONTROL_NONE,\
|
||||||
.tx_io_num = 25, \
|
.tx_io_num = 25, \
|
||||||
.rx_io_num = 26, \
|
.rx_io_num = 26, \
|
||||||
.rts_io_num = 27, \
|
.rts_io_num = 27, \
|
||||||
@ -94,6 +111,80 @@ typedef esp_err_t (*esp_modem_on_receive)(void *buffer, size_t len, void *contex
|
|||||||
.line_buffer_size = 512 \
|
.line_buffer_size = 512 \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ESP_MODEM_DCE_TYPES DCE Types
|
||||||
|
* @brief Configuration and related types used to init and setup a new DCE object
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup ESP_MODEM_DCE_TYPES
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PDP context type used as an input parameter to esp_modem_dce_set_pdp_context
|
||||||
|
* also used as a part of configuration structure
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_dce_pdp_ctx_s {
|
||||||
|
size_t cid; /*!< PDP context identifier */
|
||||||
|
const char *type; /*!< Protocol type */
|
||||||
|
const char *apn; /*!< Modem APN (Access Point Name, a logical name to choose data network) */
|
||||||
|
} esp_modem_dce_pdp_ctx_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Devices that the DCE will act as
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef enum esp_modem_dce_device_e {
|
||||||
|
ESP_MODEM_DEVICE_UNSPECIFIED,
|
||||||
|
ESP_MODEM_DEVICE_SIM800,
|
||||||
|
ESP_MODEM_DEVICE_SIM7600,
|
||||||
|
ESP_MODEM_DEVICE_BG96,
|
||||||
|
} esp_modem_dce_device_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DCE's configuration structure
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_dce_config_s {
|
||||||
|
esp_modem_dce_pdp_ctx_t pdp_context; /*!< modem PDP context including APN */
|
||||||
|
bool populate_command_list; /*!< use command list interface: Setting this to true creates
|
||||||
|
a list of supported AT commands enabling sending
|
||||||
|
these commands, but will occupy data memory */
|
||||||
|
esp_modem_dce_device_t device; /*!< predefined device enum that the DCE will initialise as */
|
||||||
|
} esp_modem_dce_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default configuration of DCE unit of ESP-MODEM
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define ESP_MODEM_DCE_DEFAULT_CONFIG(APN) \
|
||||||
|
{ \
|
||||||
|
.pdp_context = { \
|
||||||
|
.cid = 1, \
|
||||||
|
.type = "IP", \
|
||||||
|
.apn = APN }, \
|
||||||
|
.populate_command_list = false,\
|
||||||
|
.device = ESP_MODEM_DEVICE_UNSPECIFIED \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ESP_MODEM_DTE_DCE DCE and DCE object init and setup API
|
||||||
|
* @brief Creating and init objects of DTE and DCE
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup ESP_MODEM_DTE_DCE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create and initialize Modem DTE object
|
* @brief Create and initialize Modem DTE object
|
||||||
*
|
*
|
||||||
@ -101,7 +192,42 @@ typedef esp_err_t (*esp_modem_on_receive)(void *buffer, size_t len, void *contex
|
|||||||
* @return modem_dte_t*
|
* @return modem_dte_t*
|
||||||
* - Modem DTE object
|
* - Modem DTE object
|
||||||
*/
|
*/
|
||||||
modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config);
|
esp_modem_dte_t *esp_modem_dte_new(const esp_modem_dte_config_t *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create and initialize Modem DCE object
|
||||||
|
*
|
||||||
|
* @param config configuration of ESP Modem DTE object
|
||||||
|
* @return modem_dce_t* Modem DCE object
|
||||||
|
*/
|
||||||
|
esp_modem_dce_t *esp_modem_dce_new(esp_modem_dce_config_t *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the DCE object that has already been created
|
||||||
|
*
|
||||||
|
* This API is typically used to initialize extended DCE object,
|
||||||
|
* "sub-class" of esp_modem_dce_t
|
||||||
|
*
|
||||||
|
* @param config Configuration for DCE object
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error (init issue, set specific command issue)
|
||||||
|
* - ESP_ERR_INVALID_ARG on invalid parameters
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_init(esp_modem_dce_t *dce, esp_modem_dce_config_t *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ESP_MODEM_EVENTS Event handling API
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup ESP_MODEM_EVENTS
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register event handler for ESP Modem event loop
|
* @brief Register event handler for ESP Modem event loop
|
||||||
@ -114,7 +240,7 @@ modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config);
|
|||||||
* - ESP_ERR_NO_MEM on allocating memory for the handler failed
|
* - ESP_ERR_NO_MEM on allocating memory for the handler failed
|
||||||
* - ESP_ERR_INVALID_ARG on invalid combination of event base and event id
|
* - ESP_ERR_INVALID_ARG on invalid combination of event base and event id
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_set_event_handler(modem_dte_t *dte, esp_event_handler_t handler, int32_t event_id, void *handler_args);
|
esp_err_t esp_modem_set_event_handler(esp_modem_dte_t *dte, esp_event_handler_t handler, int32_t event_id, void *handler_args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unregister event handler for ESP Modem event loop
|
* @brief Unregister event handler for ESP Modem event loop
|
||||||
@ -125,7 +251,21 @@ esp_err_t esp_modem_set_event_handler(modem_dte_t *dte, esp_event_handler_t hand
|
|||||||
* - ESP_OK on success
|
* - ESP_OK on success
|
||||||
* - ESP_ERR_INVALID_ARG on invalid combination of event base and event id
|
* - ESP_ERR_INVALID_ARG on invalid combination of event base and event id
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t handler);
|
esp_err_t esp_modem_remove_event_handler(esp_modem_dte_t *dte, esp_event_handler_t handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ESP_MODEM_LIFECYCLE Modem lifecycle API
|
||||||
|
* @brief Basic modem API to start/stop the PPP mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup ESP_MODEM_LIFECYCLE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Setup PPP Session
|
* @brief Setup PPP Session
|
||||||
@ -135,7 +275,7 @@ esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t h
|
|||||||
* - ESP_OK on success
|
* - ESP_OK on success
|
||||||
* - ESP_FAIL on error
|
* - ESP_FAIL on error
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_start_ppp(modem_dte_t *dte);
|
esp_err_t esp_modem_start_ppp(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Exit PPP Session
|
* @brief Exit PPP Session
|
||||||
@ -145,29 +285,49 @@ esp_err_t esp_modem_start_ppp(modem_dte_t *dte);
|
|||||||
* - ESP_OK on success
|
* - ESP_OK on success
|
||||||
* - ESP_FAIL on error
|
* - ESP_FAIL on error
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_stop_ppp(modem_dte_t *dte);
|
esp_err_t esp_modem_stop_ppp(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Setup on reception callback
|
* @brief Basic start of the modem. This API performs default dce's start_up() function
|
||||||
*
|
*
|
||||||
* @param dte ESP Modem DTE object
|
* @param dte Modem DTE Object
|
||||||
* @param receive_cb Function pointer to the reception callback
|
* @return esp_err_t
|
||||||
* @param receive_cb_ctx Contextual pointer to be passed to the reception callback
|
* - ESP_OK on success
|
||||||
*
|
* - ESP_FAIL on error
|
||||||
* @return ESP_OK on success
|
* - ESP_ERR_INVALID_ARG on invalid arguments
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_set_rx_cb(modem_dte_t *dte, esp_modem_on_receive receive_cb, void *receive_cb_ctx);
|
esp_err_t esp_modem_default_start(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Notify the modem, that ppp netif has closed
|
* @brief Basic attach operation of modem sub-elements
|
||||||
*
|
*
|
||||||
* @note This API should only be used internally by the modem-netif layer
|
* This API binds the supplied DCE and netif to the modem's DTE and initializes the modem
|
||||||
*
|
*
|
||||||
* @param dte ESP Modem DTE object
|
* @param dte Modem DTE Object
|
||||||
*
|
* @return esp_err_t
|
||||||
* @return ESP_OK on success
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_notify_ppp_netif_closed(modem_dte_t *dte);
|
esp_err_t esp_modem_default_attach(esp_modem_dte_t *dte, esp_modem_dce_t *dce, esp_netif_t* ppp_netif);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Basic destroy operation of the modem DTE and all the sub-elements bound to it
|
||||||
|
*
|
||||||
|
* This API deletes the DCE, modem netif adapter as well as the esp_netif supplied to
|
||||||
|
* esp_modem_default_attach(). Then it deletes the DTE itself.
|
||||||
|
*
|
||||||
|
* @param dte Modem DTE Object
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_INVALID_ARG on invalid arguments
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_default_destroy(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ESP Modem Event backward compatible version
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
MODEM_EVENT_PPP_START = 0x100,
|
|
||||||
MODEM_EVENT_PPP_CONNECT = 0x101,
|
|
||||||
MODEM_EVENT_PPP_DISCONNECT = 0x102,
|
|
||||||
MODEM_EVENT_PPP_STOP = 0x103,
|
|
||||||
MODEM_EVENT_UNKNOWN = 0x104,
|
|
||||||
} esp_modem_compat_event_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief PPPoS Client IP Information backward compatible version
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
ip4_addr_t ip; /*!< IP Address */
|
|
||||||
ip4_addr_t netmask; /*!< Net Mask */
|
|
||||||
ip4_addr_t gw; /*!< Gateway */
|
|
||||||
ip4_addr_t ns1; /*!< Name Server1 */
|
|
||||||
ip4_addr_t ns2; /*!< Name Server2 */
|
|
||||||
} ppp_client_ip_info_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Backward compatible version of esp_modem_set_event_handler()
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_add_event_handler(modem_dte_t *dte, esp_event_handler_t handler, void *handler_args) __attribute__ ((deprecated));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Backward compatible version of creating esp-netif(PPP) and attaching to esp_modem_start_ppp()
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_setup_ppp(modem_dte_t *dte) __attribute__ ((deprecated));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Backward compatible version of deleting esp-netif and esp_modem_stop_ppp()
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_exit_ppp(modem_dte_t *dte) __attribute__ ((deprecated));
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -19,81 +19,218 @@ extern "C" {
|
|||||||
|
|
||||||
#include "esp_types.h"
|
#include "esp_types.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
#include "esp_modem.h"
|
||||||
#include "esp_modem_dte.h"
|
#include "esp_modem_dte.h"
|
||||||
|
|
||||||
typedef struct modem_dce modem_dce_t;
|
|
||||||
typedef struct modem_dte modem_dte_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Result Code from DCE
|
* @brief Forward declaration of the command list object, which (if enabled) is used
|
||||||
*
|
* to populate a command palette and access commands by its symbolic name
|
||||||
*/
|
*/
|
||||||
#define MODEM_RESULT_CODE_SUCCESS "OK" /*!< Acknowledges execution of a command */
|
struct esp_modem_dce_cmd_list;
|
||||||
#define MODEM_RESULT_CODE_CONNECT "CONNECT" /*!< A connection has been established */
|
|
||||||
#define MODEM_RESULT_CODE_RING "RING" /*!< Detect an incoming call signal from network */
|
|
||||||
#define MODEM_RESULT_CODE_NO_CARRIER "NO CARRIER" /*!< Connection termincated or establish a connection failed */
|
|
||||||
#define MODEM_RESULT_CODE_ERROR "ERROR" /*!< Command not recognized, command line maximum length exceeded, parameter value invalid */
|
|
||||||
#define MODEM_RESULT_CODE_NO_DIALTONE "NO DIALTONE" /*!< No dial tone detected */
|
|
||||||
#define MODEM_RESULT_CODE_BUSY "BUSY" /*!< Engaged signal detected */
|
|
||||||
#define MODEM_RESULT_CODE_NO_ANSWER "NO ANSWER" /*!< Wait for quiet answer */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Specific Length Constraint
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define MODEM_MAX_NAME_LENGTH (32) /*!< Max Module Name Length */
|
|
||||||
#define MODEM_MAX_OPERATOR_LENGTH (32) /*!< Max Operator Name Length */
|
|
||||||
#define MODEM_IMEI_LENGTH (15) /*!< IMEI Number Length */
|
|
||||||
#define MODEM_IMSI_LENGTH (15) /*!< IMSI Number Length */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Specific Timeout Constraint, Unit: millisecond
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define MODEM_COMMAND_TIMEOUT_DEFAULT (500) /*!< Default timeout value for most commands */
|
|
||||||
#define MODEM_COMMAND_TIMEOUT_OPERATOR (75000) /*!< Timeout value for getting operator status */
|
|
||||||
#define MODEM_COMMAND_TIMEOUT_MODE_CHANGE (5000) /*!< Timeout value for changing working mode */
|
|
||||||
#define MODEM_COMMAND_TIMEOUT_HANG_UP (90000) /*!< Timeout value for hang up */
|
|
||||||
#define MODEM_COMMAND_TIMEOUT_POWEROFF (1000) /*!< Timeout value for power down */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Working state of DCE
|
* @brief Working state of DCE
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MODEM_STATE_PROCESSING, /*!< In processing */
|
ESP_MODEM_STATE_PROCESSING, /*!< In processing */
|
||||||
MODEM_STATE_SUCCESS, /*!< Process successfully */
|
ESP_MODEM_STATE_SUCCESS, /*!< Process successfully */
|
||||||
MODEM_STATE_FAIL /*!< Process failed */
|
ESP_MODEM_STATE_FAIL /*!< Process failed */
|
||||||
} modem_state_t;
|
} esp_modem_state_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generic command type used in DCE unit
|
||||||
|
*/
|
||||||
|
typedef esp_err_t (*dce_command_t)(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of line handlers called fro DTE upon line response reception
|
||||||
|
*/
|
||||||
|
typedef esp_err_t (*esp_modem_dce_handle_line_t)(esp_modem_dce_t *dce, const char *line);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief DCE(Data Communication Equipment)
|
* @brief DCE(Data Communication Equipment)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct modem_dce {
|
struct esp_modem_dce {
|
||||||
char imei[MODEM_IMEI_LENGTH + 1]; /*!< IMEI number */
|
esp_modem_state_t state; /*!< Modem working state */
|
||||||
char imsi[MODEM_IMSI_LENGTH + 1]; /*!< IMSI number */
|
esp_modem_mode_t mode; /*!< Working mode */
|
||||||
char name[MODEM_MAX_NAME_LENGTH]; /*!< Module name */
|
esp_modem_dte_t *dte; /*!< DTE which connect to DCE */
|
||||||
char oper[MODEM_MAX_OPERATOR_LENGTH]; /*!< Operator name */
|
struct esp_modem_dce_cmd_list *dce_cmd_list;
|
||||||
modem_state_t state; /*!< Modem working state */
|
esp_modem_dce_config_t config;
|
||||||
modem_mode_t mode; /*!< Working mode */
|
esp_modem_dce_handle_line_t handle_line; /*!< Handle line strategy */
|
||||||
modem_dte_t *dte; /*!< DTE which connect to DCE */
|
|
||||||
esp_err_t (*handle_line)(modem_dce_t *dce, const char *line); /*!< Handle line strategy */
|
void *handle_line_ctx; /*!< DCE context reserved for handle_line
|
||||||
esp_err_t (*sync)(modem_dce_t *dce); /*!< Synchronization */
|
processing */
|
||||||
esp_err_t (*echo_mode)(modem_dce_t *dce, bool on); /*!< Echo command on or off */
|
// higher level actions DCE unit can take
|
||||||
esp_err_t (*store_profile)(modem_dce_t *dce); /*!< Store user settings */
|
esp_err_t (*set_working_mode)(esp_modem_dce_t *dce, esp_modem_mode_t mode); /*!< Set working mode */
|
||||||
esp_err_t (*set_flow_ctrl)(modem_dce_t *dce, modem_flow_ctrl_t flow_ctrl); /*!< Flow control on or off */
|
esp_err_t (*deinit)(esp_modem_dce_t *dce); /*!< Destroys the DCE */
|
||||||
esp_err_t (*get_signal_quality)(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber); /*!< Get signal quality */
|
esp_err_t (*start_up)(esp_modem_dce_t *dce); /*!< Start-up sequence */
|
||||||
esp_err_t (*get_battery_status)(modem_dce_t *dce, uint32_t *bcs,
|
|
||||||
uint32_t *bcl, uint32_t *voltage); /*!< Get battery status */
|
// list of essential commands for esp-modem basic work
|
||||||
esp_err_t (*define_pdp_context)(modem_dce_t *dce, uint32_t cid,
|
dce_command_t hang_up; /*!< generic command for hang-up */
|
||||||
const char *type, const char *apn); /*!< Set PDP Contex */
|
dce_command_t set_pdp_context; /*!< generic command for pdp context */
|
||||||
esp_err_t (*set_working_mode)(modem_dce_t *dce, modem_mode_t mode); /*!< Set working mode */
|
dce_command_t set_data_mode; /*!< generic command for data mode */
|
||||||
esp_err_t (*hang_up)(modem_dce_t *dce); /*!< Hang up */
|
dce_command_t resume_data_mode; /*!< generic command to resume already dialed data mode */
|
||||||
esp_err_t (*power_down)(modem_dce_t *dce); /*!< Normal power down */
|
dce_command_t set_command_mode; /*!< generic command for command mode */
|
||||||
esp_err_t (*deinit)(modem_dce_t *dce); /*!< Deinitialize */
|
dce_command_t set_echo; /*!< generic command for echo mode */
|
||||||
|
dce_command_t sync; /*!< generic command for sync */
|
||||||
|
dce_command_t set_flow_ctrl; /*!< generic command for flow-ctrl */
|
||||||
|
dce_command_t store_profile; /*!< generic command for store-profile */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// DCE commands building blocks
|
||||||
|
/**
|
||||||
|
* @brief Sending generic command to DCE
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] command String command
|
||||||
|
* @param[in] timeout Command timeout in ms
|
||||||
|
* @param[in] handle_line Function ptr which processes the command response
|
||||||
|
* @param[in] ctx Function ptr context
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_generic_command(esp_modem_dce_t *dce, const char * command, uint32_t timeout, esp_modem_dce_handle_line_t handle_line, void *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicate that processing current command has done
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param state Modem state after processing
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_process_command_done(esp_modem_dce_t *dce, esp_modem_state_t state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default handler for response
|
||||||
|
* Some responses for command are simple, commonly will return OK when succeed of ERROR when failed
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param line line string
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_handle_response_default(esp_modem_dce_t *dce, const char *line);
|
||||||
|
|
||||||
|
|
||||||
|
// DCE higher level commands
|
||||||
|
/**
|
||||||
|
* @brief Set Working Mode
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param mode working mode
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_working_mode(esp_modem_dce_t *dce, esp_modem_mode_t mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default start-up sequence, which sets the modem into an operational mode
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_default_start_up(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroys the DCE
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_default_destroy(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the DCE
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param config DCE configuration structure
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_default_init(esp_modem_dce_t *dce, esp_modem_dce_config_t* config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the DCE parameters. This API updates runtime DCE config parameters,
|
||||||
|
* typically used to update PDP context data.
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param config DCE configuration structure
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_params(esp_modem_dce_t *dce, esp_modem_dce_config_t* config);
|
||||||
|
|
||||||
|
|
||||||
|
// list command operations
|
||||||
|
/**
|
||||||
|
* @brief Executes a specific command from the list
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param command Symbolic name of the command to execute
|
||||||
|
* @param param Generic parameter to the command
|
||||||
|
* @param result Generic output parameter
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_command_list_run(esp_modem_dce_t *dce, const char * command, void * param, void* result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinitialize the command list
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_command_list_deinit(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes default command list with predefined command palette
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_set_default_command_list(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add or set specific command to the command list
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param command_id Command symbolic name
|
||||||
|
* @param command Generic command function pointer
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_command_list_set_cmd(esp_modem_dce_t *dce, const char * command_id, dce_command_t command);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
359
esp_modem/include/esp_modem_dce_common_commands.h
Normal file
359
esp_modem/include/esp_modem_dce_common_commands.h
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Result Code from DCE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define MODEM_RESULT_CODE_SUCCESS "OK" /*!< Acknowledges execution of a command */
|
||||||
|
#define MODEM_RESULT_CODE_CONNECT "CONNECT" /*!< A connection has been established */
|
||||||
|
#define MODEM_RESULT_CODE_RING "RING" /*!< Detect an incoming call signal from network */
|
||||||
|
#define MODEM_RESULT_CODE_NO_CARRIER "NO CARRIER" /*!< Connection termincated or establish a connection failed */
|
||||||
|
#define MODEM_RESULT_CODE_ERROR "ERROR" /*!< Command not recognized, command line maximum length exceeded, parameter value invalid */
|
||||||
|
#define MODEM_RESULT_CODE_NO_DIALTONE "NO DIALTONE" /*!< No dial tone detected */
|
||||||
|
#define MODEM_RESULT_CODE_BUSY "BUSY" /*!< Engaged signal detected */
|
||||||
|
#define MODEM_RESULT_CODE_NO_ANSWER "NO ANSWER" /*!< Wait for quiet answer */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specific Timeout Constraint, Unit: millisecond
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define MODEM_COMMAND_TIMEOUT_DEFAULT (500) /*!< Default timeout value for most commands */
|
||||||
|
#define MODEM_COMMAND_TIMEOUT_OPERATOR (75000) /*!< Timeout value for getting operator status */
|
||||||
|
#define MODEM_COMMAND_TIMEOUT_RESET (60000) /*!< Timeout value for reset command */
|
||||||
|
#define MODEM_COMMAND_TIMEOUT_MODE_CHANGE (5000) /*!< Timeout value for changing working mode */
|
||||||
|
#define MODEM_COMMAND_TIMEOUT_POWEROFF (1000) /*!< Timeout value for power down */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Strip the tailed "\r\n"
|
||||||
|
*
|
||||||
|
* @param str string to strip
|
||||||
|
* @param len length of string
|
||||||
|
*/
|
||||||
|
static inline void strip_cr_lf_tail(char *str, uint32_t len)
|
||||||
|
{
|
||||||
|
if (str[len - 2] == '\r') {
|
||||||
|
str[len - 2] = '\0';
|
||||||
|
} else if (str[len - 1] == '\r') {
|
||||||
|
str[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synchronization
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_sync(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable or not echo mode of DCE
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param[in] param bool casted to (void*): true to enable echo mode, false to disable echo mode
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_echo(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Store current parameter setting in the user profile
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_store_profile(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set flow control mode of DCE in data mode
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param esp_modem_flow_ctrl_t casted to (void*): flow control mode
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_flow_ctrl(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define PDP context
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param esp_modem_dce_pdp_ctx_t type defining PDP context
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_pdp_context(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hang up
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_hang_up(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signal strength structure used as a result to esp_modem_dce_get_signal_quality() API
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_dce_csq_ctx_s {
|
||||||
|
int rssi; //!< Signal strength indication
|
||||||
|
int ber; //!< Channel bit error rate
|
||||||
|
} esp_modem_dce_csq_ctx_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get signal quality
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result esp_modem_dce_csq_ctx_t type returning rssi and ber values
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_get_signal_quality(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Voltage status structure used as a result to esp_modem_dce_get_battery_status() API
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_dce_cbc_ctx_s {
|
||||||
|
int battery_status; //!< current status in mV
|
||||||
|
int bcs; //!< charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||||
|
int bcl; //!< 1-100% battery capacity, -1-Not available
|
||||||
|
} esp_modem_dce_cbc_ctx_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get battery status
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result esp_modem_dce_cbc_ctx_t type returning battery status and other fields if available
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_get_battery_status(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get DCE module IMEI number
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param size_t of output string length (casted to void*), max size the resultant string
|
||||||
|
* @param[out] result pointer to the string where the resultant IMEI number gets copied (if size param fits)
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_get_imei_number(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get DCE module IMSI number
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param size_t of output string length (casted to void*), max size the resultant string
|
||||||
|
* @param[out] result pointer to the string where the resultant IMSI number gets copied (if size param fits)
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_get_imsi_number(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get DCE module name
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param size_t of output string length (casted to void*), max size the resultant string
|
||||||
|
* @param[out] result pointer to the string where the resultant module name gets copied (if size param fits)
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_get_module_name(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get operator name
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param size_t of output string length (casted to void*), max size the resultant string
|
||||||
|
* @param[out] result pointer to the string where the resultant operator name gets copied (if size param fits)
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_get_operator_name(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switch to data mode
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_data_mode(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resume the data mode when PPP has already been started, but switched back to command
|
||||||
|
* mode (typically using the `+++` PPP escape sequence)
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_resume_data_mode(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switch to command mode
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_command_mode(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Power-down the module
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_power_down(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the module
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_reset(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the module waits for entering the PIN
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param None
|
||||||
|
* @param[out] result pointer to bool indicating READY if set to true
|
||||||
|
* or the module is waiting for PIN if set to false
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_read_pin(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enters the PIN number
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param 4 character string pointer to the PIN
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_pin(esp_modem_dce_t *dce, void *param, void *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the DCE to temporarily use the baudrate specified
|
||||||
|
*
|
||||||
|
* @param[in] dce Modem DCE object
|
||||||
|
* @param[in] param string pointer to char representation of the baudrate
|
||||||
|
* @param[out] result None
|
||||||
|
*
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
* - ESP_ERR_TIMEOUT if timeout while waiting for expected response
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_baud_temp(esp_modem_dce_t *dce, void *param, void *result);
|
@ -1,131 +0,0 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "esp_modem_dce.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Indicate that processing current command has done
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param state Modem state after processing
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static inline esp_err_t esp_modem_process_command_done(modem_dce_t *dce, modem_state_t state)
|
|
||||||
{
|
|
||||||
dce->state = state;
|
|
||||||
return dce->dte->process_cmd_done(dce->dte);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Strip the tailed "\r\n"
|
|
||||||
*
|
|
||||||
* @param str string to strip
|
|
||||||
* @param len length of string
|
|
||||||
*/
|
|
||||||
static inline void strip_cr_lf_tail(char *str, uint32_t len)
|
|
||||||
{
|
|
||||||
if (str[len - 2] == '\r') {
|
|
||||||
str[len - 2] = '\0';
|
|
||||||
} else if (str[len - 1] == '\r') {
|
|
||||||
str[len - 1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Default handler for response
|
|
||||||
* Some responses for command are simple, commonly will return OK when succeed of ERROR when failed
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param line line string
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_dce_handle_response_default(modem_dce_t *dce, const char *line);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Syncronization
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_dce_sync(modem_dce_t *dce);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enable or not echo mode of DCE
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param on true to enable echo mode, false to disable echo mode
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_dce_echo(modem_dce_t *dce, bool on);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Store current parameter setting in the user profile
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_dce_store_profile(modem_dce_t *dce);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set flow control mode of DCE in data mode
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param flow_ctrl flow control mode
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_dce_set_flow_ctrl(modem_dce_t *dce, modem_flow_ctrl_t flow_ctrl);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Define PDP context
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param cid PDP context identifier
|
|
||||||
* @param type Protocol type
|
|
||||||
* @param apn Access point name
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_dce_define_pdp_context(modem_dce_t *dce, uint32_t cid, const char *type, const char *apn);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Hang up
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
esp_err_t esp_modem_dce_hang_up(modem_dce_t *dce);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2018-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -21,46 +21,81 @@ extern "C" {
|
|||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
|
|
||||||
typedef struct modem_dte modem_dte_t;
|
|
||||||
typedef struct modem_dce modem_dce_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Working mode of Modem
|
* @brief Working mode of Modem
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MODEM_COMMAND_MODE = 0, /*!< Command Mode */
|
ESP_MODEM_COMMAND_MODE = 0, /*!< Command Mode */
|
||||||
MODEM_PPP_MODE, /*!< PPP Mode */
|
ESP_MODEM_PPP_MODE, /*!< PPP Mode */
|
||||||
MODEM_TRANSITION_MODE /*!< Transition Mode betwen data and command mode indicating that
|
ESP_MODEM_TRANSITION_MODE /*!< Transition Mode between data and command mode indicating that
|
||||||
the modem is not yet ready for sending commands nor data */
|
the modem is not yet ready for sending commands nor data */
|
||||||
} modem_mode_t;
|
} esp_modem_mode_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Modem flow control type
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
MODEM_FLOW_CONTROL_NONE = 0,
|
|
||||||
MODEM_FLOW_CONTROL_SW,
|
|
||||||
MODEM_FLOW_CONTROL_HW
|
|
||||||
} modem_flow_ctrl_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief DTE(Data Terminal Equipment)
|
* @brief DTE(Data Terminal Equipment)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct modem_dte {
|
struct esp_modem_dte {
|
||||||
modem_flow_ctrl_t flow_ctrl; /*!< Flow control of DTE */
|
esp_modem_flow_ctrl_t flow_ctrl; /*!< Flow control of DTE */
|
||||||
modem_dce_t *dce; /*!< DCE which connected to the DTE */
|
esp_modem_dce_t *dce; /*!< DCE which connected to the DTE */
|
||||||
esp_err_t (*send_cmd)(modem_dte_t *dte, const char *command, uint32_t timeout); /*!< Send command to DCE */
|
struct esp_modem_netif_driver_s *netif_adapter;
|
||||||
int (*send_data)(modem_dte_t *dte, const char *data, uint32_t length); /*!< Send data to DCE */
|
esp_err_t (*send_cmd)(esp_modem_dte_t *dte, const char *command, uint32_t timeout); /*!< Send command to DCE */
|
||||||
esp_err_t (*send_wait)(modem_dte_t *dte, const char *data, uint32_t length,
|
int (*send_data)(esp_modem_dte_t *dte, const char *data, uint32_t length); /*!< Send data to DCE */
|
||||||
|
esp_err_t (*send_wait)(esp_modem_dte_t *dte, const char *data, uint32_t length,
|
||||||
const char *prompt, uint32_t timeout); /*!< Wait for specific prompt */
|
const char *prompt, uint32_t timeout); /*!< Wait for specific prompt */
|
||||||
esp_err_t (*change_mode)(modem_dte_t *dte, modem_mode_t new_mode); /*!< Changing working mode */
|
esp_err_t (*change_mode)(esp_modem_dte_t *dte, esp_modem_mode_t new_mode); /*!< Changing working mode */
|
||||||
esp_err_t (*process_cmd_done)(modem_dte_t *dte); /*!< Callback when DCE process command done */
|
esp_err_t (*process_cmd_done)(esp_modem_dte_t *dte); /*!< Callback when DCE process command done */
|
||||||
esp_err_t (*deinit)(modem_dte_t *dte); /*!< Deinitialize */
|
esp_err_t (*deinit)(esp_modem_dte_t *dte); /*!< Deinitialize */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type used for reception callback
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef esp_err_t (*esp_modem_on_receive)(void *buffer, size_t len, void *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Setup on reception callback
|
||||||
|
*
|
||||||
|
* @param dte ESP Modem DTE object
|
||||||
|
* @param receive_cb Function pointer to the reception callback
|
||||||
|
* @param receive_cb_ctx Contextual pointer to be passed to the reception callback
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_set_rx_cb(esp_modem_dte_t *dte, esp_modem_on_receive receive_cb, void *receive_cb_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify the modem, that ppp netif has closed
|
||||||
|
*
|
||||||
|
* @note This API should only be used internally by the modem-netif layer
|
||||||
|
*
|
||||||
|
* @param dte ESP Modem DTE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_notify_ppp_netif_closed(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify the modem, that all the modem units (DTE, DCE, PPP) has
|
||||||
|
* been properly initialized and DTE loop can safely start
|
||||||
|
*
|
||||||
|
* @param dte ESP Modem DTE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_notify_initialized(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure runtime parameters for the DTE. Currently supports only the baud rate to be set
|
||||||
|
*
|
||||||
|
* @param dte ESP Modem DTE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dte_set_params(esp_modem_dte_t *dte, const esp_modem_dte_config_t *config);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -17,6 +17,21 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief modem netif adapter type
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_netif_driver_s esp_modem_netif_driver_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ESP_MODEM_NETIF Modem netif adapter API
|
||||||
|
* @brief network interface adapter for esp-modem
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup ESP_MODEM_NETIF
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates handle to esp_modem used as an esp-netif driver
|
* @brief Creates handle to esp_modem used as an esp-netif driver
|
||||||
*
|
*
|
||||||
@ -24,21 +39,22 @@ extern "C" {
|
|||||||
*
|
*
|
||||||
* @return opaque pointer to esp-modem IO driver used to attach to esp-netif
|
* @return opaque pointer to esp-modem IO driver used to attach to esp-netif
|
||||||
*/
|
*/
|
||||||
void *esp_modem_netif_setup(modem_dte_t *dte);
|
esp_modem_netif_driver_t *esp_modem_netif_new(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroys the esp-netif driver handle
|
* @brief Destroys the esp-netif driver handle as well as the internal netif
|
||||||
|
* object attached to it
|
||||||
*
|
*
|
||||||
* @param h pointer to the esp-netif adapter for esp-modem
|
* @param h pointer to the esp-netif adapter for esp-modem
|
||||||
*/
|
*/
|
||||||
void esp_modem_netif_teardown(void *h);
|
void esp_modem_netif_destroy(esp_modem_netif_driver_t *h);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clears default handlers for esp-modem lifecycle
|
* @brief Clears default handlers for esp-modem lifecycle
|
||||||
*
|
*
|
||||||
* @param h pointer to the esp-netif adapter for esp-modem
|
* @param h pointer to the esp-netif adapter for esp-modem
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_netif_clear_default_handlers(void *h);
|
esp_err_t esp_modem_netif_clear_default_handlers(esp_modem_netif_driver_t *h);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Setups default handlers for esp-modem lifecycle
|
* @brief Setups default handlers for esp-modem lifecycle
|
||||||
@ -46,7 +62,41 @@ esp_err_t esp_modem_netif_clear_default_handlers(void *h);
|
|||||||
* @param h pointer to the esp-netif adapter for esp-modem
|
* @param h pointer to the esp-netif adapter for esp-modem
|
||||||
* @param esp_netif pointer corresponding esp-netif instance
|
* @param esp_netif pointer corresponding esp-netif instance
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_netif_set_default_handlers(void *h, esp_netif_t * esp_netif);
|
esp_err_t esp_modem_netif_set_default_handlers(esp_modem_netif_driver_t *h, esp_netif_t * esp_netif);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ESP_MODEM_NETIF_LEGACY Modem netif adapter legacy API
|
||||||
|
* @brief Legacy API for modem netif
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup ESP_MODEM_NETIF_LEGACY
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroys the esp-netif driver handle the same way
|
||||||
|
* as esp_modem_netif_destroy()
|
||||||
|
*
|
||||||
|
* @note This API is only provided for legacy API
|
||||||
|
*/
|
||||||
|
void esp_modem_netif_teardown(esp_modem_netif_driver_t *h);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The same as `esp_modem_netif_new()`, but autostarts the netif
|
||||||
|
* on esp_netif_attach().
|
||||||
|
*
|
||||||
|
* @note This API is only provided for legacy API
|
||||||
|
*/
|
||||||
|
esp_modem_netif_driver_t *esp_modem_netif_setup(esp_modem_dte_t *dte);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
89
esp_modem/include/esp_modem_recov_helper.h
Normal file
89
esp_modem/include/esp_modem_recov_helper.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility macro to define a retry method
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define DEFINE_RETRY_CMD(name, retry, super_type) \
|
||||||
|
esp_err_t name(esp_modem_dce_t *dce, void *param, void *result) \
|
||||||
|
{ \
|
||||||
|
super_type *super = __containerof(dce, super_type, parent); \
|
||||||
|
return super->retry->run(super->retry, param, result); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO helper object used to pull modem IOs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_gpio_s {
|
||||||
|
int gpio_num;
|
||||||
|
int inactive_level;
|
||||||
|
int active_width_ms;
|
||||||
|
int inactive_width_ms;
|
||||||
|
void (*pulse)(struct esp_modem_gpio_s *pin);
|
||||||
|
void (*pulse_special)(struct esp_modem_gpio_s *pin, int active_width_ms, int inactive_width_ms);
|
||||||
|
void (*destroy)(struct esp_modem_gpio_s *pin);
|
||||||
|
} esp_modem_recov_gpio_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recovery helper object used to resend commands if failed or timeouted
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct esp_modem_retry_s esp_modem_recov_resend_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User recovery function to be called upon modem command failed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef esp_err_t (*esp_modem_retry_fn_t)(esp_modem_recov_resend_t *retry_cmd, esp_err_t current_err, int timeouts, int errors);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recovery helper object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct esp_modem_retry_s {
|
||||||
|
const char *command;
|
||||||
|
esp_err_t (*run)(struct esp_modem_retry_s *retry, void *param, void *result);
|
||||||
|
dce_command_t orig_cmd;
|
||||||
|
esp_modem_retry_fn_t recover;
|
||||||
|
esp_modem_dce_t *dce;
|
||||||
|
int retries_after_timeout; //!< Retry strategy: numbers of resending the same command on timeout
|
||||||
|
int retries_after_error; //!< Retry strategy: numbers of resending the same command on error
|
||||||
|
void (*destroy)(struct esp_modem_retry_s *this_recov);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new resend object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
esp_modem_recov_resend_t *esp_modem_recov_resend_new(esp_modem_dce_t *dce, dce_command_t orig_cmd, esp_modem_retry_fn_t recover, int max_timeouts, int max_errors);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new gpio object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
esp_modem_recov_gpio_t *esp_modem_recov_gpio_new(int gpio_num, int inactive_level, int active_width_ms, int inactive_width_ms);
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -13,21 +13,4 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include "esp_modem_compat.h"
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "esp_modem_dce_service.h"
|
|
||||||
#include "esp_modem.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create and initialize BG96 object
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @return modem_dce_t* Modem DCE object
|
|
||||||
*/
|
|
||||||
modem_dce_t *bg96_init(modem_dte_t *dte);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
71
esp_modem/include_compat/esp_modem_compat.h
Normal file
71
esp_modem/include_compat/esp_modem_compat.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "esp_modem.h"
|
||||||
|
#include "esp_modem_dte.h"
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specific Length Constraint
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define MODEM_MAX_NAME_LENGTH (32) /*!< Max Module Name Length */
|
||||||
|
#define MODEM_MAX_OPERATOR_LENGTH (32) /*!< Max Operator Name Length */
|
||||||
|
#define MODEM_IMEI_LENGTH (15) /*!< IMEI Number Length */
|
||||||
|
#define MODEM_IMSI_LENGTH (15) /*!< IMSI Number Length */
|
||||||
|
|
||||||
|
#define esp_modem_dte_init esp_modem_dte_new
|
||||||
|
|
||||||
|
typedef esp_modem_dte_t modem_dte_t;
|
||||||
|
|
||||||
|
typedef struct modem_dce modem_dce_t;
|
||||||
|
|
||||||
|
struct modem_dce {
|
||||||
|
char imei[MODEM_IMEI_LENGTH + 1]; /*!< IMEI number */
|
||||||
|
char imsi[MODEM_IMSI_LENGTH + 1]; /*!< IMSI number */
|
||||||
|
char name[MODEM_MAX_NAME_LENGTH]; /*!< Module name */
|
||||||
|
char oper[MODEM_MAX_OPERATOR_LENGTH]; /*!< Operator name */
|
||||||
|
esp_modem_state_t state; /*!< Modem working state */
|
||||||
|
esp_modem_mode_t mode; /*!< Working mode */
|
||||||
|
modem_dte_t *dte; /*!< DTE which connect to DCE */
|
||||||
|
esp_err_t (*handle_line)(modem_dce_t *dce, const char *line); /*!< Handle line strategy */
|
||||||
|
esp_err_t (*sync)(modem_dce_t *dce); /*!< Synchronization */
|
||||||
|
esp_err_t (*echo_mode)(modem_dce_t *dce, bool on); /*!< Echo command on or off */
|
||||||
|
esp_err_t (*store_profile)(modem_dce_t *dce); /*!< Store user settings */
|
||||||
|
esp_err_t (*set_flow_ctrl)(modem_dce_t *dce, esp_modem_flow_ctrl_t flow_ctrl); /*!< Flow control on or off */
|
||||||
|
esp_err_t (*get_signal_quality)(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber); /*!< Get signal quality */
|
||||||
|
esp_err_t (*get_battery_status)(modem_dce_t *dce, uint32_t *bcs,
|
||||||
|
uint32_t *bcl, uint32_t *voltage); /*!< Get battery status */
|
||||||
|
esp_err_t (*define_pdp_context)(modem_dce_t *dce, uint32_t cid,
|
||||||
|
const char *type, const char *apn); /*!< Set PDP Contex */
|
||||||
|
esp_err_t (*set_working_mode)(modem_dce_t *dce, esp_modem_mode_t mode); /*!< Set working mode */
|
||||||
|
esp_err_t (*hang_up)(modem_dce_t *dce); /*!< Hang up */
|
||||||
|
esp_err_t (*power_down)(modem_dce_t *dce); /*!< Normal power down */
|
||||||
|
esp_err_t (*deinit)(modem_dce_t *dce); /*!< Deinitialize */
|
||||||
|
esp_modem_dce_t parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
modem_dce_t *sim800_init(modem_dte_t *dte);
|
||||||
|
modem_dce_t *sim7600_init(modem_dte_t *dte);
|
||||||
|
modem_dce_t *bg96_init(modem_dte_t *dte);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -13,21 +13,4 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include "esp_modem_compat.h"
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "esp_modem_dce_service.h"
|
|
||||||
#include "esp_modem.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create and initialize SIM7600 object
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @return modem_dce_t* Modem DCE object
|
|
||||||
*/
|
|
||||||
modem_dce_t *sim7600_init(modem_dte_t *dte);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -13,21 +13,4 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include "esp_modem_compat.h"
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "esp_modem_dce_service.h"
|
|
||||||
#include "esp_modem.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create and initialize SIM800 object
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @return modem_dce_t* Modem DCE object
|
|
||||||
*/
|
|
||||||
modem_dce_t *sim800_init(modem_dte_t *dte);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
62
esp_modem/private_include/esp_modem_dce_command_lib.h
Normal file
62
esp_modem/private_include/esp_modem_dce_command_lib.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
#include "esp_modem.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finds the command par its symbolic name
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param command Symbolic name of the command
|
||||||
|
*
|
||||||
|
* @return Function pointer to the
|
||||||
|
*/
|
||||||
|
dce_command_t esp_modem_dce_find_command(esp_modem_dce_t *dce, const char *command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete specific command from the list
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param command Symbolic name of the command to delete
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_delete_command(esp_modem_dce_t *dce, const char *command_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deletes all commands in the list
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_delete_all_commands(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates internal structure for holding the command list
|
||||||
|
*
|
||||||
|
* @return Pointer to the command list struct on success, NULL otherwise
|
||||||
|
*/
|
||||||
|
struct esp_modem_dce_cmd_list *esp_modem_command_list_create(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
51
esp_modem/private_include/esp_modem_device_specific_dce.h
Normal file
51
esp_modem/private_include/esp_modem_device_specific_dce.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "esp_modem.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specific init of SIM800 device
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_sim800_specific_init(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specific init of SIM7600 device
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_sim7600_specific_init(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specific init of BG96 device
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_bg96_specific_init(esp_modem_dce_t *dce);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
57
esp_modem/private_include/esp_modem_dte_internal.h
Normal file
57
esp_modem/private_include/esp_modem_dte_internal.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_modem.h"
|
||||||
|
#include "esp_modem_dte.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main lifecycle states of the esp-modem
|
||||||
|
*
|
||||||
|
* The bits below are used to indicate events in process_group
|
||||||
|
* field of the esp_modem_dte_internal_t
|
||||||
|
*/
|
||||||
|
#define ESP_MODEM_START_BIT BIT0
|
||||||
|
#define ESP_MODEM_COMMAND_BIT BIT1
|
||||||
|
#define ESP_MODEM_STOP_PPP_BIT BIT2
|
||||||
|
#define ESP_MODEM_STOP_BIT BIT3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ESP32 Modem DTE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uart_port_t uart_port; /*!< UART port */
|
||||||
|
uint8_t *buffer; /*!< Internal buffer to store response lines/data from DCE */
|
||||||
|
QueueHandle_t event_queue; /*!< UART event queue handle */
|
||||||
|
esp_event_loop_handle_t event_loop_hdl; /*!< Event loop handle */
|
||||||
|
TaskHandle_t uart_event_task_hdl; /*!< UART event task handle */
|
||||||
|
EventGroupHandle_t process_group; /*!< Event group used for indicating DTE state changes */
|
||||||
|
esp_modem_dte_t parent; /*!< DTE interface that should extend */
|
||||||
|
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 */
|
||||||
|
} esp_modem_dte_internal_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -13,25 +13,36 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_modem.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Macro defined for error checking
|
* @brief Macro defined for error checking
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define DCE_CHECK(a, str, goto_tag, ...) \
|
#define ESP_MODEM_ERR_CHECK(a, str, goto_tag, ...) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
if (!(a)) \
|
if (!(a)) \
|
||||||
{ \
|
{ \
|
||||||
ESP_LOGE(DCE_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
goto goto_tag; \
|
goto goto_tag; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief BG96 Modem
|
* @brief common modem delay function
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
static inline void esp_modem_wait_ms(size_t time)
|
||||||
void *priv_resource; /*!< Private resource */
|
{
|
||||||
modem_dce_t parent; /*!< DCE parent class */
|
vTaskDelay(pdMS_TO_TICKS(time));
|
||||||
} bg96_modem_dce_t;
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,472 +0,0 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "bg96.h"
|
|
||||||
#include "bg96_private.h"
|
|
||||||
|
|
||||||
#define MODEM_RESULT_CODE_POWERDOWN "POWERED DOWN"
|
|
||||||
|
|
||||||
static const char *DCE_TAG = "bg96";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CSQ
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_csq(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
|
|
||||||
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, "+CSQ", strlen("+CSQ"))) {
|
|
||||||
/* store value of rssi and ber */
|
|
||||||
uint32_t **csq = bg96_dce->priv_resource;
|
|
||||||
/* +CSQ: <rssi>,<ber> */
|
|
||||||
sscanf(line, "%*s%d,%d", csq[0], csq[1]);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CBC
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_cbc(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
|
|
||||||
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, "+CBC", strlen("+CBC"))) {
|
|
||||||
/* store value of bcs, bcl, voltage */
|
|
||||||
uint32_t **cbc = bg96_dce->priv_resource;
|
|
||||||
/* +CBC: <bcs>,<bcl>,<voltage> */
|
|
||||||
sscanf(line, "%*s%d,%d,%d", cbc[0], cbc[1], cbc[2]);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from +++
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_exit_data_mode(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_NO_CARRIER)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from ATD*99#
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_atd_ppp(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
if (strstr(line, MODEM_RESULT_CODE_CONNECT)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CGMM
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_cgmm(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 {
|
|
||||||
int len = snprintf(dce->name, MODEM_MAX_NAME_LENGTH, "%s", line);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->name, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CGSN
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_cgsn(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 {
|
|
||||||
int len = snprintf(dce->imei, MODEM_IMEI_LENGTH + 1, "%s", line);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->imei, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CIMI
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_cimi(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 {
|
|
||||||
int len = snprintf(dce->imsi, MODEM_IMSI_LENGTH + 1, "%s", line);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->imsi, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+COPS?
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_cops(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, "+COPS", strlen("+COPS"))) {
|
|
||||||
/* there might be some random spaces in operator's name, we can not use sscanf to parse the result */
|
|
||||||
/* strtok will break the string, we need to create a copy */
|
|
||||||
size_t len = strlen(line);
|
|
||||||
char *line_copy = malloc(len + 1);
|
|
||||||
strcpy(line_copy, line);
|
|
||||||
/* +COPS: <mode>[, <format>[, <oper>]] */
|
|
||||||
char *str_ptr = NULL;
|
|
||||||
char *p[3];
|
|
||||||
uint8_t i = 0;
|
|
||||||
/* strtok will broke string by replacing delimiter with '\0' */
|
|
||||||
p[i] = strtok_r(line_copy, ",", &str_ptr);
|
|
||||||
while (p[i]) {
|
|
||||||
p[++i] = strtok_r(NULL, ",", &str_ptr);
|
|
||||||
}
|
|
||||||
if (i >= 3) {
|
|
||||||
int len = snprintf(dce->oper, MODEM_MAX_OPERATOR_LENGTH, "%s", p[2]);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->oper, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(line_copy);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+QPOWD=1
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_handle_power_down(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
|
|
||||||
err = ESP_OK;
|
|
||||||
} else if (strstr(line, MODEM_RESULT_CODE_POWERDOWN)) {
|
|
||||||
err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get signal quality
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param rssi received signal strength indication
|
|
||||||
* @param ber bit error ratio
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_get_signal_quality(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
|
|
||||||
uint32_t *resource[2] = {rssi, ber};
|
|
||||||
bg96_dce->priv_resource = resource;
|
|
||||||
dce->handle_line = bg96_handle_csq;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CSQ\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire signal quality failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "inquire signal quality ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get battery status
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param bcs Battery charge status
|
|
||||||
* @param bcl Battery connection level
|
|
||||||
* @param voltage Battery voltage
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_get_battery_status(modem_dce_t *dce, uint32_t *bcs, uint32_t *bcl, uint32_t *voltage)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
|
|
||||||
uint32_t *resource[3] = {bcs, bcl, voltage};
|
|
||||||
bg96_dce->priv_resource = resource;
|
|
||||||
dce->handle_line = bg96_handle_cbc;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CBC\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire battery status failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "inquire battery status ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set Working Mode
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param mode woking mode
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_set_working_mode(modem_dce_t *dce, modem_mode_t mode)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
switch (mode) {
|
|
||||||
case MODEM_COMMAND_MODE:
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000)); // spec: 1s delay for the modem to recognize the escape sequence
|
|
||||||
dce->handle_line = bg96_handle_exit_data_mode;
|
|
||||||
if (dte->send_cmd(dte, "+++", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) != ESP_OK) {
|
|
||||||
// "+++" Could fail if we are already in the command mode.
|
|
||||||
// in that case we ignore the timout and re-sync the modem
|
|
||||||
ESP_LOGI(DCE_TAG, "Sending \"+++\" command failed");
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "sync failed", err);
|
|
||||||
} else {
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter command mode failed", err);
|
|
||||||
}
|
|
||||||
ESP_LOGD(DCE_TAG, "enter command mode ok");
|
|
||||||
dce->mode = MODEM_COMMAND_MODE;
|
|
||||||
break;
|
|
||||||
case MODEM_PPP_MODE:
|
|
||||||
dce->handle_line = bg96_handle_atd_ppp;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "ATD*99***1#\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
|
|
||||||
if (dce->state != MODEM_STATE_SUCCESS) {
|
|
||||||
// Initiate PPP mode could fail, if we've already "dialed" the data call before.
|
|
||||||
// in that case we retry with "ATO" to just resume the data mode
|
|
||||||
ESP_LOGD(DCE_TAG, "enter ppp mode failed, retry with ATO");
|
|
||||||
dce->handle_line = bg96_handle_atd_ppp;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "ATO\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter ppp mode failed", err);
|
|
||||||
}
|
|
||||||
ESP_LOGD(DCE_TAG, "enter ppp mode ok");
|
|
||||||
dce->mode = MODEM_PPP_MODE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGW(DCE_TAG, "unsupported working mode: %d", mode);
|
|
||||||
goto err;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Power down
|
|
||||||
*
|
|
||||||
* @param bg96_dce bg96 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_power_down(modem_dce_t *dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
dce->handle_line = bg96_handle_power_down;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+QPOWD=1\r", MODEM_COMMAND_TIMEOUT_POWEROFF) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "power down failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "power down ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get DCE module name
|
|
||||||
*
|
|
||||||
* @param bg96_dce bg96 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_get_module_name(bg96_modem_dce_t *bg96_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = bg96_dce->parent.dte;
|
|
||||||
bg96_dce->parent.handle_line = bg96_handle_cgmm;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CGMM\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(bg96_dce->parent.state == MODEM_STATE_SUCCESS, "get module name failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get module name ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get DCE module IMEI number
|
|
||||||
*
|
|
||||||
* @param bg96_dce bg96 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_get_imei_number(bg96_modem_dce_t *bg96_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = bg96_dce->parent.dte;
|
|
||||||
bg96_dce->parent.handle_line = bg96_handle_cgsn;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CGSN\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(bg96_dce->parent.state == MODEM_STATE_SUCCESS, "get imei number failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get imei number ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get DCE module IMSI number
|
|
||||||
*
|
|
||||||
* @param bg96_dce bg96 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_get_imsi_number(bg96_modem_dce_t *bg96_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = bg96_dce->parent.dte;
|
|
||||||
bg96_dce->parent.handle_line = bg96_handle_cimi;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CIMI\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(bg96_dce->parent.state == MODEM_STATE_SUCCESS, "get imsi number failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get imsi number ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get Operator's name
|
|
||||||
*
|
|
||||||
* @param bg96_dce bg96 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_get_operator_name(bg96_modem_dce_t *bg96_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = bg96_dce->parent.dte;
|
|
||||||
bg96_dce->parent.handle_line = bg96_handle_cops;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+COPS?\r", MODEM_COMMAND_TIMEOUT_OPERATOR) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(bg96_dce->parent.state == MODEM_STATE_SUCCESS, "get network operator failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get network operator ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Deinitialize BG96 object
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on fail
|
|
||||||
*/
|
|
||||||
static esp_err_t bg96_deinit(modem_dce_t *dce)
|
|
||||||
{
|
|
||||||
bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
|
|
||||||
if (dce->dte) {
|
|
||||||
dce->dte->dce = NULL;
|
|
||||||
}
|
|
||||||
free(bg96_dce);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
modem_dce_t *bg96_init(modem_dte_t *dte)
|
|
||||||
{
|
|
||||||
DCE_CHECK(dte, "DCE should bind with a DTE", err);
|
|
||||||
/* malloc memory for bg96_dce object */
|
|
||||||
bg96_modem_dce_t *bg96_dce = calloc(1, sizeof(bg96_modem_dce_t));
|
|
||||||
DCE_CHECK(bg96_dce, "calloc bg96_dce failed", err);
|
|
||||||
/* Bind DTE with DCE */
|
|
||||||
bg96_dce->parent.dte = dte;
|
|
||||||
dte->dce = &(bg96_dce->parent);
|
|
||||||
/* Bind methods */
|
|
||||||
bg96_dce->parent.handle_line = NULL;
|
|
||||||
bg96_dce->parent.sync = esp_modem_dce_sync;
|
|
||||||
bg96_dce->parent.echo_mode = esp_modem_dce_echo;
|
|
||||||
bg96_dce->parent.store_profile = esp_modem_dce_store_profile;
|
|
||||||
bg96_dce->parent.set_flow_ctrl = esp_modem_dce_set_flow_ctrl;
|
|
||||||
bg96_dce->parent.define_pdp_context = esp_modem_dce_define_pdp_context;
|
|
||||||
bg96_dce->parent.hang_up = esp_modem_dce_hang_up;
|
|
||||||
bg96_dce->parent.get_signal_quality = bg96_get_signal_quality;
|
|
||||||
bg96_dce->parent.get_battery_status = bg96_get_battery_status;
|
|
||||||
bg96_dce->parent.set_working_mode = bg96_set_working_mode;
|
|
||||||
bg96_dce->parent.power_down = bg96_power_down;
|
|
||||||
bg96_dce->parent.deinit = bg96_deinit;
|
|
||||||
/* Sync between DTE and DCE */
|
|
||||||
DCE_CHECK(esp_modem_dce_sync(&(bg96_dce->parent)) == ESP_OK, "sync failed", err_io);
|
|
||||||
/* Close echo */
|
|
||||||
DCE_CHECK(esp_modem_dce_echo(&(bg96_dce->parent), false) == ESP_OK, "close echo mode failed", err_io);
|
|
||||||
/* Get Module name */
|
|
||||||
DCE_CHECK(bg96_get_module_name(bg96_dce) == ESP_OK, "get module name failed", err_io);
|
|
||||||
/* Get IMEI number */
|
|
||||||
DCE_CHECK(bg96_get_imei_number(bg96_dce) == ESP_OK, "get imei failed", err_io);
|
|
||||||
/* Get IMSI number */
|
|
||||||
DCE_CHECK(bg96_get_imsi_number(bg96_dce) == ESP_OK, "get imsi failed", err_io);
|
|
||||||
/* Get operator name */
|
|
||||||
DCE_CHECK(bg96_get_operator_name(bg96_dce) == ESP_OK, "get operator name failed", err_io);
|
|
||||||
return &(bg96_dce->parent);
|
|
||||||
err_io:
|
|
||||||
free(bg96_dce);
|
|
||||||
err:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
25
esp_modem/src/esp_bg96.c
Normal file
25
esp_modem/src/esp_bg96.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
|
||||||
|
static const char *TAG = "bg96";
|
||||||
|
|
||||||
|
esp_err_t esp_modem_bg96_specific_init(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "failed to specific init with zero dce", err_params);
|
||||||
|
// BG96 specifics is the same as the default DCE, as of now
|
||||||
|
return ESP_OK;
|
||||||
|
err_params:
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
@ -12,524 +12,41 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "esp_modem.h"
|
#include "esp_modem.h"
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
#include "esp_modem_dte_internal.h"
|
||||||
|
#include "esp_modem_device_specific_dce.h"
|
||||||
|
#include "esp_modem_netif.h"
|
||||||
|
|
||||||
#define ESP_MODEM_EVENT_QUEUE_SIZE (16)
|
static const char *TAG = "esp-modem";
|
||||||
|
|
||||||
#define MIN_PATTERN_INTERVAL (9)
|
|
||||||
#define MIN_POST_IDLE (0)
|
|
||||||
#define MIN_PRE_IDLE (0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Macro defined for error checking
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static const char *MODEM_TAG = "esp-modem";
|
|
||||||
#define MODEM_CHECK(a, str, goto_tag, ...) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (!(a)) \
|
|
||||||
{ \
|
|
||||||
ESP_LOGE(MODEM_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
|
||||||
goto goto_tag; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
ESP_EVENT_DEFINE_BASE(ESP_MODEM_EVENT);
|
ESP_EVENT_DEFINE_BASE(ESP_MODEM_EVENT);
|
||||||
|
|
||||||
/**
|
esp_err_t esp_modem_set_event_handler(esp_modem_dte_t *dte, esp_event_handler_t handler, int32_t event_id, void *handler_args)
|
||||||
* @brief ESP32 Modem DTE
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
uart_port_t uart_port; /*!< UART port */
|
|
||||||
uint8_t *buffer; /*!< Internal buffer to store response lines/data from DCE */
|
|
||||||
QueueHandle_t event_queue; /*!< UART event queue handle */
|
|
||||||
esp_event_loop_handle_t event_loop_hdl; /*!< Event loop handle */
|
|
||||||
TaskHandle_t uart_event_task_hdl; /*!< UART event task handle */
|
|
||||||
SemaphoreHandle_t process_sem; /*!< Semaphore used for indicating processing status */
|
|
||||||
SemaphoreHandle_t exit_sem; /*!< Semaphore used for indicating PPP mode has stopped */
|
|
||||||
modem_dte_t parent; /*!< DTE interface that should extend */
|
|
||||||
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 commnad mode */
|
|
||||||
int pattern_queue_size; /*!< UART pattern queue size */
|
|
||||||
} esp_modem_dte_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns true if the supplied string contains only CR or LF
|
|
||||||
*
|
|
||||||
* @param str string to check
|
|
||||||
* @param len length of string
|
|
||||||
*/
|
|
||||||
static inline bool is_only_cr_lf(const char *str, uint32_t len)
|
|
||||||
{
|
{
|
||||||
for (int i=0; i<len; ++i) {
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
if (str[i] != '\r' && str[i] != '\n') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_set_rx_cb(modem_dte_t *dte, esp_modem_on_receive receive_cb, void *receive_cb_ctx)
|
|
||||||
{
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
esp_dte->receive_cb_ctx = receive_cb_ctx;
|
|
||||||
esp_dte->receive_cb = receive_cb;
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle one line in DTE
|
|
||||||
*
|
|
||||||
* @param esp_dte ESP modem DTE object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t esp_dte_handle_line(esp_modem_dte_t *esp_dte)
|
|
||||||
{
|
|
||||||
modem_dce_t *dce = esp_dte->parent.dce;
|
|
||||||
MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
|
|
||||||
const char *line = (const char *)(esp_dte->buffer);
|
|
||||||
size_t len = strlen(line);
|
|
||||||
/* Skip pure "\r\n" lines */
|
|
||||||
if (len > 2 && !is_only_cr_lf(line, len)) {
|
|
||||||
MODEM_CHECK(dce->handle_line, "no handler for line", err_handle);
|
|
||||||
MODEM_CHECK(dce->handle_line(dce, line) == ESP_OK, "handle line failed", err_handle);
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
err_handle:
|
|
||||||
/* Send ESP_MODEM_EVENT_UNKNOWN signal to event loop */
|
|
||||||
esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_UNKNOWN,
|
|
||||||
(void *)line, strlen(line) + 1, pdMS_TO_TICKS(100));
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle when a pattern has been detected by UART
|
|
||||||
*
|
|
||||||
* @param esp_dte ESP32 Modem DTE object
|
|
||||||
*/
|
|
||||||
static void esp_handle_uart_pattern(esp_modem_dte_t *esp_dte)
|
|
||||||
{
|
|
||||||
int pos = uart_pattern_pop_pos(esp_dte->uart_port);
|
|
||||||
int read_len = 0;
|
|
||||||
if (pos != -1) {
|
|
||||||
if (pos < esp_dte->line_buffer_size - 1) {
|
|
||||||
/* read one line(include '\n') */
|
|
||||||
read_len = pos + 1;
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(MODEM_TAG, "ESP Modem Line buffer too small");
|
|
||||||
read_len = esp_dte->line_buffer_size - 1;
|
|
||||||
}
|
|
||||||
read_len = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, read_len, pdMS_TO_TICKS(100));
|
|
||||||
if (read_len) {
|
|
||||||
/* make sure the line is a standard string */
|
|
||||||
esp_dte->buffer[read_len] = '\0';
|
|
||||||
/* Send new line to handle */
|
|
||||||
esp_dte_handle_line(esp_dte);
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(MODEM_TAG, "uart read bytes failed");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
size_t length = 0;
|
|
||||||
uart_get_buffered_data_len(esp_dte->uart_port, &length);
|
|
||||||
ESP_LOGW(MODEM_TAG, "Pattern not found in the pattern queue, uart data length = %d", length);
|
|
||||||
length = MIN(esp_dte->line_buffer_size-1, length);
|
|
||||||
length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
|
|
||||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG);
|
|
||||||
uart_flush(esp_dte->uart_port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle when new data received by UART
|
|
||||||
*
|
|
||||||
* @param esp_dte ESP32 Modem DTE object
|
|
||||||
*/
|
|
||||||
static void esp_handle_uart_data(esp_modem_dte_t *esp_dte)
|
|
||||||
{
|
|
||||||
size_t length = 0;
|
|
||||||
uart_get_buffered_data_len(esp_dte->uart_port, &length);
|
|
||||||
if (esp_dte->parent.dce->mode != MODEM_PPP_MODE) {
|
|
||||||
// Check if matches the pattern to process the data as pattern
|
|
||||||
int pos = uart_pattern_pop_pos(esp_dte->uart_port);
|
|
||||||
if (pos > -1) {
|
|
||||||
esp_handle_uart_pattern(esp_dte);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Read the data and process it using `handle_line` logic
|
|
||||||
length = MIN(esp_dte->line_buffer_size-1, length);
|
|
||||||
length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
|
|
||||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG);
|
|
||||||
esp_dte->buffer[length] = '\0';
|
|
||||||
if (esp_dte->parent.dce->handle_line) {
|
|
||||||
/* Send new line to handle if handler registered */
|
|
||||||
esp_dte_handle_line(esp_dte);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
length = MIN(esp_dte->line_buffer_size, length);
|
|
||||||
length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
|
|
||||||
/* pass the input data to configured callback */
|
|
||||||
if (length) {
|
|
||||||
esp_dte->receive_cb(esp_dte->buffer, length, esp_dte->receive_cb_ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief UART Event Task Entry
|
|
||||||
*
|
|
||||||
* @param param task parameter
|
|
||||||
*/
|
|
||||||
static void uart_event_task_entry(void *param)
|
|
||||||
{
|
|
||||||
esp_modem_dte_t *esp_dte = (esp_modem_dte_t *)param;
|
|
||||||
uart_event_t event;
|
|
||||||
while (1) {
|
|
||||||
if (xQueueReceive(esp_dte->event_queue, &event, pdMS_TO_TICKS(100))) {
|
|
||||||
switch (event.type) {
|
|
||||||
case UART_DATA:
|
|
||||||
esp_handle_uart_data(esp_dte);
|
|
||||||
break;
|
|
||||||
case UART_FIFO_OVF:
|
|
||||||
ESP_LOGW(MODEM_TAG, "HW FIFO Overflow");
|
|
||||||
uart_flush_input(esp_dte->uart_port);
|
|
||||||
xQueueReset(esp_dte->event_queue);
|
|
||||||
break;
|
|
||||||
case UART_BUFFER_FULL:
|
|
||||||
ESP_LOGW(MODEM_TAG, "Ring Buffer Full");
|
|
||||||
uart_flush_input(esp_dte->uart_port);
|
|
||||||
xQueueReset(esp_dte->event_queue);
|
|
||||||
break;
|
|
||||||
case UART_BREAK:
|
|
||||||
ESP_LOGW(MODEM_TAG, "Rx Break");
|
|
||||||
break;
|
|
||||||
case UART_PARITY_ERR:
|
|
||||||
ESP_LOGE(MODEM_TAG, "Parity Error");
|
|
||||||
break;
|
|
||||||
case UART_FRAME_ERR:
|
|
||||||
ESP_LOGE(MODEM_TAG, "Frame Error");
|
|
||||||
break;
|
|
||||||
case UART_PATTERN_DET:
|
|
||||||
esp_handle_uart_pattern(esp_dte);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGW(MODEM_TAG, "unknown uart event type: %d", event.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Drive the event loop */
|
|
||||||
esp_event_loop_run(esp_dte->event_loop_hdl, pdMS_TO_TICKS(50));
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Send command to DCE
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @param command command string
|
|
||||||
* @param timeout timeout value, unit: ms
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t esp_modem_dte_send_cmd(modem_dte_t *dte, const char *command, uint32_t timeout)
|
|
||||||
{
|
|
||||||
esp_err_t ret = ESP_FAIL;
|
|
||||||
modem_dce_t *dce = dte->dce;
|
|
||||||
MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
|
|
||||||
MODEM_CHECK(command, "command is NULL", err);
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
/* Calculate timeout clock tick */
|
|
||||||
/* Reset runtime information */
|
|
||||||
dce->state = MODEM_STATE_PROCESSING;
|
|
||||||
/* Send command via UART */
|
|
||||||
uart_write_bytes(esp_dte->uart_port, command, strlen(command));
|
|
||||||
/* Check timeout */
|
|
||||||
MODEM_CHECK(xSemaphoreTake(esp_dte->process_sem, pdMS_TO_TICKS(timeout)) == pdTRUE, "process command timeout", err);
|
|
||||||
ret = ESP_OK;
|
|
||||||
err:
|
|
||||||
dce->handle_line = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Send data to DCE
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @param data data buffer
|
|
||||||
* @param length length of data to send
|
|
||||||
* @return int actual length of data that has been send out
|
|
||||||
*/
|
|
||||||
static int esp_modem_dte_send_data(modem_dte_t *dte, const char *data, uint32_t length)
|
|
||||||
{
|
|
||||||
MODEM_CHECK(data, "data is NULL", err);
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
if (esp_dte->parent.dce->mode == MODEM_TRANSITION_MODE) {
|
|
||||||
ESP_LOGD(MODEM_TAG, "Not sending data in transition mode");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return uart_write_bytes(esp_dte->uart_port, data, length);
|
|
||||||
err:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Send data and wait for prompt from DCE
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @param data data buffer
|
|
||||||
* @param length length of data to send
|
|
||||||
* @param prompt pointer of specific prompt
|
|
||||||
* @param timeout timeout value (unit: ms)
|
|
||||||
* @return esp_err_t
|
|
||||||
* ESP_OK on success
|
|
||||||
* ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t esp_modem_dte_send_wait(modem_dte_t *dte, const char *data, uint32_t length,
|
|
||||||
const char *prompt, uint32_t timeout)
|
|
||||||
{
|
|
||||||
MODEM_CHECK(data, "data is NULL", err_param);
|
|
||||||
MODEM_CHECK(prompt, "prompt is NULL", err_param);
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
// We'd better disable pattern detection here for a moment in case prompt string contains the pattern character
|
|
||||||
uart_disable_pattern_det_intr(esp_dte->uart_port);
|
|
||||||
// uart_disable_rx_intr(esp_dte->uart_port);
|
|
||||||
MODEM_CHECK(uart_write_bytes(esp_dte->uart_port, data, length) >= 0, "uart write bytes failed", err_write);
|
|
||||||
uint32_t len = strlen(prompt);
|
|
||||||
uint8_t *buffer = calloc(len + 1, sizeof(uint8_t));
|
|
||||||
int res = uart_read_bytes(esp_dte->uart_port, buffer, len, pdMS_TO_TICKS(timeout));
|
|
||||||
MODEM_CHECK(res >= len, "wait prompt [%s] timeout", err, prompt);
|
|
||||||
MODEM_CHECK(!strncmp(prompt, (const char *)buffer, len), "get wrong prompt: %s", err, buffer);
|
|
||||||
free(buffer);
|
|
||||||
uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
free(buffer);
|
|
||||||
err_write:
|
|
||||||
uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
|
||||||
err_param:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Change Modem's working mode
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @param new_mode new working mode
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t esp_modem_dte_change_mode(modem_dte_t *dte, modem_mode_t new_mode)
|
|
||||||
{
|
|
||||||
modem_dce_t *dce = dte->dce;
|
|
||||||
MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
modem_mode_t current_mode = dce->mode;
|
|
||||||
MODEM_CHECK(current_mode != new_mode, "already in mode: %d", err, new_mode);
|
|
||||||
dce->mode = MODEM_TRANSITION_MODE; // mode switching will be finished in set_working_mode() on success
|
|
||||||
// (or restored on failure)
|
|
||||||
switch (new_mode) {
|
|
||||||
case MODEM_PPP_MODE:
|
|
||||||
MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err_restore_mode, new_mode);
|
|
||||||
uart_disable_pattern_det_intr(esp_dte->uart_port);
|
|
||||||
uart_enable_rx_intr(esp_dte->uart_port);
|
|
||||||
break;
|
|
||||||
case MODEM_COMMAND_MODE:
|
|
||||||
MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err_restore_mode, new_mode);
|
|
||||||
uart_disable_rx_intr(esp_dte->uart_port);
|
|
||||||
uart_flush(esp_dte->uart_port);
|
|
||||||
uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
|
||||||
uart_pattern_queue_reset(esp_dte->uart_port, esp_dte->pattern_queue_size);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
err_restore_mode:
|
|
||||||
dce->mode = current_mode;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t esp_modem_dte_process_cmd_done(modem_dte_t *dte)
|
|
||||||
{
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
return xSemaphoreGive(esp_dte->process_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Deinitialize a Modem DTE object
|
|
||||||
*
|
|
||||||
* @param dte Modem DTE object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t esp_modem_dte_deinit(modem_dte_t *dte)
|
|
||||||
{
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
/* Delete UART event task */
|
|
||||||
vTaskDelete(esp_dte->uart_event_task_hdl);
|
|
||||||
/* Delete semaphores */
|
|
||||||
vSemaphoreDelete(esp_dte->process_sem);
|
|
||||||
vSemaphoreDelete(esp_dte->exit_sem);
|
|
||||||
/* Delete event loop */
|
|
||||||
esp_event_loop_delete(esp_dte->event_loop_hdl);
|
|
||||||
/* Uninstall UART Driver */
|
|
||||||
uart_driver_delete(esp_dte->uart_port);
|
|
||||||
/* Free memory */
|
|
||||||
free(esp_dte->buffer);
|
|
||||||
if (dte->dce) {
|
|
||||||
dte->dce->dte = NULL;
|
|
||||||
}
|
|
||||||
free(esp_dte);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config)
|
|
||||||
{
|
|
||||||
esp_err_t res;
|
|
||||||
/* malloc memory for esp_dte object */
|
|
||||||
esp_modem_dte_t *esp_dte = calloc(1, sizeof(esp_modem_dte_t));
|
|
||||||
MODEM_CHECK(esp_dte, "calloc esp_dte failed", err_dte_mem);
|
|
||||||
/* malloc memory to storing lines from modem dce */
|
|
||||||
esp_dte->line_buffer_size = config->line_buffer_size;
|
|
||||||
esp_dte->buffer = calloc(1, config->line_buffer_size);
|
|
||||||
MODEM_CHECK(esp_dte->buffer, "calloc line memory failed", err_line_mem);
|
|
||||||
/* Set attributes */
|
|
||||||
esp_dte->uart_port = config->port_num;
|
|
||||||
esp_dte->parent.flow_ctrl = config->flow_control;
|
|
||||||
/* Bind methods */
|
|
||||||
esp_dte->parent.send_cmd = esp_modem_dte_send_cmd;
|
|
||||||
esp_dte->parent.send_data = esp_modem_dte_send_data;
|
|
||||||
esp_dte->parent.send_wait = esp_modem_dte_send_wait;
|
|
||||||
esp_dte->parent.change_mode = esp_modem_dte_change_mode;
|
|
||||||
esp_dte->parent.process_cmd_done = esp_modem_dte_process_cmd_done;
|
|
||||||
esp_dte->parent.deinit = esp_modem_dte_deinit;
|
|
||||||
|
|
||||||
/* Config UART */
|
|
||||||
uart_config_t uart_config = {
|
|
||||||
.baud_rate = config->baud_rate,
|
|
||||||
.data_bits = config->data_bits,
|
|
||||||
.parity = config->parity,
|
|
||||||
.stop_bits = config->stop_bits,
|
|
||||||
.source_clk = UART_SCLK_REF_TICK,
|
|
||||||
.flow_ctrl = (config->flow_control == MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE
|
|
||||||
};
|
|
||||||
MODEM_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config);
|
|
||||||
if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
|
|
||||||
res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
|
|
||||||
config->rts_io_num, config->cts_io_num);
|
|
||||||
} else {
|
|
||||||
res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
|
|
||||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
|
||||||
}
|
|
||||||
MODEM_CHECK(res == ESP_OK, "config uart gpio failed", err_uart_config);
|
|
||||||
/* Set flow control threshold */
|
|
||||||
if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
|
|
||||||
res = uart_set_hw_flow_ctrl(esp_dte->uart_port, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
|
|
||||||
} else if (config->flow_control == MODEM_FLOW_CONTROL_SW) {
|
|
||||||
res = uart_set_sw_flow_ctrl(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8);
|
|
||||||
}
|
|
||||||
MODEM_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config);
|
|
||||||
/* Install UART driver and get event queue used inside driver */
|
|
||||||
res = uart_driver_install(esp_dte->uart_port, config->rx_buffer_size, config->tx_buffer_size,
|
|
||||||
config->event_queue_size, &(esp_dte->event_queue), 0);
|
|
||||||
MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config);
|
|
||||||
res = uart_set_rx_timeout(esp_dte->uart_port, 1);
|
|
||||||
MODEM_CHECK(res == ESP_OK, "set rx timeout failed", err_uart_config);
|
|
||||||
|
|
||||||
/* Set pattern interrupt, used to detect the end of a line. */
|
|
||||||
res = uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
|
||||||
/* Set pattern queue size */
|
|
||||||
esp_dte->pattern_queue_size = config->pattern_queue_size;
|
|
||||||
res |= uart_pattern_queue_reset(esp_dte->uart_port, config->pattern_queue_size);
|
|
||||||
/* Starting in command mode -> explicitly disable RX interrupt */
|
|
||||||
uart_disable_rx_intr(esp_dte->uart_port);
|
|
||||||
|
|
||||||
MODEM_CHECK(res == ESP_OK, "config uart pattern failed", err_uart_pattern);
|
|
||||||
/* Create Event loop */
|
|
||||||
esp_event_loop_args_t loop_args = {
|
|
||||||
.queue_size = ESP_MODEM_EVENT_QUEUE_SIZE,
|
|
||||||
.task_name = NULL
|
|
||||||
};
|
|
||||||
MODEM_CHECK(esp_event_loop_create(&loop_args, &esp_dte->event_loop_hdl) == ESP_OK, "create event loop failed", err_eloop);
|
|
||||||
/* Create semaphore */
|
|
||||||
esp_dte->process_sem = xSemaphoreCreateBinary();
|
|
||||||
MODEM_CHECK(esp_dte->process_sem, "create process semaphore failed", err_sem1);
|
|
||||||
esp_dte->exit_sem = xSemaphoreCreateBinary();
|
|
||||||
MODEM_CHECK(esp_dte->exit_sem, "create exit semaphore failed", err_sem);
|
|
||||||
|
|
||||||
/* Create UART Event task */
|
|
||||||
BaseType_t ret = xTaskCreate(uart_event_task_entry, //Task Entry
|
|
||||||
"uart_event", //Task Name
|
|
||||||
config->event_task_stack_size, //Task Stack Size(Bytes)
|
|
||||||
esp_dte, //Task Parameter
|
|
||||||
config->event_task_priority, //Task Priority
|
|
||||||
& (esp_dte->uart_event_task_hdl) //Task Handler
|
|
||||||
);
|
|
||||||
MODEM_CHECK(ret == pdTRUE, "create uart event task failed", err_tsk_create);
|
|
||||||
return &(esp_dte->parent);
|
|
||||||
/* Error handling */
|
|
||||||
err_tsk_create:
|
|
||||||
vSemaphoreDelete(esp_dte->exit_sem);
|
|
||||||
err_sem:
|
|
||||||
vSemaphoreDelete(esp_dte->process_sem);
|
|
||||||
err_sem1:
|
|
||||||
esp_event_loop_delete(esp_dte->event_loop_hdl);
|
|
||||||
err_eloop:
|
|
||||||
uart_disable_pattern_det_intr(esp_dte->uart_port);
|
|
||||||
err_uart_pattern:
|
|
||||||
uart_driver_delete(esp_dte->uart_port);
|
|
||||||
err_uart_config:
|
|
||||||
free(esp_dte->buffer);
|
|
||||||
err_line_mem:
|
|
||||||
free(esp_dte);
|
|
||||||
err_dte_mem:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_set_event_handler(modem_dte_t *dte, esp_event_handler_t handler, int32_t event_id, void *handler_args)
|
|
||||||
{
|
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
|
||||||
return esp_event_handler_register_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, event_id, handler, handler_args);
|
return esp_event_handler_register_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, event_id, handler, handler_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t handler)
|
esp_err_t esp_modem_remove_event_handler(esp_modem_dte_t *dte, esp_event_handler_t handler)
|
||||||
{
|
{
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
return esp_event_handler_unregister_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_EVENT_ANY_ID, handler);
|
return esp_event_handler_unregister_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_EVENT_ANY_ID, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_start_ppp(modem_dte_t *dte)
|
esp_err_t esp_modem_start_ppp(esp_modem_dte_t *dte)
|
||||||
{
|
{
|
||||||
modem_dce_t *dce = dte->dce;
|
esp_modem_dce_t *dce = dte->dce;
|
||||||
MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
|
ESP_MODEM_ERR_CHECK(dce, "DTE has not yet bind with DCE", err);
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
/* Set PDP Context */
|
|
||||||
MODEM_CHECK(dce->define_pdp_context(dce, 1, "IP", CONFIG_EXAMPLE_COMPONENT_MODEM_APN) == ESP_OK, "set MODEM APN failed", err);
|
|
||||||
/* Enter PPP mode */
|
/* Enter PPP mode */
|
||||||
MODEM_CHECK(dte->change_mode(dte, MODEM_PPP_MODE) == ESP_OK, "enter ppp mode failed", err);
|
ESP_MODEM_ERR_CHECK(dte->change_mode(dte, ESP_MODEM_PPP_MODE) == ESP_OK, "enter ppp mode failed", err);
|
||||||
|
|
||||||
/* post PPP mode started event */
|
/* post PPP mode started event */
|
||||||
esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_START, NULL, 0, 0);
|
esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_START, NULL, 0, 0);
|
||||||
@ -538,29 +55,131 @@ err:
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_stop_ppp(modem_dte_t *dte)
|
esp_err_t esp_modem_stop_ppp(esp_modem_dte_t *dte)
|
||||||
{
|
{
|
||||||
modem_dce_t *dce = dte->dce;
|
esp_modem_dce_t *dce = dte->dce;
|
||||||
MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
|
ESP_MODEM_ERR_CHECK(dce, "DTE has not yet bind with DCE", err);
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
|
||||||
/* Enter command mode */
|
/* Enter command mode */
|
||||||
MODEM_CHECK(dte->change_mode(dte, MODEM_COMMAND_MODE) == ESP_OK, "enter command mode failed", err);
|
ESP_MODEM_ERR_CHECK(dte->change_mode(dte, ESP_MODEM_COMMAND_MODE) == ESP_OK, "enter command mode failed", err);
|
||||||
|
|
||||||
/* post PPP mode stopped event */
|
/* post PPP mode stopped event */
|
||||||
esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_STOP, NULL, 0, 0);
|
esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_STOP, NULL, 0, 0);
|
||||||
/* Hang up */
|
|
||||||
MODEM_CHECK(dce->hang_up(dce) == ESP_OK, "hang up failed", err);
|
|
||||||
/* wait for the PPP mode to exit gracefully */
|
/* wait for the PPP mode to exit gracefully */
|
||||||
if (xSemaphoreTake(esp_dte->exit_sem, pdMS_TO_TICKS(20000)) != pdTRUE) {
|
EventBits_t bits = xEventGroupWaitBits(esp_dte->process_group, ESP_MODEM_STOP_PPP_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(20000));
|
||||||
ESP_LOGW(MODEM_TAG, "Failed to exit the PPP mode gracefully");
|
if (!(bits & ESP_MODEM_STOP_PPP_BIT)) {
|
||||||
|
ESP_LOGW(TAG, "Failed to exit the PPP mode gracefully");
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
err:
|
err:
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_notify_ppp_netif_closed(modem_dte_t *dte)
|
esp_err_t esp_modem_notify_ppp_netif_closed(esp_modem_dte_t *dte)
|
||||||
{
|
{
|
||||||
esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
return xSemaphoreGive(esp_dte->exit_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
|
EventBits_t bits = xEventGroupSetBits(esp_dte->process_group, ESP_MODEM_STOP_PPP_BIT);
|
||||||
|
return bits & ESP_MODEM_STOP_BIT ? ESP_FAIL : ESP_OK; // set error if the group indicated MODEM_STOP condition
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_notify_initialized(esp_modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
EventBits_t bits = xEventGroupSetBits(esp_dte->process_group, ESP_MODEM_START_BIT);
|
||||||
|
return bits & ESP_MODEM_START_BIT ? ESP_OK : ESP_FAIL; // START bit should be set (since it's not auto-cleared)
|
||||||
|
// report error otherwise
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_default_destroy(esp_modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(dte, "Cannot destroy NULL dte", err_params);
|
||||||
|
esp_modem_netif_driver_t *netif_adapter = dte->netif_adapter;
|
||||||
|
esp_modem_dce_t *dce = dte->dce;
|
||||||
|
ESP_MODEM_ERR_CHECK(dce && netif_adapter, "Cannot destroy dce or netif_adapter", err_params);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_netif_clear_default_handlers(netif_adapter) == ESP_OK,
|
||||||
|
"modem_netif failed to clread handlers", err);
|
||||||
|
esp_modem_netif_destroy(netif_adapter);
|
||||||
|
dte->netif_adapter = NULL;
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->deinit(dce) == ESP_OK, "failed to deinit dce", err);
|
||||||
|
dte->dce = NULL;
|
||||||
|
ESP_MODEM_ERR_CHECK(dte->deinit(dte) == ESP_OK, "failed to deinit ", err);
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
err_params:
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_default_start(esp_modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(dte, "failed to start zero DTE", err_params);
|
||||||
|
esp_modem_dce_t *dce = dte->dce;
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "failed to start zero DCE", err_params);
|
||||||
|
|
||||||
|
return dce->start_up(dce);
|
||||||
|
|
||||||
|
err_params:
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_default_attach(esp_modem_dte_t *dte, esp_modem_dce_t *dce, esp_netif_t* ppp_netif)
|
||||||
|
{
|
||||||
|
/* Bind DTE with DCE */
|
||||||
|
dce->dte = dte;
|
||||||
|
dte->dce = dce;
|
||||||
|
|
||||||
|
/* Init and bind DTE with the PPP netif adapter */
|
||||||
|
esp_modem_netif_driver_t *modem_netif_adapter = esp_modem_netif_new(dte);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_netif_set_default_handlers(modem_netif_adapter, ppp_netif) == ESP_OK,
|
||||||
|
"modem_netif failed to set handlers", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_netif_attach(ppp_netif, modem_netif_adapter) == ESP_OK,
|
||||||
|
"attach netif to modem adapter failed", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_notify_initialized(dte) == ESP_OK, "DTE init notification failed", err);
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_modem_dce_t *esp_modem_dce_new(esp_modem_dce_config_t *config)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(config, "failed to init with zero configuration", err);
|
||||||
|
esp_modem_dce_t *dce = calloc(1, sizeof(esp_modem_dce_t));
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "calloc of esp_modem_dce_t failed", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_dce_init(dce, config) == ESP_OK, "esp_modem_dce_init has failed", err);
|
||||||
|
return dce;
|
||||||
|
err:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_init(esp_modem_dce_t *dce, esp_modem_dce_config_t *config)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
/* init the default DCE first */
|
||||||
|
ESP_MODEM_ERR_CHECK(dce && config, "failed to init with zero dce or configuration", err_params);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_dce_default_init(dce, config) == ESP_OK, "dce default init has failed", err);
|
||||||
|
if (config->populate_command_list) {
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_set_default_command_list(dce) == ESP_OK, "esp_modem_dce_set_default_commands failed", err);
|
||||||
|
}
|
||||||
|
switch (config->device) {
|
||||||
|
case ESP_MODEM_DEVICE_SIM800:
|
||||||
|
err = esp_modem_sim800_specific_init(dce);
|
||||||
|
break;
|
||||||
|
case ESP_MODEM_DEVICE_SIM7600:
|
||||||
|
err = esp_modem_sim7600_specific_init(dce);
|
||||||
|
break;
|
||||||
|
case ESP_MODEM_DEVICE_BG96:
|
||||||
|
err = esp_modem_bg96_specific_init(dce);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case ESP_MODEM_DEVICE_UNSPECIFIED:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ESP_MODEM_ERR_CHECK(err == ESP_OK, "dce specific initialization has failed for %d type device", err, config->device);
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
err_params:
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -11,94 +11,237 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include "esp_netif.h"
|
|
||||||
#include "esp_netif_ppp.h"
|
|
||||||
#include "esp_modem.h"
|
|
||||||
#include "esp_modem_netif.h"
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#include "esp_modem.h"
|
||||||
|
#include "esp_modem_dte.h"
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
#include "esp_modem_compat.h"
|
||||||
|
#include "esp_modem_dce_common_commands.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Error check macro
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define ESP_MODEM_COMPAT_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 = "esp-modem-compat";
|
static const char *TAG = "esp-modem-compat";
|
||||||
|
|
||||||
static void on_modem_compat_handler(void *arg, esp_event_base_t event_base,
|
/**
|
||||||
int32_t event_id, void *event_data)
|
* @note Below are the backward compatible functions defined using esp_modem_dce framework
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static esp_err_t compat_hang_up(modem_dce_t *dce)
|
||||||
{
|
{
|
||||||
int32_t compat_event_id = MODEM_EVENT_UNKNOWN;
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
switch (event_id) {
|
return esp_dce->hang_up(esp_dce, NULL, NULL);
|
||||||
case ESP_MODEM_EVENT_PPP_START:
|
}
|
||||||
compat_event_id = MODEM_EVENT_PPP_START;
|
|
||||||
break;
|
static esp_err_t compat_echo(modem_dce_t *dce, bool on)
|
||||||
case ESP_MODEM_EVENT_PPP_STOP:
|
{
|
||||||
compat_event_id = MODEM_EVENT_PPP_STOP;
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
break;
|
return esp_dce->set_echo(esp_dce, (void*)on, NULL);
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
|
static esp_err_t compat_define_pdp_context(modem_dce_t *dce, uint32_t cid, const char *type, const char *apn)
|
||||||
|
{
|
||||||
|
esp_modem_dce_pdp_ctx_t pdp = { .type = type, .cid = cid, .apn = apn };
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
return esp_dce->set_pdp_context(esp_dce, &pdp, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t compat_sync(modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
return esp_dce->sync(esp_dce, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t compat_set_flow_ctrl(modem_dce_t *dce, esp_modem_flow_ctrl_t flow_ctrl)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
return esp_dce->set_flow_ctrl(esp_dce, (void*)flow_ctrl, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t compat_store_profile(modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
return esp_dce->store_profile(esp_dce, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t compat_get_signal_quality(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber)
|
||||||
|
{
|
||||||
|
esp_modem_dce_csq_ctx_t result;
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
esp_err_t err = esp_modem_command_list_run(esp_dce, "get_signal_quality", NULL, &result);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
*rssi = result.rssi;
|
||||||
|
*ber = result.ber;
|
||||||
}
|
}
|
||||||
esp_event_post(ESP_MODEM_EVENT, compat_event_id, NULL, 0, 0);
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_ip_event(void *arg, esp_event_base_t event_base,
|
static esp_err_t compat_get_battery_status(modem_dce_t *dce, uint32_t *bcs, uint32_t *bcl, uint32_t *voltage)
|
||||||
int32_t event_id, void *event_data)
|
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "IP event! %d", event_id);
|
esp_modem_dce_cbc_ctx_t result;
|
||||||
if (event_id == IP_EVENT_PPP_GOT_IP) {
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
esp_netif_dns_info_t dns_info;
|
esp_err_t err = esp_modem_command_list_run(esp_dce, "get_battery_status", NULL, &result);
|
||||||
ppp_client_ip_info_t ipinfo = {0};
|
if (err == ESP_OK) {
|
||||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
*bcs = result.bcs;
|
||||||
esp_netif_t *netif = event->esp_netif;
|
*bcl = result.bcl;
|
||||||
ipinfo.ip.addr = event->ip_info.ip.addr;
|
*voltage = result.battery_status;
|
||||||
ipinfo.gw.addr = event->ip_info.gw.addr;
|
|
||||||
ipinfo.netmask.addr = event->ip_info.netmask.addr;
|
|
||||||
esp_netif_get_dns_info(netif, 0, &dns_info);
|
|
||||||
ipinfo.ns1.addr = dns_info.ip.u_addr.ip4.addr;
|
|
||||||
ipinfo.ns2.addr = dns_info.ip.u_addr.ip4.addr;
|
|
||||||
esp_event_post(ESP_MODEM_EVENT, MODEM_EVENT_PPP_CONNECT, &ipinfo, sizeof(ipinfo), 0);
|
|
||||||
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
|
|
||||||
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
|
|
||||||
esp_event_post(ESP_MODEM_EVENT, MODEM_EVENT_PPP_DISCONNECT, NULL, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_add_event_handler(modem_dte_t *dte, esp_event_handler_t handler, void *handler_args)
|
static esp_err_t compat_set_working_mode(modem_dce_t *dce, esp_modem_mode_t mode)
|
||||||
{
|
{
|
||||||
// event loop has to be created when using this API -- create and ignore failure if already created
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
esp_event_loop_create_default();
|
return esp_modem_dce_set_working_mode(esp_dce, mode);
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(ESP_MODEM_EVENT, MODEM_EVENT_PPP_START, handler, handler_args));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(ESP_MODEM_EVENT, MODEM_EVENT_PPP_CONNECT, handler, handler_args));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(ESP_MODEM_EVENT, MODEM_EVENT_PPP_DISCONNECT, handler, handler_args));
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(ESP_MODEM_EVENT, MODEM_EVENT_PPP_STOP, handler, handler_args));
|
|
||||||
return esp_modem_set_event_handler(dte, on_modem_compat_handler, ESP_EVENT_ANY_ID, handler_args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_setup_ppp(modem_dte_t *dte)
|
static esp_err_t compat_get_module_name(modem_dce_t *dce)
|
||||||
{
|
{
|
||||||
#if CONFIG_LWIP_PPP_PAP_SUPPORT && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD)
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_PAP;
|
return esp_modem_command_list_run(esp_dce, "get_module_name", (void *) sizeof(dce->name), dce->name);
|
||||||
#elif CONFIG_LWIP_PPP_CHAP_SUPPORT && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD)
|
|
||||||
esp_netif_auth_type_t auth_type = NETIF_PPP_AUTHTYPE_CHAP;
|
|
||||||
#elif defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD)
|
|
||||||
#error "Unsupported AUTH Negotiation while AUTH_USERNAME and PASSWORD defined"
|
|
||||||
#endif
|
|
||||||
// Init netif object
|
|
||||||
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP();
|
|
||||||
esp_netif_t *esp_netif = esp_netif_new(&cfg);
|
|
||||||
assert(esp_netif);
|
|
||||||
|
|
||||||
// event loop has to be created when using this API -- create and ignore failure if already created
|
|
||||||
esp_event_loop_create_default();
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event, NULL));
|
|
||||||
#if defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME) && defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD)
|
|
||||||
esp_netif_ppp_set_auth(esp_netif, auth_type, CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME, CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD);
|
|
||||||
#endif
|
|
||||||
void *modem_netif_adapter = esp_modem_netif_setup(dte);
|
|
||||||
esp_modem_netif_set_default_handlers(modem_netif_adapter, esp_netif);
|
|
||||||
/* attach the modem to the network interface */
|
|
||||||
return esp_netif_attach(esp_netif, modem_netif_adapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_exit_ppp(modem_dte_t *dte)
|
static esp_err_t compat_get_imei_number(modem_dce_t *dce)
|
||||||
{
|
{
|
||||||
// Note: A minor memory leak is expected when using esp-modem-compat
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
return esp_modem_stop_ppp(dte);
|
return esp_modem_command_list_run(esp_dce, "get_imei_number", (void *) sizeof(dce->imei), dce->imei);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t compat_get_operator_name(modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
return esp_modem_command_list_run(esp_dce, "get_operator_name", (void *) sizeof(dce->oper), dce->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t compat_get_imsi_number(modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
return esp_modem_command_list_run(esp_dce, "get_imsi_number", (void *) sizeof(dce->imsi), dce->imsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t compat_power_down(modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
return esp_modem_command_list_run(esp_dce, "power_down", (void *) sizeof(dce->imsi), dce->imsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compatibility deinitialize
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on fail
|
||||||
|
*/
|
||||||
|
static esp_err_t compat_deinit(modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
esp_err_t err = esp_modem_command_list_deinit(esp_dce);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
free(dce);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compatibility init
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static modem_dce_t *esp_modem_compat_init(modem_dte_t *dte, esp_modem_dce_device_t device)
|
||||||
|
{
|
||||||
|
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_MODEM_PPP_APN);
|
||||||
|
dce_config.device = device;
|
||||||
|
dce_config.populate_command_list = true;
|
||||||
|
modem_dce_t *dce = calloc(1, sizeof(modem_dce_t));
|
||||||
|
if (dce == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esp_modem_dce_init(&dce->parent, &dce_config) != ESP_OK) {
|
||||||
|
free(dce);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dce->sync = compat_sync;
|
||||||
|
dce->echo_mode = compat_echo;
|
||||||
|
dce->store_profile = compat_store_profile;
|
||||||
|
dce->set_flow_ctrl = compat_set_flow_ctrl;
|
||||||
|
dce->define_pdp_context = compat_define_pdp_context;
|
||||||
|
dce->hang_up = compat_hang_up;
|
||||||
|
dce->get_signal_quality = compat_get_signal_quality;
|
||||||
|
dce->get_battery_status = compat_get_battery_status;
|
||||||
|
dce->set_working_mode = compat_set_working_mode;
|
||||||
|
dce->power_down = compat_power_down;
|
||||||
|
dce->deinit = compat_deinit;
|
||||||
|
esp_modem_dce_t* esp_dce = &dce->parent;
|
||||||
|
/* Bind DTE with DCE */
|
||||||
|
esp_dce->dte = dte;
|
||||||
|
dte->dce = esp_dce;
|
||||||
|
/* All units initialized, notify the modem before sending commands */
|
||||||
|
ESP_MODEM_COMPAT_CHECK(esp_modem_notify_initialized(dte) == ESP_OK, "modem start notification failed", err);
|
||||||
|
|
||||||
|
ESP_MODEM_COMPAT_CHECK(compat_sync(dce) == ESP_OK, "sync failed", err);
|
||||||
|
/* Close echo */
|
||||||
|
ESP_MODEM_COMPAT_CHECK(compat_echo(dce, false) == ESP_OK, "close echo mode failed", err);
|
||||||
|
|
||||||
|
|
||||||
|
bool ready;
|
||||||
|
ESP_ERROR_CHECK(esp_modem_command_list_run(esp_dce, "read_pin", NULL, &ready));
|
||||||
|
if (!ready) {
|
||||||
|
ESP_LOGE(TAG, "PIN not ready man");
|
||||||
|
ESP_ERROR_CHECK(esp_modem_command_list_run(esp_dce, "set_pin", "1234", NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get Module name */
|
||||||
|
ESP_MODEM_COMPAT_CHECK(compat_get_module_name(dce) == ESP_OK, "get module name failed", err);
|
||||||
|
/* Get IMEI number */
|
||||||
|
ESP_MODEM_COMPAT_CHECK(compat_get_imei_number(dce) == ESP_OK, "get imei number failed", err);
|
||||||
|
/* Get IMSI number */
|
||||||
|
ESP_MODEM_COMPAT_CHECK(compat_get_imsi_number(dce) == ESP_OK, "get imsi number failed", err);
|
||||||
|
/* Get operator name */
|
||||||
|
ESP_MODEM_COMPAT_CHECK(compat_get_operator_name(dce) == ESP_OK, "get operator name failed", err);
|
||||||
|
return dce;
|
||||||
|
err:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Legacy init of SIM800 module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
modem_dce_t *sim800_init(modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
return esp_modem_compat_init(dte, ESP_MODEM_DEVICE_SIM800);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Legacy init of BG96 module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
modem_dce_t *bg96_init(modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
return esp_modem_compat_init(dte, ESP_MODEM_DEVICE_BG96);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Legacy init of SIM7600 module
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
modem_dce_t *sim7600_init(modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
return esp_modem_compat_init(dte, ESP_MODEM_DEVICE_SIM7600);
|
||||||
}
|
}
|
||||||
|
190
esp_modem/src/esp_modem_dce.c
Normal file
190
esp_modem/src/esp_modem_dce.c
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
#include "esp_modem_dce_command_lib.h"
|
||||||
|
#include "esp_modem_dce_common_commands.h"
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
static const char *TAG = "esp_modem_dce";
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_generic_command(esp_modem_dce_t *dce, const char * command, uint32_t timeout, esp_modem_dce_handle_line_t handle_line, void *ctx)
|
||||||
|
{
|
||||||
|
esp_modem_dte_t *dte = dce->dte;
|
||||||
|
ESP_LOGD(TAG, "%s(%d): Sending command:%s\n", __func__, __LINE__, command );
|
||||||
|
dce->handle_line = handle_line;
|
||||||
|
dce->handle_line_ctx = ctx;
|
||||||
|
if (dte->send_cmd(dte, command, timeout) != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "%s(%d): Command:%s response timeout", __func__, __LINE__, command );
|
||||||
|
return ESP_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
if (dce->state == ESP_MODEM_STATE_FAIL) {
|
||||||
|
ESP_LOGW(TAG, "%s(%d): Command:%s\n...failed", __func__, __LINE__, command );
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "%s(%d): Command:%s\n succeeded", __func__, __LINE__, command );
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_params(esp_modem_dce_t *dce, esp_modem_dce_config_t* config)
|
||||||
|
{
|
||||||
|
// save the config
|
||||||
|
memcpy(&dce->config, config, sizeof(esp_modem_dce_config_t));
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_default_init(esp_modem_dce_t *dce, esp_modem_dce_config_t* config)
|
||||||
|
{
|
||||||
|
// Check parameters
|
||||||
|
ESP_MODEM_ERR_CHECK(dce && config, "dce object or configuration is NULL", err);
|
||||||
|
|
||||||
|
// Set default commands needed for the DCE to operate
|
||||||
|
// note: command links will be overwritten if cmd-list enabled
|
||||||
|
dce->set_data_mode = esp_modem_dce_set_data_mode;
|
||||||
|
dce->resume_data_mode = esp_modem_dce_resume_data_mode;
|
||||||
|
dce->set_command_mode = esp_modem_dce_set_command_mode;
|
||||||
|
dce->set_pdp_context = esp_modem_dce_set_pdp_context;
|
||||||
|
dce->hang_up = esp_modem_dce_hang_up;
|
||||||
|
dce->set_echo = esp_modem_dce_set_echo;
|
||||||
|
dce->sync = esp_modem_dce_sync;
|
||||||
|
dce->set_flow_ctrl = esp_modem_dce_set_flow_ctrl;
|
||||||
|
dce->store_profile = esp_modem_dce_store_profile;
|
||||||
|
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_dce_set_params(dce, config) == ESP_OK, "Failed to configure dce object", err);
|
||||||
|
|
||||||
|
// set DCE basic API
|
||||||
|
dce->start_up = esp_modem_dce_default_start_up;
|
||||||
|
dce->deinit = esp_modem_dce_default_destroy;
|
||||||
|
dce->set_working_mode = esp_modem_dce_set_working_mode;
|
||||||
|
|
||||||
|
// initialize the list if enabled
|
||||||
|
if (config->populate_command_list) {
|
||||||
|
dce->dce_cmd_list = esp_modem_command_list_create();
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->dce_cmd_list, "Allocation of dce internal object has failed", err);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_default_destroy(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_command_list_deinit(dce) == ESP_OK, "failed", err);
|
||||||
|
free(dce);
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_handle_response_default(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_process_command_done(esp_modem_dce_t *dce, esp_modem_state_t state)
|
||||||
|
{
|
||||||
|
dce->state = state;
|
||||||
|
return dce->dte->process_cmd_done(dce->dte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t esp_modem_switch_to_command_mode(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_modem_wait_ms(1000); // 1s delay for the device to recognize the data escape sequence
|
||||||
|
if (dce->set_command_mode(dce, NULL, NULL) != ESP_OK) {
|
||||||
|
// exiting data mode could fail if the modem is already in command mode via PPP netif closed
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->sync(dce, NULL, NULL) == ESP_OK, "sync after PPP exit failed", err);
|
||||||
|
} else {
|
||||||
|
// hang-up if exit PPP succeeded
|
||||||
|
dce->mode = ESP_MODEM_COMMAND_MODE;
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->hang_up(dce, NULL, NULL) == ESP_OK, "hang-up after PPP exit failed", err);
|
||||||
|
}
|
||||||
|
dce->mode = ESP_MODEM_COMMAND_MODE;
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t esp_modem_switch_to_data_mode(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
// before going to data mode, set the PDP data context
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_pdp_context(dce, &dce->config.pdp_context, NULL) == ESP_OK, "setting pdp context failed", err);
|
||||||
|
// now set the data mode
|
||||||
|
if (dce->set_data_mode(dce, NULL, NULL) != ESP_OK) {
|
||||||
|
// Initiate PPP mode could fail, if we've already "dialed" the data call before.
|
||||||
|
// in that case we retry to just resume the data mode
|
||||||
|
ESP_LOGD(TAG, "set_data_mode, retry with resume_data_mode");
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->resume_data_mode(dce, NULL, NULL) == ESP_OK, "setting data mode failed", err);
|
||||||
|
}
|
||||||
|
dce->mode = ESP_MODEM_PPP_MODE;
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set Working Mode
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param mode working mode
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t esp_modem_dce_set_working_mode(esp_modem_dce_t *dce, esp_modem_mode_t mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case ESP_MODEM_COMMAND_MODE:
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_switch_to_command_mode(dce) == ESP_OK, "Setting command mode failed", err);
|
||||||
|
break;
|
||||||
|
case ESP_MODEM_PPP_MODE:
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_switch_to_data_mode(dce) == ESP_OK, "Setting data mode failed", err);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "unsupported working mode: %d", mode);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_default_start_up(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->sync(dce, NULL, NULL) == ESP_OK, "sending sync failed", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_echo(dce, (void*)false, NULL) == ESP_OK, "set_echo failed", err);
|
||||||
|
// TODO: remove!
|
||||||
|
bool ready;
|
||||||
|
// ESP_ERROR_CHECK(esp_modem_command_list_run(dce, "read_pin", NULL, &ready));
|
||||||
|
ESP_ERROR_CHECK(esp_modem_dce_read_pin(dce, NULL, &ready));
|
||||||
|
if (!ready) {
|
||||||
|
ESP_LOGE(TAG, "PIN not ready man");
|
||||||
|
// ESP_ERROR_CHECK(esp_modem_command_list_run(dce, "set_pin", "1234", NULL));
|
||||||
|
ESP_ERROR_CHECK(esp_modem_dce_set_pin(dce, "1234", NULL));
|
||||||
|
}
|
||||||
|
// TODO: remove!
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_flow_ctrl(dce, (void*)ESP_MODEM_FLOW_CONTROL_NONE, NULL) == ESP_OK, "set_flow_ctrl failed", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->store_profile(dce, NULL, NULL) == ESP_OK, "store_profile failed", err);
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
204
esp_modem/src/esp_modem_dce_command_lib.c
Normal file
204
esp_modem/src/esp_modem_dce_command_lib.c
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_modem_dce_command_lib.h"
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
#include "esp_modem_dce_common_commands.h"
|
||||||
|
|
||||||
|
static const char *TAG = "esp_modem_command_lib";
|
||||||
|
|
||||||
|
typedef struct cmd_item_s cmd_item_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct for one item in command list
|
||||||
|
*/
|
||||||
|
struct cmd_item_s {
|
||||||
|
const char *command; //!< command name
|
||||||
|
dce_command_t function; //!< function pointer
|
||||||
|
SLIST_ENTRY(cmd_item_s) next; //!< next command in the list
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private struct defined for dce internal object
|
||||||
|
*/
|
||||||
|
struct esp_modem_dce_cmd_list {
|
||||||
|
SLIST_HEAD(cmd_list_, cmd_item_s) command_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief List of common AT commands in the library
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static const cmd_item_t s_command_list[] = {
|
||||||
|
{ .command = "sync", .function = esp_modem_dce_sync },
|
||||||
|
{ .command = "get_imei_number", .function = esp_modem_dce_get_imei_number },
|
||||||
|
{ .command = "get_imsi_number", .function = esp_modem_dce_get_imsi_number },
|
||||||
|
{ .command = "get_module_name", .function = esp_modem_dce_get_module_name },
|
||||||
|
{ .command = "get_operator_name", .function = esp_modem_dce_get_operator_name },
|
||||||
|
{ .command = "set_echo", .function = esp_modem_dce_set_echo },
|
||||||
|
{ .command = "store_profile", .function = esp_modem_dce_store_profile },
|
||||||
|
{ .command = "set_flow_ctrl", .function = esp_modem_dce_set_flow_ctrl },
|
||||||
|
{ .command = "set_pdp_context", .function = esp_modem_dce_set_pdp_context },
|
||||||
|
{ .command = "hang_up", .function = esp_modem_dce_hang_up },
|
||||||
|
{ .command = "get_signal_quality", .function = esp_modem_dce_get_signal_quality },
|
||||||
|
{ .command = "set_data_mode", .function = esp_modem_dce_set_data_mode },
|
||||||
|
{ .command = "resume_data_mode", .function = esp_modem_dce_resume_data_mode },
|
||||||
|
{ .command = "set_command_mode", .function = esp_modem_dce_set_command_mode },
|
||||||
|
{ .command = "get_battery_status", .function = esp_modem_dce_get_battery_status },
|
||||||
|
{ .command = "power_down", .function = esp_modem_dce_power_down },
|
||||||
|
{ .command = "reset", .function = esp_modem_dce_reset },
|
||||||
|
{ .command = "set_pin", .function = esp_modem_dce_set_pin },
|
||||||
|
{ .command = "read_pin", .function = esp_modem_dce_read_pin },
|
||||||
|
{ .command = "set_baud", .function = esp_modem_dce_set_baud_temp },
|
||||||
|
};
|
||||||
|
|
||||||
|
static esp_err_t update_internal_command_refs(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_data_mode = esp_modem_dce_find_command(dce, "set_data_mode"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->resume_data_mode = esp_modem_dce_find_command(dce, "resume_data_mode"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_command_mode = esp_modem_dce_find_command(dce, "set_command_mode"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_pdp_context = esp_modem_dce_find_command(dce, "set_pdp_context"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->hang_up = esp_modem_dce_find_command(dce, "hang_up"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_echo = esp_modem_dce_find_command(dce, "set_echo"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->sync = esp_modem_dce_find_command(dce, "sync"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_flow_ctrl = esp_modem_dce_find_command(dce, "set_flow_ctrl"), "cmd not found", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->store_profile = esp_modem_dce_find_command(dce, "store_profile"), "cmd not found", err);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t esp_modem_dce_init_command_list(esp_modem_dce_t *dce, size_t commands, const cmd_item_t *command_list)
|
||||||
|
{
|
||||||
|
if (commands < 1 || command_list == NULL || dce->dce_cmd_list == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
SLIST_INIT(&dce->dce_cmd_list->command_list);
|
||||||
|
|
||||||
|
for (int i=0; i < commands; ++i) {
|
||||||
|
cmd_item_t *new_item = calloc(1, sizeof(struct cmd_item_s));
|
||||||
|
new_item->command = command_list[i].command;
|
||||||
|
new_item->function = command_list[i].function;
|
||||||
|
SLIST_INSERT_HEAD(&dce->dce_cmd_list->command_list, new_item, next);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_modem_set_default_command_list(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
esp_err_t err = esp_modem_dce_init_command_list(dce, sizeof(s_command_list) / sizeof(cmd_item_t), s_command_list);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
return update_internal_command_refs(dce);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_command_list_run(esp_modem_dce_t *dce, const char * command, void * param, void* result)
|
||||||
|
{
|
||||||
|
if (dce == NULL || dce->dce_cmd_list == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_item_t *item;
|
||||||
|
SLIST_FOREACH(item, &dce->dce_cmd_list->command_list, next) {
|
||||||
|
if (strcmp(item->command, command) == 0) {
|
||||||
|
return item->function(dce, param, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dce_command_t esp_modem_dce_find_command(esp_modem_dce_t *dce, const char * command)
|
||||||
|
{
|
||||||
|
if (dce == NULL || dce->dce_cmd_list == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_item_t *item;
|
||||||
|
SLIST_FOREACH(item, &dce->dce_cmd_list->command_list, next) {
|
||||||
|
if (strcmp(item->command, command) == 0) {
|
||||||
|
return item->function;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_delete_all_commands(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
if (dce->dce_cmd_list) {
|
||||||
|
while (!SLIST_EMPTY(&dce->dce_cmd_list->command_list)) {
|
||||||
|
cmd_item_t *item = SLIST_FIRST(&dce->dce_cmd_list->command_list);
|
||||||
|
SLIST_REMOVE_HEAD(&dce->dce_cmd_list->command_list, next);
|
||||||
|
free(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_delete_command(esp_modem_dce_t *dce, const char * command_id)
|
||||||
|
{
|
||||||
|
cmd_item_t *item;
|
||||||
|
SLIST_FOREACH(item, &dce->dce_cmd_list->command_list, next) {
|
||||||
|
if (strcmp(item->command, command_id) == 0) {
|
||||||
|
SLIST_REMOVE(&dce->dce_cmd_list->command_list, item, cmd_item_s, next);
|
||||||
|
free(item);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_command_list_set_cmd(esp_modem_dce_t *dce, const char * command_id, dce_command_t command)
|
||||||
|
{
|
||||||
|
if (dce == NULL || dce->dce_cmd_list == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_item_t *item;
|
||||||
|
SLIST_FOREACH(item, &dce->dce_cmd_list->command_list, next) {
|
||||||
|
if (strcmp(item->command, command_id) == 0) {
|
||||||
|
item->function = command;
|
||||||
|
return update_internal_command_refs(dce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd_item_t *new_item = calloc(1, sizeof(struct cmd_item_s));
|
||||||
|
new_item->command = command_id;
|
||||||
|
new_item->function = command;
|
||||||
|
SLIST_INSERT_HEAD(&dce->dce_cmd_list->command_list, new_item, next);
|
||||||
|
return update_internal_command_refs(dce);;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct esp_modem_dce_cmd_list* esp_modem_command_list_create(void)
|
||||||
|
{
|
||||||
|
return calloc(1, sizeof(struct esp_modem_dce_cmd_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_command_list_deinit(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
if (dce->dte) {
|
||||||
|
dce->dte->dce = NULL;
|
||||||
|
}
|
||||||
|
esp_modem_dce_delete_all_commands(dce);
|
||||||
|
free(dce->dce_cmd_list);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
357
esp_modem/src/esp_modem_dce_common_commands.c
Normal file
357
esp_modem/src/esp_modem_dce_common_commands.c
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_modem_dce.h"
|
||||||
|
#include "esp_modem_dce_common_commands.h"
|
||||||
|
|
||||||
|
typedef struct common_string_s {
|
||||||
|
const char * command;
|
||||||
|
char * string;
|
||||||
|
size_t len;
|
||||||
|
} common_string_t;
|
||||||
|
|
||||||
|
|
||||||
|
static inline esp_err_t generic_command_default_handle(esp_modem_dce_t *dce, const char * command)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, command, MODEM_COMMAND_TIMEOUT_DEFAULT, esp_modem_dce_handle_response_default, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t common_handle_string(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
} else {
|
||||||
|
common_string_t *result_str = dce->handle_line_ctx;
|
||||||
|
assert(result_str->string != NULL && result_str->len != 0);
|
||||||
|
int len = snprintf(result_str->string, result_str->len, "%s", line);
|
||||||
|
if (len > 2) {
|
||||||
|
/* Strip "\r\n" */
|
||||||
|
strip_cr_lf_tail(result_str->string, len);
|
||||||
|
err = ESP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle response from AT+CBC
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dce_common_handle_cbc(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
} else if (!strncmp(line, "+CBC", strlen("+CBC"))) {
|
||||||
|
esp_modem_dce_cbc_ctx_t *cbc = dce->handle_line_ctx;
|
||||||
|
/* +CBC: <bcs>,<bcl>,<voltage> */
|
||||||
|
sscanf(line, "%*s%d,%d,%d", &cbc->bcs, &cbc->bcl, &cbc->battery_status);
|
||||||
|
err = ESP_OK;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Handle response from AT+CSQ
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dce_common_handle_csq(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
} else if (!strncmp(line, "+CSQ", strlen("+CSQ"))) {
|
||||||
|
/* store value of rssi and ber */
|
||||||
|
esp_modem_dce_csq_ctx_t *csq = dce->handle_line_ctx;
|
||||||
|
/* +CSQ: <rssi>,<ber> */
|
||||||
|
sscanf(line, "%*s%d,%d", &csq->rssi, &csq->ber);
|
||||||
|
err = ESP_OK;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle response from AT+QPOWD=1
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dce_handle_power_down(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
|
||||||
|
err = ESP_OK;
|
||||||
|
} else if (strstr(line, "POWERED DOWN")) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle response from exiting the PPP mode
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dce_handle_exit_data_mode(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_NO_CARRIER)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle response from entry of the PPP mode
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dce_handle_atd_ppp(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (strstr(line, MODEM_RESULT_CODE_CONNECT)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t esp_modem_dce_handle_read_pin(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, "READY")) {
|
||||||
|
bool *ready = (bool*)dce->handle_line_ctx;
|
||||||
|
*ready = true;
|
||||||
|
err = ESP_OK;
|
||||||
|
} else if (strstr(line, "PIN") || strstr(line, "PUK")) {
|
||||||
|
bool *ready = (bool*)dce->handle_line_ctx;
|
||||||
|
*ready = false;
|
||||||
|
err = ESP_OK;
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t esp_modem_dce_handle_reset(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
|
||||||
|
err = ESP_OK;
|
||||||
|
} else
|
||||||
|
if (strstr(line, "PB DONE")) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_sync(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return generic_command_default_handle(dce, "AT\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_echo(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
bool echo_on = (bool)param;
|
||||||
|
if (echo_on) {
|
||||||
|
return generic_command_default_handle(dce, "ATE1\r");
|
||||||
|
} else {
|
||||||
|
return generic_command_default_handle(dce, "ATE0\r");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t common_get_operator_after_mode_format(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
} else if (!strncmp(line, "+COPS", strlen("+COPS"))) {
|
||||||
|
common_string_t *result_str = dce->handle_line_ctx;
|
||||||
|
assert(result_str->string != NULL && result_str->len != 0);
|
||||||
|
/* there might be some random spaces in operator's name, we can not use sscanf to parse the result */
|
||||||
|
/* strtok will break the string, we need to create a copy */
|
||||||
|
char *line_copy = strdup(line);
|
||||||
|
/* +COPS: <mode>[, <format>[, <oper>]] */
|
||||||
|
char *str_ptr = NULL;
|
||||||
|
char *p[3];
|
||||||
|
uint8_t i = 0;
|
||||||
|
/* strtok will broke string by replacing delimiter with '\0' */
|
||||||
|
p[i] = strtok_r(line_copy, ",", &str_ptr);
|
||||||
|
while (p[i]) {
|
||||||
|
p[++i] = strtok_r(NULL, ",", &str_ptr);
|
||||||
|
}
|
||||||
|
if (i >= 3) {
|
||||||
|
int len = snprintf(result_str->string, result_str->len, "%s", p[2]);
|
||||||
|
if (len > 2) {
|
||||||
|
/* Strip "\r\n" */
|
||||||
|
strip_cr_lf_tail(result_str->string, len);
|
||||||
|
err = ESP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(line_copy);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t common_get_common_string(esp_modem_dce_t *dce, void *ctx)
|
||||||
|
{
|
||||||
|
common_string_t * param_str = ctx;
|
||||||
|
return esp_modem_dce_generic_command(dce, param_str->command, MODEM_COMMAND_TIMEOUT_DEFAULT, common_handle_string, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_get_imei_number(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
common_string_t common_str = { .command = "AT+CGSN\r", .string = result, .len = (size_t)param };
|
||||||
|
return common_get_common_string(dce, &common_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_get_imsi_number(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
common_string_t common_str = { .command = "AT+CIMI\r", .string = result, .len = (size_t)param };
|
||||||
|
return common_get_common_string(dce, &common_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_get_module_name(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
common_string_t common_str = { .command = "AT+CGMM\r", .string = result, .len = (size_t)param };
|
||||||
|
return common_get_common_string(dce, &common_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_get_operator_name(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
common_string_t common_str = { .command = "AT+COPS?\r", .string = result, .len = (size_t)param };
|
||||||
|
return esp_modem_dce_generic_command(dce, common_str.command, MODEM_COMMAND_TIMEOUT_OPERATOR,
|
||||||
|
common_get_operator_after_mode_format, &common_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_reset(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "AT+CRESET\r", MODEM_COMMAND_TIMEOUT_RESET, esp_modem_dce_handle_reset, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_pin(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
char command[] = "AT+CPIN=0000\r";
|
||||||
|
memcpy(command + 8, param, 4); // copy 4 bytes to the "0000" placeholder
|
||||||
|
esp_err_t err = esp_modem_dce_generic_command(dce, command, MODEM_COMMAND_TIMEOUT_DEFAULT, esp_modem_dce_handle_response_default, NULL);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_read_pin(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "AT+CPIN?\r", MODEM_COMMAND_TIMEOUT_DEFAULT, esp_modem_dce_handle_read_pin, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_store_profile(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return generic_command_default_handle(dce, "AT&W\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_flow_ctrl(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
esp_modem_dte_t *dte = dce->dte;
|
||||||
|
esp_modem_flow_ctrl_t flow_ctrl = (esp_modem_flow_ctrl_t)param;
|
||||||
|
char *command;
|
||||||
|
int len = asprintf(&command, "AT+IFC=%d,%d\r", dte->flow_ctrl, flow_ctrl);
|
||||||
|
if (len <= 0) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
esp_err_t err = generic_command_default_handle(dce, command);
|
||||||
|
free(command);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_pdp_context(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
esp_modem_dce_pdp_ctx_t *pdp = param;
|
||||||
|
char *command;
|
||||||
|
int len = asprintf(&command, "AT+CGDCONT=%d,\"%s\",\"%s\"\r", pdp->cid, pdp->type, pdp->apn);
|
||||||
|
if (len <= 0) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
esp_err_t err = generic_command_default_handle(dce, command);
|
||||||
|
free(command);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MODEM_COMMAND_TIMEOUT_HANG_UP (90000) /*!< Timeout value for hang up */
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_hang_up(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "ATH\r", MODEM_COMMAND_TIMEOUT_HANG_UP,
|
||||||
|
esp_modem_dce_handle_response_default, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_get_signal_quality(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "AT+CSQ\r", MODEM_COMMAND_TIMEOUT_DEFAULT,
|
||||||
|
esp_modem_dce_common_handle_csq, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_get_battery_status(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "AT+CBC\r", MODEM_COMMAND_TIMEOUT_DEFAULT,
|
||||||
|
esp_modem_dce_common_handle_cbc, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_data_mode(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "ATD*99***1#\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE,
|
||||||
|
esp_modem_dce_handle_atd_ppp, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_resume_data_mode(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "ATO\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE,
|
||||||
|
esp_modem_dce_handle_atd_ppp, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_command_mode(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "+++", MODEM_COMMAND_TIMEOUT_MODE_CHANGE,
|
||||||
|
esp_modem_dce_handle_exit_data_mode, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_power_down(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "AT+QPOWD=1\r", MODEM_COMMAND_TIMEOUT_POWEROFF,
|
||||||
|
esp_modem_dce_handle_power_down, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dce_set_baud_temp(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
char command[] = "AT+IPR=3686400\r"; // reserve space with max baud placeholder
|
||||||
|
size_t cmd_placeholder_len = strlen(command);
|
||||||
|
strncpy(command + 7, param, cmd_placeholder_len-7); // copy param string to the param
|
||||||
|
size_t cmd_len = strlen(command);
|
||||||
|
if (cmd_len+1 >= cmd_placeholder_len) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
command[cmd_len] = '\r';
|
||||||
|
command[cmd_len+1] = '\0';
|
||||||
|
return esp_modem_dce_generic_command(dce, command, MODEM_COMMAND_TIMEOUT_DEFAULT,
|
||||||
|
esp_modem_dce_handle_response_default, NULL);
|
||||||
|
}
|
@ -1,126 +0,0 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_modem_dce_service.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Macro defined for error checking
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static const char *DCE_TAG = "dce_service";
|
|
||||||
#define DCE_CHECK(a, str, goto_tag, ...) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (!(a)) \
|
|
||||||
{ \
|
|
||||||
ESP_LOGE(DCE_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
|
||||||
goto goto_tag; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
esp_err_t esp_modem_dce_handle_response_default(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_dce_sync(modem_dce_t *dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "sync failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "sync ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_dce_echo(modem_dce_t *dce, bool on)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
if (on) {
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "ATE1\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enable echo failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "enable echo ok");
|
|
||||||
} else {
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "ATE0\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "disable echo failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "disable echo ok");
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_dce_store_profile(modem_dce_t *dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT&W\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "save settings failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "save settings ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_dce_set_flow_ctrl(modem_dce_t *dce, modem_flow_ctrl_t flow_ctrl)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
char command[16];
|
|
||||||
int len = snprintf(command, sizeof(command), "AT+IFC=%d,%d\r", dte->flow_ctrl, flow_ctrl);
|
|
||||||
DCE_CHECK(len < sizeof(command), "command too long: %s", err, command);
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, command, MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "set flow control failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "set flow control ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_dce_define_pdp_context(modem_dce_t *dce, uint32_t cid, const char *type, const char *apn)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
char command[64];
|
|
||||||
int len = snprintf(command, sizeof(command), "AT+CGDCONT=%d,\"%s\",\"%s\"\r", cid, type, apn);
|
|
||||||
DCE_CHECK(len < sizeof(command), "command too long: %s", err, command);
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, command, MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "define pdp context failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "define pdp context ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t esp_modem_dce_hang_up(modem_dce_t *dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "ATH\r", MODEM_COMMAND_TIMEOUT_HANG_UP) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "hang up failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "hang up ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
505
esp_modem/src/esp_modem_dte.c
Normal file
505
esp_modem/src/esp_modem_dte.c
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#define ESP_MODEM_EVENT_QUEUE_SIZE (16)
|
||||||
|
|
||||||
|
#define MIN_PATTERN_INTERVAL (9)
|
||||||
|
#define MIN_POST_IDLE (0)
|
||||||
|
#define MIN_PRE_IDLE (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Macro defined for error checking
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static const char *TAG = "esp-modem-dte";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns true if the supplied string contains only CR or LF
|
||||||
|
*
|
||||||
|
* @param str string to check
|
||||||
|
* @param len length of string
|
||||||
|
*/
|
||||||
|
static inline bool is_only_cr_lf(const char *str, uint32_t len)
|
||||||
|
{
|
||||||
|
for (int i=0; i<len; ++i) {
|
||||||
|
if (str[i] != '\r' && str[i] != '\n') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_set_rx_cb(esp_modem_dte_t *dte, esp_modem_on_receive receive_cb, void *receive_cb_ctx)
|
||||||
|
{
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
esp_dte->receive_cb_ctx = receive_cb_ctx;
|
||||||
|
esp_dte->receive_cb = receive_cb;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle one line in DTE
|
||||||
|
*
|
||||||
|
* @param esp_dte ESP modem DTE object
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_dte_handle_line(esp_modem_dte_internal_t *esp_dte)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t *dce = esp_dte->parent.dce;
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "DTE has not yet bind with DCE", err);
|
||||||
|
const char *line = (const char *)(esp_dte->buffer);
|
||||||
|
size_t len = strlen(line);
|
||||||
|
/* Skip pure "\r\n" lines */
|
||||||
|
if (len > 2 && !is_only_cr_lf(line, len)) {
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->handle_line, "no handler for line", err_handle);
|
||||||
|
ESP_LOGD(TAG, "%s: %s", __func__ , line);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->handle_line(dce, line) == ESP_OK, "handle line failed", err_handle);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
err_handle:
|
||||||
|
/* Send ESP_MODEM_EVENT_UNKNOWN signal to event loop */
|
||||||
|
esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_UNKNOWN,
|
||||||
|
(void *)line, strlen(line) + 1, pdMS_TO_TICKS(100));
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle when a pattern has been detected by UART
|
||||||
|
*
|
||||||
|
* @param esp_dte ESP32 Modem DTE object
|
||||||
|
*/
|
||||||
|
static void esp_handle_uart_pattern(esp_modem_dte_internal_t *esp_dte)
|
||||||
|
{
|
||||||
|
int pos = uart_pattern_pop_pos(esp_dte->uart_port);
|
||||||
|
int read_len = 0;
|
||||||
|
if (pos != -1) {
|
||||||
|
if (pos < esp_dte->line_buffer_size - 1) {
|
||||||
|
/* read one line(include '\n') */
|
||||||
|
read_len = pos + 1;
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "ESP Modem Line buffer too small");
|
||||||
|
read_len = esp_dte->line_buffer_size - 1;
|
||||||
|
}
|
||||||
|
read_len = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, read_len, pdMS_TO_TICKS(100));
|
||||||
|
if (read_len) {
|
||||||
|
/* make sure the line is a standard string */
|
||||||
|
esp_dte->buffer[read_len] = '\0';
|
||||||
|
/* Send new line to handle */
|
||||||
|
esp_dte_handle_line(esp_dte);
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "uart read bytes failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t length = 0;
|
||||||
|
uart_get_buffered_data_len(esp_dte->uart_port, &length);
|
||||||
|
ESP_LOGW(TAG, "Pattern not found in the pattern queue, uart data length = %d", length);
|
||||||
|
length = MIN(esp_dte->line_buffer_size-1, length);
|
||||||
|
length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("esp-modem-dte: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG);
|
||||||
|
|
||||||
|
uart_flush(esp_dte->uart_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle when new data received by UART
|
||||||
|
*
|
||||||
|
* @param esp_dte ESP32 Modem DTE object
|
||||||
|
*/
|
||||||
|
static void esp_handle_uart_data(esp_modem_dte_internal_t *esp_dte)
|
||||||
|
{
|
||||||
|
if (!esp_dte->parent.dce) {
|
||||||
|
// we could possibly get a data event before
|
||||||
|
// the DCE gets bound yet with the DTE, so just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t length = 0;
|
||||||
|
uart_get_buffered_data_len(esp_dte->uart_port, &length);
|
||||||
|
|
||||||
|
if (esp_dte->parent.dce->mode != ESP_MODEM_PPP_MODE) {
|
||||||
|
// Check if matches the pattern to process the data as pattern
|
||||||
|
int pos = uart_pattern_pop_pos(esp_dte->uart_port);
|
||||||
|
if (pos > -1) {
|
||||||
|
esp_handle_uart_pattern(esp_dte);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Read the data and process it using `handle_line` logic
|
||||||
|
length = MIN(esp_dte->line_buffer_size-1, length);
|
||||||
|
length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("esp-modem-dte: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG);
|
||||||
|
esp_dte->buffer[length] = '\0';
|
||||||
|
if (esp_dte->parent.dce->handle_line) {
|
||||||
|
// Send new line to handle if handler registered
|
||||||
|
esp_dte_handle_line(esp_dte);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
length = MIN(esp_dte->line_buffer_size, length);
|
||||||
|
length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
|
||||||
|
/* pass the input data to configured callback */
|
||||||
|
if (length) {
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("esp-modem-dte: ppp_input", esp_dte->buffer, length, ESP_LOG_VERBOSE);
|
||||||
|
esp_dte->receive_cb(esp_dte->buffer, length, esp_dte->receive_cb_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UART Event Task Entry
|
||||||
|
*
|
||||||
|
* @param param task parameter
|
||||||
|
*/
|
||||||
|
static void uart_event_task_entry(void *param)
|
||||||
|
{
|
||||||
|
esp_modem_dte_internal_t *esp_dte = (esp_modem_dte_internal_t *)param;
|
||||||
|
uart_event_t event;
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(esp_dte->process_group, (ESP_MODEM_START_BIT|ESP_MODEM_STOP_BIT), pdFALSE, pdFALSE, portMAX_DELAY);
|
||||||
|
if (bits & ESP_MODEM_STOP_BIT) {
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (xEventGroupGetBits(esp_dte->process_group) & ESP_MODEM_START_BIT) {
|
||||||
|
if (xQueueReceive(esp_dte->event_queue, &event, pdMS_TO_TICKS(100))) {
|
||||||
|
switch (event.type) {
|
||||||
|
case UART_DATA:
|
||||||
|
esp_handle_uart_data(esp_dte);
|
||||||
|
break;
|
||||||
|
case UART_FIFO_OVF:
|
||||||
|
ESP_LOGW(TAG, "HW FIFO Overflow");
|
||||||
|
uart_flush_input(esp_dte->uart_port);
|
||||||
|
xQueueReset(esp_dte->event_queue);
|
||||||
|
break;
|
||||||
|
case UART_BUFFER_FULL:
|
||||||
|
ESP_LOGW(TAG, "Ring Buffer Full");
|
||||||
|
uart_flush_input(esp_dte->uart_port);
|
||||||
|
xQueueReset(esp_dte->event_queue);
|
||||||
|
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_handle_uart_pattern(esp_dte);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "unknown uart event type: %d", event.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Drive the event loop */
|
||||||
|
esp_event_loop_run(esp_dte->event_loop_hdl, pdMS_TO_TICKS(0));
|
||||||
|
}
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send command to DCE
|
||||||
|
*
|
||||||
|
* @param dte Modem DTE object
|
||||||
|
* @param command command string
|
||||||
|
* @param timeout timeout value, unit: ms
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dte_send_cmd(esp_modem_dte_t *dte, const char *command, uint32_t timeout)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
esp_modem_dce_t *dce = dte->dce;
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "DTE has not yet bind with DCE", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(command, "command is NULL", err);
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
/* Calculate timeout clock tick */
|
||||||
|
/* Reset runtime information */
|
||||||
|
dce->state = ESP_MODEM_STATE_PROCESSING;
|
||||||
|
/* Send command via UART */
|
||||||
|
uart_write_bytes(esp_dte->uart_port, command, strlen(command));
|
||||||
|
/* Check timeout */
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(esp_dte->process_group, (ESP_MODEM_COMMAND_BIT|ESP_MODEM_STOP_BIT), pdTRUE, pdFALSE, pdMS_TO_TICKS(timeout));
|
||||||
|
ESP_MODEM_ERR_CHECK(bits&ESP_MODEM_COMMAND_BIT, "process command timeout", err);
|
||||||
|
ret = ESP_OK;
|
||||||
|
err:
|
||||||
|
dce->handle_line = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send data to DCE
|
||||||
|
*
|
||||||
|
* @param dte Modem DTE object
|
||||||
|
* @param data data buffer
|
||||||
|
* @param length length of data to send
|
||||||
|
* @return int actual length of data that has been send out
|
||||||
|
*/
|
||||||
|
static int esp_modem_dte_send_data(esp_modem_dte_t *dte, const char *data, uint32_t length)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(data, "data is NULL", err);
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
if (esp_dte->parent.dce->mode == ESP_MODEM_TRANSITION_MODE) {
|
||||||
|
ESP_LOGD(TAG, "Not sending data in transition mode");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("esp-modem-dte: ppp_output", data, length, ESP_LOG_VERBOSE);
|
||||||
|
|
||||||
|
return uart_write_bytes(esp_dte->uart_port, data, length);
|
||||||
|
err:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send data and wait for prompt from DCE
|
||||||
|
*
|
||||||
|
* @param dte Modem DTE object
|
||||||
|
* @param data data buffer
|
||||||
|
* @param length length of data to send
|
||||||
|
* @param prompt pointer of specific prompt
|
||||||
|
* @param timeout timeout value (unit: ms)
|
||||||
|
* @return esp_err_t
|
||||||
|
* ESP_OK on success
|
||||||
|
* ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dte_send_wait(esp_modem_dte_t *dte, const char *data, uint32_t length,
|
||||||
|
const char *prompt, uint32_t timeout)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(data, "data is NULL", err_param);
|
||||||
|
ESP_MODEM_ERR_CHECK(prompt, "prompt is NULL", err_param);
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
// We'd better disable pattern detection here for a moment in case prompt string contains the pattern character
|
||||||
|
uart_disable_pattern_det_intr(esp_dte->uart_port);
|
||||||
|
// uart_disable_rx_intr(esp_dte->uart_port);
|
||||||
|
ESP_MODEM_ERR_CHECK(uart_write_bytes(esp_dte->uart_port, data, length) >= 0, "uart write bytes failed", err_write);
|
||||||
|
uint32_t len = strlen(prompt);
|
||||||
|
uint8_t *buffer = calloc(len + 1, sizeof(uint8_t));
|
||||||
|
int res = uart_read_bytes(esp_dte->uart_port, buffer, len, pdMS_TO_TICKS(timeout));
|
||||||
|
ESP_MODEM_ERR_CHECK(res >= len, "wait prompt [%s] timeout", err, prompt);
|
||||||
|
ESP_MODEM_ERR_CHECK(!strncmp(prompt, (const char *)buffer, len), "get wrong prompt: %s", err, buffer);
|
||||||
|
free(buffer);
|
||||||
|
uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
free(buffer);
|
||||||
|
err_write:
|
||||||
|
uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
||||||
|
err_param:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change Modem's working mode
|
||||||
|
*
|
||||||
|
* @param dte Modem DTE object
|
||||||
|
* @param new_mode new working mode
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dte_change_mode(esp_modem_dte_t *dte, esp_modem_mode_t new_mode)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t *dce = dte->dce;
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "DTE has not yet bind with DCE", err);
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->mode != new_mode, "already in mode: %d", err, new_mode);
|
||||||
|
esp_modem_mode_t current_mode = dce->mode;
|
||||||
|
ESP_MODEM_ERR_CHECK(current_mode != new_mode, "already in mode: %d", err, new_mode);
|
||||||
|
dce->mode = ESP_MODEM_TRANSITION_MODE; // mode switching will be finished in set_working_mode() on success
|
||||||
|
// (or restored on failure)
|
||||||
|
switch (new_mode) {
|
||||||
|
case ESP_MODEM_PPP_MODE:
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err_restore_mode, new_mode);
|
||||||
|
uart_disable_pattern_det_intr(esp_dte->uart_port);
|
||||||
|
uart_set_rx_full_threshold(esp_dte->uart_port, 64);
|
||||||
|
uart_enable_rx_intr(esp_dte->uart_port);
|
||||||
|
break;
|
||||||
|
case ESP_MODEM_COMMAND_MODE:
|
||||||
|
ESP_MODEM_ERR_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err_restore_mode, new_mode);
|
||||||
|
uart_disable_rx_intr(esp_dte->uart_port);
|
||||||
|
uart_flush(esp_dte->uart_port);
|
||||||
|
uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
||||||
|
uart_pattern_queue_reset(esp_dte->uart_port, esp_dte->pattern_queue_size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
err_restore_mode:
|
||||||
|
dce->mode = current_mode;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t esp_modem_dte_process_cmd_done(esp_modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
EventBits_t bits = xEventGroupSetBits(esp_dte->process_group, ESP_MODEM_COMMAND_BIT);
|
||||||
|
return bits & ESP_MODEM_STOP_BIT ? ESP_FAIL : ESP_OK; // report error if the group indicated MODEM_STOP condition
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinitialize a Modem DTE object
|
||||||
|
*
|
||||||
|
* @param dte Modem DTE object
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_dte_deinit(esp_modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
/* Clear the start bit */
|
||||||
|
xEventGroupClearBits(esp_dte->process_group, ESP_MODEM_START_BIT);
|
||||||
|
/* Delete UART event task */
|
||||||
|
vTaskDelete(esp_dte->uart_event_task_hdl);
|
||||||
|
/* Delete semaphore */
|
||||||
|
vEventGroupDelete(esp_dte->process_group);
|
||||||
|
/* Delete event loop */
|
||||||
|
esp_event_loop_delete(esp_dte->event_loop_hdl);
|
||||||
|
/* Uninstall UART Driver */
|
||||||
|
uart_driver_delete(esp_dte->uart_port);
|
||||||
|
/* Free memory */
|
||||||
|
free(esp_dte->buffer);
|
||||||
|
if (dte->dce) {
|
||||||
|
dte->dce->dte = NULL;
|
||||||
|
}
|
||||||
|
free(esp_dte);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create and init Modem DTE object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
esp_modem_dte_t *esp_modem_dte_new(const esp_modem_dte_config_t *config)
|
||||||
|
{
|
||||||
|
esp_err_t res;
|
||||||
|
/* malloc memory for esp_dte object */
|
||||||
|
esp_modem_dte_internal_t *esp_dte = calloc(1, sizeof(esp_modem_dte_internal_t));
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_dte, "calloc esp_dte failed", err_dte_mem);
|
||||||
|
/* malloc memory to storing lines from modem dce */
|
||||||
|
esp_dte->line_buffer_size = config->line_buffer_size;
|
||||||
|
esp_dte->buffer = calloc(1, config->line_buffer_size);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_dte->buffer, "calloc line memory failed", err_line_mem);
|
||||||
|
/* Set attributes */
|
||||||
|
esp_dte->uart_port = config->port_num;
|
||||||
|
esp_dte->parent.flow_ctrl = config->flow_control;
|
||||||
|
/* Bind methods */
|
||||||
|
esp_dte->parent.send_cmd = esp_modem_dte_send_cmd;
|
||||||
|
esp_dte->parent.send_data = esp_modem_dte_send_data;
|
||||||
|
esp_dte->parent.send_wait = esp_modem_dte_send_wait;
|
||||||
|
esp_dte->parent.change_mode = esp_modem_dte_change_mode;
|
||||||
|
esp_dte->parent.process_cmd_done = esp_modem_dte_process_cmd_done;
|
||||||
|
esp_dte->parent.deinit = esp_modem_dte_deinit;
|
||||||
|
|
||||||
|
/* Config UART */
|
||||||
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = config->baud_rate,
|
||||||
|
.data_bits = config->data_bits,
|
||||||
|
.parity = config->parity,
|
||||||
|
.stop_bits = config->stop_bits,
|
||||||
|
.source_clk = UART_SCLK_REF_TICK,
|
||||||
|
.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE
|
||||||
|
};
|
||||||
|
ESP_MODEM_ERR_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config);
|
||||||
|
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||||
|
res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
|
||||||
|
config->rts_io_num, config->cts_io_num);
|
||||||
|
} else {
|
||||||
|
res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
|
||||||
|
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||||
|
}
|
||||||
|
ESP_MODEM_ERR_CHECK(res == ESP_OK, "config uart gpio failed", err_uart_config);
|
||||||
|
/* Set flow control threshold */
|
||||||
|
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||||
|
res = uart_set_hw_flow_ctrl(esp_dte->uart_port, 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(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8);
|
||||||
|
}
|
||||||
|
ESP_MODEM_ERR_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config);
|
||||||
|
/* Install UART driver and get event queue used inside driver */
|
||||||
|
res = uart_driver_install(esp_dte->uart_port, config->rx_buffer_size, config->tx_buffer_size,
|
||||||
|
config->event_queue_size, &(esp_dte->event_queue), 0);
|
||||||
|
ESP_MODEM_ERR_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config);
|
||||||
|
res = uart_set_rx_timeout(esp_dte->uart_port, 1);
|
||||||
|
ESP_MODEM_ERR_CHECK(res == ESP_OK, "set rx timeout failed", err_uart_config);
|
||||||
|
|
||||||
|
/* Set pattern interrupt, used to detect the end of a line. */
|
||||||
|
res = uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
|
||||||
|
/* Set pattern queue size */
|
||||||
|
esp_dte->pattern_queue_size = config->pattern_queue_size;
|
||||||
|
res |= uart_pattern_queue_reset(esp_dte->uart_port, config->pattern_queue_size);
|
||||||
|
/* Starting in command mode -> explicitly disable RX interrupt */
|
||||||
|
uart_disable_rx_intr(esp_dte->uart_port);
|
||||||
|
uart_set_rx_full_threshold(esp_dte->uart_port, 64);
|
||||||
|
|
||||||
|
ESP_MODEM_ERR_CHECK(res == ESP_OK, "config uart pattern failed", err_uart_pattern);
|
||||||
|
/* Create Event loop */
|
||||||
|
esp_event_loop_args_t loop_args = {
|
||||||
|
.queue_size = ESP_MODEM_EVENT_QUEUE_SIZE,
|
||||||
|
.task_name = NULL
|
||||||
|
};
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_event_loop_create(&loop_args, &esp_dte->event_loop_hdl) == ESP_OK, "create event loop failed", err_eloop);
|
||||||
|
/* Create semaphore */
|
||||||
|
esp_dte->process_group = xEventGroupCreate();
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_dte->process_group, "create process semaphore failed", err_sem);
|
||||||
|
/* Create UART Event task */
|
||||||
|
BaseType_t ret = xTaskCreate(uart_event_task_entry, //Task Entry
|
||||||
|
"uart_event", //Task Name
|
||||||
|
config->event_task_stack_size, //Task Stack Size(Bytes)
|
||||||
|
esp_dte, //Task Parameter
|
||||||
|
config->event_task_priority, //Task Priority
|
||||||
|
& (esp_dte->uart_event_task_hdl) //Task Handler
|
||||||
|
);
|
||||||
|
ESP_MODEM_ERR_CHECK(ret == pdTRUE, "create uart event task failed", err_tsk_create);
|
||||||
|
return &(esp_dte->parent);
|
||||||
|
/* Error handling */
|
||||||
|
err_tsk_create:
|
||||||
|
vEventGroupDelete(esp_dte->process_group);
|
||||||
|
err_sem:
|
||||||
|
esp_event_loop_delete(esp_dte->event_loop_hdl);
|
||||||
|
err_eloop:
|
||||||
|
uart_disable_pattern_det_intr(esp_dte->uart_port);
|
||||||
|
err_uart_pattern:
|
||||||
|
uart_driver_delete(esp_dte->uart_port);
|
||||||
|
err_uart_config:
|
||||||
|
free(esp_dte->buffer);
|
||||||
|
err_line_mem:
|
||||||
|
free(esp_dte);
|
||||||
|
err_dte_mem:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_dte_set_params(esp_modem_dte_t *dte, const esp_modem_dte_config_t *config)
|
||||||
|
{
|
||||||
|
esp_modem_dte_internal_t *esp_dte = __containerof(dte, esp_modem_dte_internal_t, parent);
|
||||||
|
return uart_set_baudrate(esp_dte->uart_port, config->baud_rate);
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -12,30 +12,34 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "esp_netif_ppp.h"
|
|
||||||
#include "esp_modem.h"
|
#include "esp_modem.h"
|
||||||
|
#include "esp_modem_netif.h"
|
||||||
|
#include "esp_modem_dte.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_netif_ppp.h"
|
||||||
|
|
||||||
|
|
||||||
static const char *TAG = "esp-modem-netif";
|
static const char *TAG = "esp-modem-netif";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ESP32 Modem handle to be used as netif IO object
|
* @brief ESP32 Modem handle to be used as netif IO object
|
||||||
*/
|
*/
|
||||||
typedef struct esp_modem_netif_driver_s {
|
struct esp_modem_netif_driver_s {
|
||||||
esp_netif_driver_base_t base; /*!< base structure reserved as esp-netif driver */
|
esp_netif_driver_base_t base; /*!< base structure reserved as esp-netif driver */
|
||||||
modem_dte_t *dte; /*!< ptr to the esp_modem objects (DTE) */
|
esp_modem_dte_t *dte; /*!< ptr to the esp_modem objects (DTE) */
|
||||||
} esp_modem_netif_driver_t;
|
};
|
||||||
|
|
||||||
static void on_ppp_changed(void *arg, esp_event_base_t event_base,
|
static void on_ppp_changed(void *arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void *event_data)
|
int32_t event_id, void *event_data)
|
||||||
{
|
{
|
||||||
modem_dte_t *dte = arg;
|
esp_modem_dte_t *dte = arg;
|
||||||
if (event_id < NETIF_PP_PHASE_OFFSET) {
|
if (event_id < NETIF_PP_PHASE_OFFSET) {
|
||||||
ESP_LOGI(TAG, "PPP state changed event %d", event_id);
|
ESP_LOGI(TAG, "PPP state changed event %d", event_id);
|
||||||
// only notify the modem on state/error events, ignoring phase transitions
|
// only notify the modem on state/error events, ignoring phase transitions
|
||||||
esp_modem_notify_ppp_netif_closed(dte);
|
esp_modem_notify_ppp_netif_closed(dte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Transmit function called from esp_netif to output network stack data
|
* @brief Transmit function called from esp_netif to output network stack data
|
||||||
*
|
*
|
||||||
@ -49,7 +53,7 @@ static void on_ppp_changed(void *arg, esp_event_base_t event_base,
|
|||||||
*/
|
*/
|
||||||
static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len)
|
static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len)
|
||||||
{
|
{
|
||||||
modem_dte_t *dte = h;
|
esp_modem_dte_t *dte = h;
|
||||||
if (dte->send_data(dte, (const char *)buffer, len) > 0) {
|
if (dte->send_data(dte, (const char *)buffer, len) > 0) {
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@ -66,10 +70,10 @@ static esp_err_t esp_modem_dte_transmit(void *h, void *buffer, size_t len)
|
|||||||
*
|
*
|
||||||
* @return ESP_OK on success, modem-start error code if starting failed
|
* @return ESP_OK on success, modem-start error code if starting failed
|
||||||
*/
|
*/
|
||||||
static esp_err_t esp_modem_post_attach_start(esp_netif_t * esp_netif, void * args)
|
static esp_err_t esp_modem_post_attach_init(esp_netif_t * esp_netif, void * args)
|
||||||
{
|
{
|
||||||
esp_modem_netif_driver_t *driver = args;
|
esp_modem_netif_driver_t *driver = args;
|
||||||
modem_dte_t *dte = driver->dte;
|
esp_modem_dte_t *dte = driver->dte;
|
||||||
const esp_netif_driver_ifconfig_t driver_ifconfig = {
|
const esp_netif_driver_ifconfig_t driver_ifconfig = {
|
||||||
.driver_free_rx_buffer = NULL,
|
.driver_free_rx_buffer = NULL,
|
||||||
.transmit = esp_modem_dte_transmit,
|
.transmit = esp_modem_dte_transmit,
|
||||||
@ -77,16 +81,28 @@ static esp_err_t esp_modem_post_attach_start(esp_netif_t * esp_netif, void * arg
|
|||||||
};
|
};
|
||||||
driver->base.netif = esp_netif;
|
driver->base.netif = esp_netif;
|
||||||
ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig));
|
ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig));
|
||||||
|
// check if PPP error events are enabled, if not, do enable the error occurred/state changed
|
||||||
// enable both events, so we could notify the modem layer if an error occurred/state changed
|
// to notify the modem layer when switching modes
|
||||||
esp_netif_ppp_config_t ppp_config = {
|
esp_netif_ppp_config_t ppp_config;
|
||||||
.ppp_error_event_enabled = true,
|
esp_netif_ppp_get_params(esp_netif, &ppp_config);
|
||||||
.ppp_phase_event_enabled = true
|
if (!ppp_config.ppp_error_event_enabled) {
|
||||||
};
|
ppp_config.ppp_error_event_enabled = true;
|
||||||
esp_netif_ppp_set_params(esp_netif, &ppp_config);
|
esp_netif_ppp_set_params(esp_netif, &ppp_config);
|
||||||
|
}
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, dte));
|
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, dte));
|
||||||
return esp_modem_start_ppp(dte);
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Post attach adapter for esp-modem with autostart functionality
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static esp_err_t esp_modem_post_attach_start(esp_netif_t * esp_netif, void * args)
|
||||||
|
{
|
||||||
|
esp_modem_netif_driver_t *driver = args;
|
||||||
|
ESP_ERROR_CHECK(esp_modem_post_attach_init(esp_netif, args));
|
||||||
|
return esp_modem_start_ppp(driver->dte);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,7 +121,17 @@ static esp_err_t modem_netif_receive_cb(void *buffer, size_t len, void *context)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *esp_modem_netif_setup(modem_dte_t *dte)
|
esp_modem_netif_driver_t *esp_modem_netif_new(esp_modem_dte_t *dte)
|
||||||
|
{
|
||||||
|
esp_modem_netif_driver_t *driver = esp_modem_netif_setup(dte);
|
||||||
|
if (driver) {
|
||||||
|
driver->base.post_attach = esp_modem_post_attach_init;
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_modem_netif_driver_t *esp_modem_netif_setup(esp_modem_dte_t *dte)
|
||||||
{
|
{
|
||||||
esp_modem_netif_driver_t *driver = calloc(1, sizeof(esp_modem_netif_driver_t));
|
esp_modem_netif_driver_t *driver = calloc(1, sizeof(esp_modem_netif_driver_t));
|
||||||
if (driver == NULL) {
|
if (driver == NULL) {
|
||||||
@ -126,13 +152,18 @@ drv_create_failed:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void esp_modem_netif_teardown(void *h)
|
void esp_modem_netif_destroy(esp_modem_netif_driver_t *driver)
|
||||||
|
{
|
||||||
|
esp_netif_destroy(driver->base.netif);
|
||||||
|
return esp_modem_netif_teardown(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp_modem_netif_teardown(esp_modem_netif_driver_t *driver)
|
||||||
{
|
{
|
||||||
esp_modem_netif_driver_t *driver = h;
|
|
||||||
free(driver);
|
free(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_netif_clear_default_handlers(void *h)
|
esp_err_t esp_modem_netif_clear_default_handlers(esp_modem_netif_driver_t *h)
|
||||||
{
|
{
|
||||||
esp_modem_netif_driver_t *driver = h;
|
esp_modem_netif_driver_t *driver = h;
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
@ -152,7 +183,7 @@ clear_event_failed:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_modem_netif_set_default_handlers(void *h, esp_netif_t * esp_netif)
|
esp_err_t esp_modem_netif_set_default_handlers(esp_modem_netif_driver_t *h, esp_netif_t * esp_netif)
|
||||||
{
|
{
|
||||||
esp_modem_netif_driver_t *driver = h;
|
esp_modem_netif_driver_t *driver = h;
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
136
esp_modem/src/esp_modem_recov_helper.c
Normal file
136
esp_modem/src/esp_modem_recov_helper.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "esp_modem_recov_helper.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
static const char *TAG = "esp_modem_recov_helper";
|
||||||
|
|
||||||
|
static void pulse_destroy(esp_modem_recov_gpio_t *pin)
|
||||||
|
{
|
||||||
|
free(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void retry_destroy(esp_modem_recov_resend_t *retry)
|
||||||
|
{
|
||||||
|
free(retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pulse_special(esp_modem_recov_gpio_t * pin, int active_width_ms, int inactive_width_ms)
|
||||||
|
{
|
||||||
|
gpio_set_level(pin->gpio_num, !pin->inactive_level);
|
||||||
|
esp_modem_wait_ms(active_width_ms);
|
||||||
|
gpio_set_level(pin->gpio_num, pin->inactive_level);
|
||||||
|
esp_modem_wait_ms(inactive_width_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pulse(esp_modem_recov_gpio_t * pin)
|
||||||
|
{
|
||||||
|
gpio_set_level(pin->gpio_num, !pin->inactive_level);
|
||||||
|
esp_modem_wait_ms(pin->active_width_ms);
|
||||||
|
gpio_set_level(pin->gpio_num, pin->inactive_level);
|
||||||
|
esp_modem_wait_ms(pin->inactive_width_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t esp_modem_retry_run(esp_modem_recov_resend_t * retry, void *param, void *result)
|
||||||
|
{
|
||||||
|
esp_modem_dce_t *dce = retry->dce;
|
||||||
|
int errors = 0;
|
||||||
|
int timeouts = 0;
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
while (timeouts <= retry->retries_after_timeout &&
|
||||||
|
errors <= retry->retries_after_error) {
|
||||||
|
if (timeouts || errors) {
|
||||||
|
// provide recovery action based on the defined strategy
|
||||||
|
if (retry->recover(retry, err, timeouts, errors) != ESP_OK) {
|
||||||
|
// fail the retry mechanism once the recovery fails
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (retry->command) {
|
||||||
|
ESP_LOGD(TAG, "%s(%d): executing:%s...", __func__, __LINE__, retry->command );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the command
|
||||||
|
err = retry->orig_cmd(dce, param, result);
|
||||||
|
|
||||||
|
// Check for timeout
|
||||||
|
if (err == ESP_ERR_TIMEOUT) {
|
||||||
|
if (retry->command) {
|
||||||
|
ESP_LOGW(TAG, "%s(%d): Command:%s response timeout", __func__, __LINE__, retry->command);
|
||||||
|
}
|
||||||
|
timeouts++;
|
||||||
|
continue;
|
||||||
|
// Check for errors
|
||||||
|
} else if (err != ESP_OK) {
|
||||||
|
if (retry->command) {
|
||||||
|
ESP_LOGW(TAG, "%s(%d): Command:%s failed", __func__, __LINE__, retry->command);
|
||||||
|
}
|
||||||
|
errors++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
if (retry->command) {
|
||||||
|
ESP_LOGD(TAG, "%s(%d): Command:%s succeeded", __func__, __LINE__, retry->command);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_modem_recov_resend_t *esp_modem_recov_resend_new(esp_modem_dce_t *dce, dce_command_t orig_cmd, esp_modem_retry_fn_t recover, int max_timeouts, int max_errors)
|
||||||
|
{
|
||||||
|
esp_modem_recov_resend_t * retry = calloc(1, sizeof(esp_modem_recov_resend_t));
|
||||||
|
ESP_MODEM_ERR_CHECK(retry, "failed to allocate pin structure", err);
|
||||||
|
retry->retries_after_error = max_errors;
|
||||||
|
retry->retries_after_timeout = max_timeouts;
|
||||||
|
retry->orig_cmd = orig_cmd;
|
||||||
|
retry->recover = recover;
|
||||||
|
retry->destroy = retry_destroy;
|
||||||
|
retry->dce = dce;
|
||||||
|
retry->run = esp_modem_retry_run;
|
||||||
|
return retry;
|
||||||
|
err:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_modem_recov_gpio_t *esp_modem_recov_gpio_new(int gpio_num, int inactive_level, int active_width_ms, int inactive_width_ms)
|
||||||
|
{
|
||||||
|
gpio_config_t io_config = {
|
||||||
|
.pin_bit_mask = BIT64(gpio_num),
|
||||||
|
.mode = GPIO_MODE_OUTPUT
|
||||||
|
};
|
||||||
|
gpio_config(&io_config);
|
||||||
|
gpio_set_level(gpio_num, inactive_level);
|
||||||
|
gpio_set_level(gpio_num, inactive_level);
|
||||||
|
|
||||||
|
esp_modem_recov_gpio_t * pin = calloc(1, sizeof(esp_modem_recov_gpio_t));
|
||||||
|
ESP_MODEM_ERR_CHECK(pin, "failed to allocate pin structure", err);
|
||||||
|
|
||||||
|
pin->inactive_level = inactive_level;
|
||||||
|
pin->active_width_ms = active_width_ms;
|
||||||
|
pin->inactive_width_ms = inactive_width_ms;
|
||||||
|
pin->gpio_num = gpio_num;
|
||||||
|
pin->pulse = pulse;
|
||||||
|
pin->pulse_special = pulse_special;
|
||||||
|
pin->destroy = pulse_destroy;
|
||||||
|
return pin;
|
||||||
|
err:
|
||||||
|
return NULL;
|
||||||
|
}
|
104
esp_modem/src/esp_sim7600.c
Normal file
104
esp_modem/src/esp_sim7600.c
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_modem_dce_common_commands.h"
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This module supports SIM7600 module, which has a very similar interface
|
||||||
|
* to the BG96, so it just references most of the handlers from BG96 and implements
|
||||||
|
* only those that differ.
|
||||||
|
*/
|
||||||
|
static const char *TAG = "sim7600";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle response from AT+CBC
|
||||||
|
*/
|
||||||
|
static esp_err_t sim7600_handle_cbc(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, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
} else if (!strncmp(line, "+CBC", strlen("+CBC"))) {
|
||||||
|
esp_modem_dce_cbc_ctx_t *cbc = dce->handle_line_ctx;
|
||||||
|
int32_t volts = 0, fraction = 0;
|
||||||
|
/* +CBC: <voltage in Volts> V*/
|
||||||
|
sscanf(line, "+CBC: %d.%dV", &volts, &fraction);
|
||||||
|
/* Since the "read_battery_status()" API (besides voltage) returns also values for BCS, BCL (charge status),
|
||||||
|
* which are not applicable to this modem, we return -1 to indicate invalid value
|
||||||
|
*/
|
||||||
|
cbc->bcs = -1; // BCS
|
||||||
|
cbc->bcl = -1; // BCL
|
||||||
|
cbc->battery_status = volts*1000 + fraction;
|
||||||
|
err = ESP_OK;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get battery status
|
||||||
|
*
|
||||||
|
* @param dce Modem DCE object
|
||||||
|
* @param bcs Battery charge status
|
||||||
|
* @param bcl Battery connection level
|
||||||
|
* @param voltage Battery voltage
|
||||||
|
* @return esp_err_t
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
static esp_err_t sim7600_get_battery_status(esp_modem_dce_t *dce, void *p, void *r)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "AT+CBC\r", 20000,
|
||||||
|
sim7600_handle_cbc, r);
|
||||||
|
}
|
||||||
|
static esp_err_t sim7600_handle_power_down(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_NO_CARRIER)) {
|
||||||
|
err = ESP_OK;
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t sim7600_power_down(esp_modem_dce_t *dce, void *p, void *r)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, " AT+CPOF\r", MODEM_COMMAND_TIMEOUT_POWEROFF,
|
||||||
|
sim7600_handle_power_down, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_modem_sim7600_specific_init(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "failed to specific init with zero dce", err_params);
|
||||||
|
if (dce->config.populate_command_list) {
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_set_default_command_list(dce) == ESP_OK, "esp_modem_dce_set_default_commands failed", err);
|
||||||
|
|
||||||
|
/* Update some commands which differ from the defaults */
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_command_list_set_cmd(dce, "power_down", sim7600_power_down) == ESP_OK, "esp_modem_dce_set_command failed", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(
|
||||||
|
esp_modem_command_list_set_cmd(dce, "get_battery_status", sim7600_get_battery_status) == ESP_OK, "esp_modem_dce_set_command failed", err);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
err_params:
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
96
esp_modem/src/esp_sim800.c
Normal file
96
esp_modem/src/esp_sim800.c
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_modem_dce_common_commands.h"
|
||||||
|
#include "esp_modem_internal.h"
|
||||||
|
|
||||||
|
static const char *TAG = "esp_sim800";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @brief Response to the SIM800 specific power-down command
|
||||||
|
*/
|
||||||
|
static esp_err_t sim800_handle_power_down(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (strstr(line, "POWER DOWN")) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Response to the SIM800 specific data mode command
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static esp_err_t sim800_handle_atd_ppp(esp_modem_dce_t *dce, const char *line)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (strstr(line, MODEM_RESULT_CODE_CONNECT)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
|
||||||
|
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
|
||||||
|
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set data mode specific to SIM800
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static esp_err_t sim800_set_data_mode(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "ATD*99##\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE,
|
||||||
|
sim800_handle_atd_ppp, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specific power down command to SMI800
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static esp_err_t sim800_power_down(esp_modem_dce_t *dce, void *param, void *result)
|
||||||
|
{
|
||||||
|
return esp_modem_dce_generic_command(dce, "AT+CPOWD=1\r", MODEM_COMMAND_TIMEOUT_POWEROFF,
|
||||||
|
sim800_handle_power_down, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static esp_err_t sim800_start_up(esp_modem_dce_t* dce)
|
||||||
|
{
|
||||||
|
if (esp_modem_dce_default_start_up(dce) != ESP_OK) {
|
||||||
|
esp_modem_wait_ms(30000); // SIM800 wakes-up 30s after sending a command
|
||||||
|
}
|
||||||
|
return esp_modem_dce_default_start_up(dce);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t esp_modem_sim800_specific_init(esp_modem_dce_t *dce)
|
||||||
|
{
|
||||||
|
ESP_MODEM_ERR_CHECK(dce, "failed to specific init with zero dce", err_params);
|
||||||
|
/* Update some commands which differ from the defaults */
|
||||||
|
if (dce->config.populate_command_list) {
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_command_list_set_cmd(dce, "set_data_mode", sim800_set_data_mode) == ESP_OK, "esp_modem_dce_set_command failed", err);
|
||||||
|
ESP_MODEM_ERR_CHECK(esp_modem_command_list_set_cmd(dce, "power_down", sim800_power_down) == ESP_OK, "esp_modem_dce_set_command failed", err);
|
||||||
|
} else {
|
||||||
|
dce->set_data_mode = sim800_set_data_mode;
|
||||||
|
}
|
||||||
|
dce->start_up = sim800_start_up;
|
||||||
|
return ESP_OK;
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
err_params:
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
@ -1,90 +0,0 @@
|
|||||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "bg96.h"
|
|
||||||
#include "bg96_private.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This module supports SIM7600 module, which has a very similar interface
|
|
||||||
* to the BG96, so it just references most of the handlers from BG96 and implements
|
|
||||||
* only those that differ.
|
|
||||||
*/
|
|
||||||
static const char *DCE_TAG = "sim7600";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CBC
|
|
||||||
*/
|
|
||||||
static esp_err_t sim7600_handle_cbc(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
|
|
||||||
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, "+CBC", strlen("+CBC"))) {
|
|
||||||
/* store value of bcs, bcl, voltage */
|
|
||||||
int32_t **cbc = bg96_dce->priv_resource;
|
|
||||||
int32_t volts = 0, fraction = 0;
|
|
||||||
/* +CBC: <voltage in Volts> V*/
|
|
||||||
sscanf(line, "+CBC: %d.%dV", &volts, &fraction);
|
|
||||||
/* Since the "read_battery_status()" API (besides voltage) returns also values for BCS, BCL (charge status),
|
|
||||||
* which are not applicable to this modem, we return -1 to indicate invalid value
|
|
||||||
*/
|
|
||||||
*cbc[0] = -1; // BCS
|
|
||||||
*cbc[1] = -1; // BCL
|
|
||||||
*cbc[2] = volts*1000 + fraction;
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get battery status
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param bcs Battery charge status
|
|
||||||
* @param bcl Battery connection level
|
|
||||||
* @param voltage Battery voltage
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim7600_get_battery_status(modem_dce_t *dce, uint32_t *bcs, uint32_t *bcl, uint32_t *voltage)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
bg96_modem_dce_t *bg96_dce = __containerof(dce, bg96_modem_dce_t, parent);
|
|
||||||
uint32_t *resource[3] = {bcs, bcl, voltage};
|
|
||||||
bg96_dce->priv_resource = resource;
|
|
||||||
dce->handle_line = sim7600_handle_cbc;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CBC\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire battery status failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "inquire battery status ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create and initialize SIM7600 object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
modem_dce_t *sim7600_init(modem_dte_t *dte)
|
|
||||||
{
|
|
||||||
modem_dce_t *dce = bg96_init(dte);
|
|
||||||
dte->dce->get_battery_status = sim7600_get_battery_status;
|
|
||||||
return dce;
|
|
||||||
}
|
|
@ -1,492 +0,0 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_modem_dce_service.h"
|
|
||||||
#include "sim800.h"
|
|
||||||
|
|
||||||
#define MODEM_RESULT_CODE_POWERDOWN "POWER DOWN"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Macro defined for error checking
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static const char *DCE_TAG = "sim800";
|
|
||||||
#define DCE_CHECK(a, str, goto_tag, ...) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (!(a)) \
|
|
||||||
{ \
|
|
||||||
ESP_LOGE(DCE_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
|
||||||
goto goto_tag; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief SIM800 Modem
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
void *priv_resource; /*!< Private resource */
|
|
||||||
modem_dce_t parent; /*!< DCE parent class */
|
|
||||||
} sim800_modem_dce_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CSQ
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_csq(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
|
|
||||||
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, "+CSQ", strlen("+CSQ"))) {
|
|
||||||
/* store value of rssi and ber */
|
|
||||||
uint32_t **csq = sim800_dce->priv_resource;
|
|
||||||
/* +CSQ: <rssi>,<ber> */
|
|
||||||
sscanf(line, "%*s%d,%d", csq[0], csq[1]);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CBC
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_cbc(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
|
|
||||||
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, "+CBC", strlen("+CBC"))) {
|
|
||||||
/* store value of bcs, bcl, voltage */
|
|
||||||
uint32_t **cbc = sim800_dce->priv_resource;
|
|
||||||
/* +CBC: <bcs>,<bcl>,<voltage> */
|
|
||||||
sscanf(line, "%*s%d,%d,%d", cbc[0], cbc[1], cbc[2]);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from +++
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_exit_data_mode(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_NO_CARRIER)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from ATD*99#
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_atd_ppp(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
if (strstr(line, MODEM_RESULT_CODE_CONNECT)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CGMM
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_cgmm(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 {
|
|
||||||
int len = snprintf(dce->name, MODEM_MAX_NAME_LENGTH, "%s", line);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->name, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CGSN
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_cgsn(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 {
|
|
||||||
int len = snprintf(dce->imei, MODEM_IMEI_LENGTH + 1, "%s", line);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->imei, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CIMI
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_cimi(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 {
|
|
||||||
int len = snprintf(dce->imsi, MODEM_IMSI_LENGTH + 1, "%s", line);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->imsi, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+COPS?
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_cops(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, "+COPS", strlen("+COPS"))) {
|
|
||||||
/* there might be some random spaces in operator's name, we can not use sscanf to parse the result */
|
|
||||||
/* strtok will break the string, we need to create a copy */
|
|
||||||
size_t len = strlen(line);
|
|
||||||
char *line_copy = malloc(len + 1);
|
|
||||||
strcpy(line_copy, line);
|
|
||||||
/* +COPS: <mode>[, <format>[, <oper>]] */
|
|
||||||
char *str_ptr = NULL;
|
|
||||||
char *p[3];
|
|
||||||
uint8_t i = 0;
|
|
||||||
/* strtok will broke string by replacing delimiter with '\0' */
|
|
||||||
p[i] = strtok_r(line_copy, ",", &str_ptr);
|
|
||||||
while (p[i]) {
|
|
||||||
p[++i] = strtok_r(NULL, ",", &str_ptr);
|
|
||||||
}
|
|
||||||
if (i >= 3) {
|
|
||||||
int len = snprintf(dce->oper, MODEM_MAX_OPERATOR_LENGTH, "%s", p[2]);
|
|
||||||
if (len > 2) {
|
|
||||||
/* Strip "\r\n" */
|
|
||||||
strip_cr_lf_tail(dce->oper, len);
|
|
||||||
err = ESP_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(line_copy);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle response from AT+CPOWD=1
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_handle_power_down(modem_dce_t *dce, const char *line)
|
|
||||||
{
|
|
||||||
esp_err_t err = ESP_FAIL;
|
|
||||||
if (strstr(line, MODEM_RESULT_CODE_POWERDOWN)) {
|
|
||||||
err = esp_modem_process_command_done(dce, MODEM_STATE_SUCCESS);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get signal quality
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param rssi received signal strength indication
|
|
||||||
* @param ber bit error ratio
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_get_signal_quality(modem_dce_t *dce, uint32_t *rssi, uint32_t *ber)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
|
|
||||||
uint32_t *resource[2] = {rssi, ber};
|
|
||||||
sim800_dce->priv_resource = resource;
|
|
||||||
dce->handle_line = sim800_handle_csq;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CSQ\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire signal quality failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "inquire signal quality ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get battery status
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param bcs Battery charge status
|
|
||||||
* @param bcl Battery connection level
|
|
||||||
* @param voltage Battery voltage
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_get_battery_status(modem_dce_t *dce, uint32_t *bcs, uint32_t *bcl, uint32_t *voltage)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
|
|
||||||
uint32_t *resource[3] = {bcs, bcl, voltage};
|
|
||||||
sim800_dce->priv_resource = resource;
|
|
||||||
dce->handle_line = sim800_handle_cbc;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CBC\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "inquire battery status failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "inquire battery status ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set Working Mode
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @param mode woking mode
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_set_working_mode(modem_dce_t *dce, modem_mode_t mode)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
switch (mode) {
|
|
||||||
case MODEM_COMMAND_MODE:
|
|
||||||
dce->handle_line = sim800_handle_exit_data_mode;
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000)); // spec: 1s delay for the modem to recognize the escape sequence
|
|
||||||
if (dte->send_cmd(dte, "+++", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) != ESP_OK) {
|
|
||||||
// "+++" Could fail if we are already in the command mode.
|
|
||||||
// in that case we ignore the timout and re-sync the modem
|
|
||||||
ESP_LOGI(DCE_TAG, "Sending \"+++\" command failed");
|
|
||||||
dce->handle_line = esp_modem_dce_handle_response_default;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "sync failed", err);
|
|
||||||
} else {
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter command mode failed", err);
|
|
||||||
}
|
|
||||||
ESP_LOGD(DCE_TAG, "enter command mode ok");
|
|
||||||
dce->mode = MODEM_COMMAND_MODE;
|
|
||||||
break;
|
|
||||||
case MODEM_PPP_MODE:
|
|
||||||
dce->handle_line = sim800_handle_atd_ppp;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "ATD*99#\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
|
|
||||||
if (dce->state != MODEM_STATE_SUCCESS) {
|
|
||||||
// Initiate PPP mode could fail, if we've already "dialed" the data call before.
|
|
||||||
// in that case we retry with "ATO" to just resume the data mode
|
|
||||||
ESP_LOGD(DCE_TAG, "enter ppp mode failed, retry with ATO");
|
|
||||||
dce->handle_line = sim800_handle_atd_ppp;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "ATO\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter ppp mode failed", err);
|
|
||||||
}
|
|
||||||
ESP_LOGD(DCE_TAG, "enter ppp mode ok");
|
|
||||||
dce->mode = MODEM_PPP_MODE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGW(DCE_TAG, "unsupported working mode: %d", mode);
|
|
||||||
goto err;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Power down
|
|
||||||
*
|
|
||||||
* @param sim800_dce sim800 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_power_down(modem_dce_t *dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = dce->dte;
|
|
||||||
dce->handle_line = sim800_handle_power_down;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CPOWD=1\r", MODEM_COMMAND_TIMEOUT_POWEROFF) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "power down failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "power down ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get DCE module name
|
|
||||||
*
|
|
||||||
* @param sim800_dce sim800 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_get_module_name(sim800_modem_dce_t *sim800_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = sim800_dce->parent.dte;
|
|
||||||
sim800_dce->parent.handle_line = sim800_handle_cgmm;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CGMM\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get module name failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get module name ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get DCE module IMEI number
|
|
||||||
*
|
|
||||||
* @param sim800_dce sim800 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_get_imei_number(sim800_modem_dce_t *sim800_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = sim800_dce->parent.dte;
|
|
||||||
sim800_dce->parent.handle_line = sim800_handle_cgsn;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CGSN\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get imei number failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get imei number ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get DCE module IMSI number
|
|
||||||
*
|
|
||||||
* @param sim800_dce sim800 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_get_imsi_number(sim800_modem_dce_t *sim800_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = sim800_dce->parent.dte;
|
|
||||||
sim800_dce->parent.handle_line = sim800_handle_cimi;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+CIMI\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get imsi number failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get imsi number ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get Operator's name
|
|
||||||
*
|
|
||||||
* @param sim800_dce sim800 object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on error
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_get_operator_name(sim800_modem_dce_t *sim800_dce)
|
|
||||||
{
|
|
||||||
modem_dte_t *dte = sim800_dce->parent.dte;
|
|
||||||
sim800_dce->parent.handle_line = sim800_handle_cops;
|
|
||||||
DCE_CHECK(dte->send_cmd(dte, "AT+COPS?\r", MODEM_COMMAND_TIMEOUT_OPERATOR) == ESP_OK, "send command failed", err);
|
|
||||||
DCE_CHECK(sim800_dce->parent.state == MODEM_STATE_SUCCESS, "get network operator failed", err);
|
|
||||||
ESP_LOGD(DCE_TAG, "get network operator ok");
|
|
||||||
return ESP_OK;
|
|
||||||
err:
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Deinitialize SIM800 object
|
|
||||||
*
|
|
||||||
* @param dce Modem DCE object
|
|
||||||
* @return esp_err_t
|
|
||||||
* - ESP_OK on success
|
|
||||||
* - ESP_FAIL on fail
|
|
||||||
*/
|
|
||||||
static esp_err_t sim800_deinit(modem_dce_t *dce)
|
|
||||||
{
|
|
||||||
sim800_modem_dce_t *sim800_dce = __containerof(dce, sim800_modem_dce_t, parent);
|
|
||||||
if (dce->dte) {
|
|
||||||
dce->dte->dce = NULL;
|
|
||||||
}
|
|
||||||
free(sim800_dce);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
modem_dce_t *sim800_init(modem_dte_t *dte)
|
|
||||||
{
|
|
||||||
DCE_CHECK(dte, "DCE should bind with a DTE", err);
|
|
||||||
/* malloc memory for sim800_dce object */
|
|
||||||
sim800_modem_dce_t *sim800_dce = calloc(1, sizeof(sim800_modem_dce_t));
|
|
||||||
DCE_CHECK(sim800_dce, "calloc sim800_dce failed", err);
|
|
||||||
/* Bind DTE with DCE */
|
|
||||||
sim800_dce->parent.dte = dte;
|
|
||||||
dte->dce = &(sim800_dce->parent);
|
|
||||||
/* Bind methods */
|
|
||||||
sim800_dce->parent.handle_line = NULL;
|
|
||||||
sim800_dce->parent.sync = esp_modem_dce_sync;
|
|
||||||
sim800_dce->parent.echo_mode = esp_modem_dce_echo;
|
|
||||||
sim800_dce->parent.store_profile = esp_modem_dce_store_profile;
|
|
||||||
sim800_dce->parent.set_flow_ctrl = esp_modem_dce_set_flow_ctrl;
|
|
||||||
sim800_dce->parent.define_pdp_context = esp_modem_dce_define_pdp_context;
|
|
||||||
sim800_dce->parent.hang_up = esp_modem_dce_hang_up;
|
|
||||||
sim800_dce->parent.get_signal_quality = sim800_get_signal_quality;
|
|
||||||
sim800_dce->parent.get_battery_status = sim800_get_battery_status;
|
|
||||||
sim800_dce->parent.set_working_mode = sim800_set_working_mode;
|
|
||||||
sim800_dce->parent.power_down = sim800_power_down;
|
|
||||||
sim800_dce->parent.deinit = sim800_deinit;
|
|
||||||
/* Sync between DTE and DCE */
|
|
||||||
DCE_CHECK(esp_modem_dce_sync(&(sim800_dce->parent)) == ESP_OK, "sync failed", err_io);
|
|
||||||
/* Close echo */
|
|
||||||
DCE_CHECK(esp_modem_dce_echo(&(sim800_dce->parent), false) == ESP_OK, "close echo mode failed", err_io);
|
|
||||||
/* Get Module name */
|
|
||||||
DCE_CHECK(sim800_get_module_name(sim800_dce) == ESP_OK, "get module name failed", err_io);
|
|
||||||
/* Get IMEI number */
|
|
||||||
DCE_CHECK(sim800_get_imei_number(sim800_dce) == ESP_OK, "get imei failed", err_io);
|
|
||||||
/* Get IMSI number */
|
|
||||||
DCE_CHECK(sim800_get_imsi_number(sim800_dce) == ESP_OK, "get imsi failed", err_io);
|
|
||||||
/* Get operator name */
|
|
||||||
DCE_CHECK(sim800_get_operator_name(sim800_dce) == ESP_OK, "get operator name failed", err_io);
|
|
||||||
return &(sim800_dce->parent);
|
|
||||||
err_io:
|
|
||||||
free(sim800_dce);
|
|
||||||
err:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
Reference in New Issue
Block a user