fix(modem): Use generated AT command definitions for IDE navigation

BREAKING CHANGE: inc headers for AT command definitions are no longer used directly, but pregenerated into *.h(pp)
This commit is contained in:
David Cermak
2024-11-01 17:32:02 +01:00
parent d2e94e5db2
commit e2fa11103c
47 changed files with 4839 additions and 560 deletions

View File

@@ -1,7 +1,13 @@
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
set(command_dir "generate")
else()
set(command_dir "command")
endif()
idf_component_register(SRCS "modem_console_main.cpp"
"console_helper.cpp"
"my_module_dce.cpp"
"${command_dir}/my_module_dce.cpp"
"httpget_handle.c"
"ping_handle.c"
REQUIRES console esp_http_client nvs_flash
INCLUDE_DIRS ".")
INCLUDE_DIRS "." "${command_dir}")

View File

@@ -0,0 +1,510 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* Modem console example: Custom DCE
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <cstring>
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
//#include "generate/esp_modem_command_declare.inc"
#include "my_module_dce.hpp"
using namespace esp_modem;
//
// Define preprocessor's forwarding to dce_commands definitions
//
//
// Repeat all declarations and forward to the AT commands defined in esp_modem::dce_commands:: namespace
//
//DECLARE_ALL_COMMAND_APIS(return_type name(...) )
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::sync()
{
return esp_modem::dce_commands::sync(this);
}
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_operator_name(std::string &name, int &act)
{
return esp_modem::dce_commands::get_operator_name(this, name, act);
}
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::store_profile()
{
return esp_modem::dce_commands::store_profile(this);
}
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_pin(const std::string &pin)
{
return esp_modem::dce_commands::set_pin(this, pin);
}
/**
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
* @param[in] cmd String command that's send to DTE
* @param[out] out Raw output from DTE
* @param[in] pass Pattern in response for the API to return OK
* @param[in] fail Pattern in response for the API to return FAIL
* @param[in] timeout AT command timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout)
{
return esp_modem::dce_commands::at_raw(this, cmd, out, pass, fail, timeout);
}
/**
* @brief Execute the supplied AT command
* @param[in] cmd AT command
* @param[out] out Command output string
* @param[in] timeout AT command timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::at(const std::string &cmd, std::string &out, int timeout)
{
return esp_modem::dce_commands::at(this, cmd, out, timeout);
}
/**
* @brief Checks if the SIM needs a PIN
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::read_pin(bool &pin_ok)
{
return esp_modem::dce_commands::read_pin(this, pin_ok);
}
/**
* @brief Sets echo mode
* @param[in] echo_on true if echo mode on (repeats the commands)
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_echo(const bool echo_on)
{
return esp_modem::dce_commands::set_echo(this, echo_on);
}
/**
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
* @param[in] txt true if txt mode
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::sms_txt_mode(const bool txt)
{
return esp_modem::dce_commands::sms_txt_mode(this, txt);
}
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::sms_character_set()
{
return esp_modem::dce_commands::sms_character_set(this);
}
/**
* @brief Sends SMS message in txt mode
* @param[in] number Phone number to send the message to
* @param[in] message Text message to be sent
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::send_sms(const std::string &number, const std::string &message)
{
return esp_modem::dce_commands::send_sms(this, number, message);
}
/**
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::resume_data_mode()
{
return esp_modem::dce_commands::resume_data_mode(this);
}
/**
* @brief Sets php context
* @param[in] p1 PdP context struct to setup modem cellular connection
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_pdp_context(PdpContext &pdp)
{
return esp_modem::dce_commands::set_pdp_context(this, pdp);
}
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_command_mode()
{
return esp_modem::dce_commands::set_command_mode(this);
}
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_cmux()
{
return esp_modem::dce_commands::set_cmux(this);
}
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_imsi(std::string &imsi)
{
return esp_modem::dce_commands::get_imsi(this, imsi);
}
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_imei(std::string &imei)
{
return esp_modem::dce_commands::get_imei(this, imei);
}
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_module_name(std::string &name)
{
return esp_modem::dce_commands::get_module_name(this, name);
}
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_data_mode()
{
return esp_modem::dce_commands::set_data_mode(this);
}
/**
* @brief Get Signal quality
* @param[out] rssi signal strength indication
* @param[out] ber channel bit error rate
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_signal_quality(int &rssi, int &ber)
{
return esp_modem::dce_commands::get_signal_quality(this, rssi, ber);
}
/**
* @brief Sets HW control flow
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_flow_control(int dce_flow, int dte_flow)
{
return esp_modem::dce_commands::set_flow_control(this, dce_flow, dte_flow);
}
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::hang_up()
{
return esp_modem::dce_commands::hang_up(this);
}
/**
* @brief Get voltage levels of modem power up circuitry
* @param[out] voltage Current status in mV
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
* @param[out] bcl 1-100% battery capacity, -1-Not available
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_battery_status(int &voltage, int &bcs, int &bcl)
{
return esp_modem::dce_commands::get_battery_status(this, voltage, bcs, bcl);
}
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::power_down()
{
return esp_modem::dce_commands::power_down(this);
}
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::reset()
{
return esp_modem::dce_commands::reset(this);
}
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_baud(int baud)
{
return esp_modem::dce_commands::set_baud(this, baud);
}
/**
* @brief Force an attempt to connect to a specific operator
* @param[in] mode mode of attempt
* mode=0 - automatic
* mode=1 - manual
* mode=2 - deregister
* mode=3 - set format for read operation
* mode=4 - manual with fallback to automatic
* @param[in] format what format the operator is given in
* format=0 - long format
* format=1 - short format
* format=2 - numeric
* @param[in] oper the operator to connect to
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_operator(int mode, int format, const std::string &oper)
{
return esp_modem::dce_commands::set_operator(this, mode, format, oper);
}
/**
* @brief Attach or detach from the GPRS service
* @param[in] state 1-attach 0-detach
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_network_attachment_state(int state)
{
return esp_modem::dce_commands::set_network_attachment_state(this, state);
}
/**
* @brief Get network attachment state
* @param[out] state 1-attached 0-detached
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_network_attachment_state(int &state)
{
return esp_modem::dce_commands::get_network_attachment_state(this, state);
}
/**
* @brief What mode the radio should be set to
* @param[in] state state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_radio_state(int state)
{
return esp_modem::dce_commands::set_radio_state(this, state);
}
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_radio_state(int &state)
{
return esp_modem::dce_commands::get_radio_state(this, state);
}
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_network_mode(int mode)
{
return esp_modem::dce_commands::set_network_mode(this, mode);
}
/**
* @brief Preferred network mode (CAT-M and/or NB-IoT)
* @param[in] mode preferred selection
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_preferred_mode(int mode)
{
return esp_modem::dce_commands::set_preferred_mode(this, mode);
}
/**
* @brief Set network bands for CAT-M or NB-IoT
* @param[in] mode CAT-M or NB-IoT
* @param[in] bands bitmap in hex representing bands
* @param[in] size size of teh bands bitmap
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_network_bands(const std::string &mode, const int *bands, int size)
{
return esp_modem::dce_commands::set_network_bands(this, mode, bands, size);
}
/**
* @brief Show network system mode
* @param[out] mode current network mode
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_network_system_mode(int &mode)
{
return esp_modem::dce_commands::get_network_system_mode(this, mode);
}
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::set_gnss_power_mode(int mode)
{
return esp_modem::dce_commands::set_gnss_power_mode(this, mode);
}
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::get_gnss_power_mode(int &mode)
{
return esp_modem::dce_commands::get_gnss_power_mode(this, mode);
}
/**
* @brief Configure PSM
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::config_psm(int mode, const std::string &tau, const std::string &active_time)
{
return esp_modem::dce_commands::config_psm(this, mode, tau, active_time);
}
/**
* @brief Configure CEREG urc
* @param[in] value
* value = 0 - Disable network URC
* value = 1 - Enable network URC
* value = 2 - Enable network URC with location information
* value = 3 - Enable network URC with location information and EMM cause
* value = 4 - Enable network URC with location information and PSM value
* value = 5 - Enable network URC with location information and PSM value, EMM cause
*/
command_result Shiny::DCE::config_network_registration_urc(int value)
{
return esp_modem::dce_commands::config_network_registration_urc(this, value);
}
/**
* @brief Gets the current network registration state
* @param[out] state The current network registration state
* state = 0 - Not registered, MT is not currently searching an operator to register to
* state = 1 - Registered, home network
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
* state = 3 - Registration denied
* state = 4 - Unknown
* state = 5 - Registered, Roaming
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
* state = 8 - Attached for emergency bearer services only
* state = 9 - Registered for CSFB not preferred, home network
* state = 10 - Registered for CSFB not preferred, roaming
*/
command_result Shiny::DCE::get_network_registration_state(int &state)
{
return esp_modem::dce_commands::get_network_registration_state(this, state);
}
/**
* @brief Configures the mobile termination error (+CME ERROR)
* @param[in] mode The form of the final result code
* mode = 0 - Disable, use and send ERROR instead
* mode = 1 - Enable, use numeric error values
* mode = 2 - Enable, result code and use verbose error values
*/
command_result Shiny::DCE::config_mobile_termination_error(int mode)
{
return esp_modem::dce_commands::config_mobile_termination_error(this, mode);
}
/**
* @brief Configure eDRX
* @param[in] mode
* mode = 0 - Disable
* mode = 1 - Enable
* mode = 2 - Enable + URC
* mode = 3 - Disable + Reset parameter.
* @param[in] access_technology
* act = 0 - ACT is not using eDRX (used in URC)
* act = 1 - EC-GSM-IoT (A/Gb mode)
* act = 2 - GSM (A/Gb mode)
* act = 3 - UTRAN (Iu mode)
* act = 4 - E-UTRAN (WB-S1 mode)
* act = 5 - E-UTRAN (NB-S1 mode)
* @param[in] edrx_value nible string containing encoded eDRX time
* @param[in] ptw_value nible string containing encoded Paging Time Window
*/
command_result Shiny::DCE::config_edrx(int mode, int access_technology, const std::string &edrx_value)
{
return esp_modem::dce_commands::config_edrx(this, mode, access_technology, edrx_value);
}
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
{
return Shiny::Factory::create(config, std::move(dte), netif);
}
/**
* @brief Definition of the command API, which makes the Shiny::DCE "command-able class"
* @param cmd Command to send
* @param got_line Recv line callback
* @param time_ms timeout in ms
* @param separator line break separator
* @return OK, FAIL or TIMEOUT
*/
command_result Shiny::DCE::command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms, const char separator)
{
if (!handling_urc) {
return dte->command(cmd, got_line, time_ms, separator);
}
handle_cmd = got_line;
signal.clear((1) | (2));
esp_modem::DTE_Command command{cmd};
dte->write(command);
signal.wait_any((1) | (2), time_ms);
handle_cmd = nullptr;
if (signal.is_any((1))) {
return esp_modem::command_result::OK;
}
if (signal.is_any((2))) {
return esp_modem::command_result::FAIL;
}
return esp_modem::command_result::TIMEOUT;
}
/**
* @brief Handle received data
*
* @param data Data received from the device
* @param len Length of the data
* @return standard command return code (OK|FAIL|TIMEOUT)
*/
command_result Shiny::DCE::handle_data(uint8_t *data, size_t len)
{
if (std::memchr(data, '\n', len)) {
if (handle_urc) {
handle_urc(data, len);
}
if (handle_cmd) {
auto ret = handle_cmd(data, len);
if (ret == esp_modem::command_result::TIMEOUT) {
return command_result::TIMEOUT;
}
if (ret == esp_modem::command_result::OK) {
signal.set((1));
}
if (ret == esp_modem::command_result::FAIL) {
signal.set((2));
}
}
}
return command_result::TIMEOUT;
}

View File

@@ -0,0 +1,381 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/*
* Modem console example: Custom DCE
*/
#pragma once
#include <utility>
#include "cxx_include/esp_modem_dce_factory.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
/**
* @brief Definition of a custom DCE uses GenericModule and all its methods
* but could override command processing. Here, for demonstration purposes only,
* we "inject" URC handler to the actual command processing.
* This is possible since we inherit from `CommandableIf` and redefine `command()` method.
* Then we're able to use declare all common methods from the command library
* to be processed using "our" `command()` method (with custom URC handler).
*/
namespace Shiny {
using namespace esp_modem;
class DCE : public esp_modem::DCE_T<GenericModule>, public CommandableIf {
public:
using DCE_T<GenericModule>::DCE_T;
command_result
command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms) override
{
return command(cmd, got_line, time_ms, '\n');
}
command_result
command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms, const char separator) override;
int write(uint8_t *data, size_t len) override
{
return dte->write(data, len);
}
void on_read(got_line_cb on_data) override
{
return dte->on_read(on_data);
}
// DECLARE_ALL_COMMAND_APIS(forwards name(...))
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result sync();
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_operator_name(std::string &name, int &act);
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result store_profile();
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_pin(const std::string &pin);
/**
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
* @param[in] cmd String command that's send to DTE
* @param[out] out Raw output from DTE
* @param[in] pass Pattern in response for the API to return OK
* @param[in] fail Pattern in response for the API to return FAIL
* @param[in] timeout AT command timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout);
/**
* @brief Execute the supplied AT command
* @param[in] cmd AT command
* @param[out] out Command output string
* @param[in] timeout AT command timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result at(const std::string &cmd, std::string &out, int timeout);
/**
* @brief Checks if the SIM needs a PIN
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result read_pin(bool &pin_ok);
/**
* @brief Sets echo mode
* @param[in] echo_on true if echo mode on (repeats the commands)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_echo(const bool echo_on);
/**
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
* @param[in] txt true if txt mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result sms_txt_mode(const bool txt);
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result sms_character_set();
/**
* @brief Sends SMS message in txt mode
* @param[in] number Phone number to send the message to
* @param[in] message Text message to be sent
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result send_sms(const std::string &number, const std::string &message);
/**
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result resume_data_mode();
/**
* @brief Sets php context
* @param[in] p1 PdP context struct to setup modem cellular connection
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_pdp_context(PdpContext &pdp);
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_command_mode();
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_cmux();
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_imsi(std::string &imsi);
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_imei(std::string &imei);
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_module_name(std::string &name);
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_data_mode();
/**
* @brief Get Signal quality
* @param[out] rssi signal strength indication
* @param[out] ber channel bit error rate
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_signal_quality(int &rssi, int &ber);
/**
* @brief Sets HW control flow
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_flow_control(int dce_flow, int dte_flow);
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result hang_up();
/**
* @brief Get voltage levels of modem power up circuitry
* @param[out] voltage Current status in mV
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
* @param[out] bcl 1-100% battery capacity, -1-Not available
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_battery_status(int &voltage, int &bcs, int &bcl);
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result power_down();
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result reset();
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_baud(int baud);
/**
* @brief Force an attempt to connect to a specific operator
* @param[in] mode mode of attempt
* mode=0 - automatic
* mode=1 - manual
* mode=2 - deregister
* mode=3 - set format for read operation
* mode=4 - manual with fallback to automatic
* @param[in] format what format the operator is given in
* format=0 - long format
* format=1 - short format
* format=2 - numeric
* @param[in] oper the operator to connect to
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_operator(int mode, int format, const std::string &oper);
/**
* @brief Attach or detach from the GPRS service
* @param[in] state 1-attach 0-detach
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_network_attachment_state(int state);
/**
* @brief Get network attachment state
* @param[out] state 1-attached 0-detached
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_network_attachment_state(int &state);
/**
* @brief What mode the radio should be set to
* @param[in] state state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_radio_state(int state);
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_radio_state(int &state);
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_network_mode(int mode);
/**
* @brief Preferred network mode (CAT-M and/or NB-IoT)
* @param[in] mode preferred selection
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_preferred_mode(int mode);
/**
* @brief Set network bands for CAT-M or NB-IoT
* @param[in] mode CAT-M or NB-IoT
* @param[in] bands bitmap in hex representing bands
* @param[in] size size of teh bands bitmap
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_network_bands(const std::string &mode, const int *bands, int size);
/**
* @brief Show network system mode
* @param[out] mode current network mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_network_system_mode(int &mode);
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_gnss_power_mode(int mode);
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_gnss_power_mode(int &mode);
/**
* @brief Configure PSM
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result config_psm(int mode, const std::string &tau, const std::string &active_time);
/**
* @brief Configure CEREG urc
* @param[in] value
* value = 0 - Disable network URC
* value = 1 - Enable network URC
* value = 2 - Enable network URC with location information
* value = 3 - Enable network URC with location information and EMM cause
* value = 4 - Enable network URC with location information and PSM value
* value = 5 - Enable network URC with location information and PSM value, EMM cause
*/
esp_modem::command_result config_network_registration_urc(int value);
/**
* @brief Gets the current network registration state
* @param[out] state The current network registration state
* state = 0 - Not registered, MT is not currently searching an operator to register to
* state = 1 - Registered, home network
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
* state = 3 - Registration denied
* state = 4 - Unknown
* state = 5 - Registered, Roaming
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
* state = 8 - Attached for emergency bearer services only
* state = 9 - Registered for CSFB not preferred, home network
* state = 10 - Registered for CSFB not preferred, roaming
*/
esp_modem::command_result get_network_registration_state(int &state);
/**
* @brief Configures the mobile termination error (+CME ERROR)
* @param[in] mode The form of the final result code
* mode = 0 - Disable, use and send ERROR instead
* mode = 1 - Enable, use numeric error values
* mode = 2 - Enable, result code and use verbose error values
*/
esp_modem::command_result config_mobile_termination_error(int mode);
/**
* @brief Configure eDRX
* @param[in] mode
* mode = 0 - Disable
* mode = 1 - Enable
* mode = 2 - Enable + URC
* mode = 3 - Disable + Reset parameter.
* @param[in] access_technology
* act = 0 - ACT is not using eDRX (used in URC)
* act = 1 - EC-GSM-IoT (A/Gb mode)
* act = 2 - GSM (A/Gb mode)
* act = 3 - UTRAN (Iu mode)
* act = 4 - E-UTRAN (WB-S1 mode)
* act = 5 - E-UTRAN (NB-S1 mode)
* @param[in] edrx_value nible string containing encoded eDRX time
* @param[in] ptw_value nible string containing encoded Paging Time Window
*/
esp_modem::command_result config_edrx(int mode, int access_technology, const std::string &edrx_value);
void set_on_read(esp_modem::got_line_cb on_read_cb)
{
if (on_read_cb == nullptr) {
handling_urc = false;
handle_urc = nullptr;
dte->on_read(nullptr);
return;
}
handle_urc = std::move(on_read_cb);
dte->on_read([this](uint8_t *data, size_t len) {
this->handle_data(data, len);
return command_result::TIMEOUT;
});
handling_urc = true;
}
private:
got_line_cb handle_urc{nullptr};
got_line_cb handle_cmd{nullptr};
SignalGroup signal;
bool handling_urc {false};
command_result handle_data(uint8_t *data, size_t len);
};
class Factory: public ::esp_modem::dce_factory::Factory {
public:
static std::unique_ptr<DCE> create(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
{
return build_generic_DCE<GenericModule, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
}
};
} // namespace Shiny
/**
* @brief Helper create method which employs the DCE factory for creating DCE objects templated by a custom module
* @return unique pointer of the resultant DCE
*/
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -15,43 +15,34 @@
#include <cstring>
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "generate/esp_modem_command_declare.inc"
//#include "generate/esp_modem_command_declare.inc"
#include "my_module_dce.hpp"
// --- ESP-MODEM command module starts here ---
using namespace esp_modem;
//
// Define preprocessor's forwarding to dce_commands definitions
//
// Helper macros to handle multiple arguments of declared API
#define ARGS0
#define ARGS1 , p1
#define ARGS2 , p1 , p2
#define ARGS3 , p1 , p2 , p3
#define ARGS4 , p1 , p2 , p3, p4
#define ARGS5 , p1 , p2 , p3, p4, p5
#define ARGS6 , p1 , p2 , p3, p4, p5, p6
#define _ARGS(x) ARGS ## x
#define ARGS(x) _ARGS(x)
#define CMD_OK (1)
#define CMD_FAIL (2)
//
// Repeat all declarations and forward to the AT commands defined in esp_modem::dce_commands:: namespace
//
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, arg_nr, ...) \
return_type Shiny::DCE::name(__VA_ARGS__) { return esp_modem::dce_commands::name(this ARGS(arg_nr) ); }
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
return_type Shiny::DCE::name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__)) { return esp_modem::dce_commands::name(this ESP_MODEM_COMMAND_FORWARD_AFTER(__VA_ARGS__) ); }
DECLARE_ALL_COMMAND_APIS(return_type name(...) )
//DECLARE_ALL_COMMAND_APIS(return_type name(...) )
#include "esp_modem_command_declare.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
{
return Shiny::Factory::create(config, std::move(dte), netif);
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -16,6 +16,7 @@
#include "cxx_include/esp_modem_dce_factory.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
// --- ESP-MODEM command module starts here ---
/**
* @brief Definition of a custom DCE uses GenericModule and all its methods
* but could override command processing. Here, for demonstration purposes only,
@@ -51,10 +52,12 @@ public:
return dte->on_read(on_data);
}
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
esp_modem::return_type name(__VA_ARGS__);
#include "../generate/include/esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
DECLARE_ALL_COMMAND_APIS(forwards name(...))
// DECLARE_ALL_COMMAND_APIS(forwards name(...))
#include "../generate/include/esp_modem_command_declare.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
@@ -103,5 +106,5 @@ public:
* @return unique pointer of the resultant DCE
*/
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif);
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif);

View File

@@ -362,7 +362,8 @@ extern "C" void app_main(void)
});
const ConsoleCommand GetBatteryStatus("get_battery_status", "Reads voltage/battery status", no_args, [&](ConsoleCommand * c) {
int volt, bcl, bcs;
CHECK_ERR(dce->get_battery_status(volt, bcl, bcs), ESP_LOGI(TAG, "OK. volt=%d, bcl=%d, bcs=%d", volt, bcl, bcs));
CHECK_ERR(dce->get_module()->get_battery_status(volt, bcl, bcs), ESP_LOGI(TAG, "OK. volt=%d, bcl=%d, bcs=%d", volt, bcl, bcs));
dce->get_battery_status(volt, bcl, bcs);
});
const ConsoleCommand PowerDown("power_down", "power down the module", no_args, [&](ConsoleCommand * c) {
ESP_LOGI(TAG, "Power down the module...");

View File

@@ -4,8 +4,14 @@ elseif(CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600)
set(device_srcs sock_commands_sim7600.cpp)
endif()
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
set(command_dir "generate")
else()
set(command_dir "command")
endif()
idf_component_register(SRCS "modem_client.cpp"
"sock_dce.cpp"
"${command_dir}/sock_dce.cpp"
"tcp_transport_at.cpp"
"${device_srcs}"
INCLUDE_DIRS ".")
INCLUDE_DIRS "." "${command_dir}")

View File

@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_types.hpp"
namespace sock_commands {
/**
* @brief Opens network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result net_open(esp_modem::CommandableIf *t);
/**
* @brief Closes network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result net_close(esp_modem::CommandableIf *t);
/**
* @brief Opens a TCP connection
* @param[in] host Host name or IP address to connect to
* @param[in] port Port number
* @param[in] timeout Connection timeout
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result tcp_open(esp_modem::CommandableIf *t, const std::string &host, int port, int timeout);
/**
* @brief Closes opened TCP socket
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result tcp_close(esp_modem::CommandableIf *t);
/**
* @brief Gets modem IP address
* @param[out] addr String representation of modem's IP
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_ip(esp_modem::CommandableIf *t, std::string &addr);
/**
* @brief Sets Rx mode
* @param[in] mode 0=auto, 1=manual
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_rx_mode(esp_modem::CommandableIf *t, int mode);
}

View File

@@ -0,0 +1,361 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <charconv>
#include <sys/socket.h>
#include "esp_vfs.h"
#include "esp_vfs_eventfd.h"
#include "sock_dce.hpp"
namespace sock_dce {
constexpr auto const *TAG = "sock_dce";
bool DCE::perform_sock()
{
if (listen_sock == -1) {
ESP_LOGE(TAG, "Listening socket not ready");
close_sock();
return false;
}
if (sock == -1) { // no active socket, need to accept one first
return accept_sock();
}
// we have a socket, let's check the status
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 500000,
};
if (state == status::PENDING) {
vTaskDelay(pdMS_TO_TICKS(500));
state = at.pending();
return true;
}
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
FD_SET(data_ready_fd, &fdset);
int s = select(std::max(sock, data_ready_fd) + 1, &fdset, nullptr, nullptr, &tv);
if (s == 0) {
ESP_LOGV(TAG, "perform select timeout...");
return true;
} else if (s < 0) {
ESP_LOGE(TAG, "select error %d", errno);
close_sock();
return false;
}
if (FD_ISSET(sock, &fdset) && !sock_to_at()) {
return false;
}
if (FD_ISSET(data_ready_fd, &fdset) && !at_to_sock()) {
return false;
}
return true;
}
void DCE::perform_at(uint8_t *data, size_t len)
{
ESP_LOG_BUFFER_HEXDUMP(TAG, data, len, ESP_LOG_VERBOSE);
switch (at.process_data(state, data, len)) {
case Responder::ret::OK:
state = status::IDLE;
signal.set(IDLE);
return;
case Responder::ret::FAIL:
state = status::FAILED;
signal.set(IDLE);
return;
case Responder::ret::NEED_MORE_DATA:
return;
case Responder::ret::IN_PROGRESS:
break;
case Responder::ret::NEED_MORE_TIME:
state = status::PENDING;
return;
}
std::string_view response((char *)data, len);
switch (at.check_async_replies(state, response)) {
case Responder::ret::OK:
state = status::IDLE;
signal.set(IDLE);
return;
case Responder::ret::FAIL:
state = status::FAILED;
signal.set(IDLE);
return;
case Responder::ret::NEED_MORE_TIME:
state = status::PENDING;
return;
case Responder::ret::NEED_MORE_DATA:
case Responder::ret::IN_PROGRESS:
break;
}
}
void DCE::close_sock()
{
if (sock > 0) {
close(sock);
sock = -1;
}
dte->on_read(nullptr);
const int retries = 5;
int i = 0;
while (net_close() != esp_modem::command_result::OK) {
if (i++ > retries) {
ESP_LOGE(TAG, "Failed to close network");
return;
}
esp_modem::Task::Delay(1000);
}
}
bool DCE::at_to_sock()
{
uint64_t data;
read(data_ready_fd, &data, sizeof(data));
ESP_LOGD(TAG, "select read: modem data available %" PRIu64, data);
if (!signal.wait(IDLE, 1000)) {
ESP_LOGE(TAG, "Failed to get idle");
close_sock();
return false;
}
if (state != status::IDLE) {
ESP_LOGE(TAG, "Unexpected state %d", static_cast<int>(state));
close_sock();
return false;
}
state = status::RECEIVING;
at.start_receiving(at.get_buf_len());
return true;
}
bool DCE::sock_to_at()
{
ESP_LOGD(TAG, "socket read: data available");
if (!signal.wait(IDLE, 1000)) {
ESP_LOGE(TAG, "Failed to get idle");
close_sock();
return false;
}
if (state != status::IDLE) {
ESP_LOGE(TAG, "Unexpected state %d", static_cast<int>(state));
close_sock();
return false;
}
state = status::SENDING;
int len = ::recv(sock, at.get_buf(), at.get_buf_len(), 0);
if (len < 0) {
ESP_LOGE(TAG, "read error %d", errno);
close_sock();
return false;
} else if (len == 0) {
ESP_LOGE(TAG, "EOF %d", errno);
close_sock();
return false;
}
ESP_LOG_BUFFER_HEXDUMP(TAG, at.get_buf(), len, ESP_LOG_VERBOSE);
at.start_sending(len);
return true;
}
bool DCE::accept_sock()
{
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 500000,
};
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(listen_sock, &fdset);
int s = select(listen_sock + 1, &fdset, nullptr, nullptr, &tv);
if (s > 0 && FD_ISSET(listen_sock, &fdset)) {
struct sockaddr_in source_addr = {};
socklen_t addr_len = sizeof(source_addr);
sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
return false;
}
ESP_LOGD(TAG, "Socket accepted!");
FD_ZERO(&fdset);
return true;
} else if (s == 0) {
return true;
}
return false;
}
void DCE::start_listening(int port)
{
listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (listen_sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
return;
}
int opt = 1;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
ESP_LOGI(TAG, "Socket created");
struct sockaddr_in addr = { };
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
// inet_aton("127.0.0.1", &addr.sin_addr);
int err = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
return;
}
ESP_LOGI(TAG, "Socket bound, port %d", 1883);
err = listen(listen_sock, 1);
if (err != 0) {
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
return;
}
}
bool DCE::connect(std::string host, int port)
{
dte->on_read(nullptr);
tcp_close();
dte->on_read([this](uint8_t *data, size_t len) {
this->perform_at(data, len);
return esp_modem::command_result::TIMEOUT;
});
if (!at.start_connecting(host, port)) {
ESP_LOGE(TAG, "Unable to start connecting");
dte->on_read(nullptr);
return false;
}
state = status::CONNECTING;
return true;
}
bool DCE::init()
{
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
esp_vfs_eventfd_register(&config);
data_ready_fd = eventfd(0, EFD_SUPPORT_ISR);
assert(data_ready_fd > 0);
dte->on_read(nullptr);
const int retries = 5;
int i = 0;
while (sync() != esp_modem::command_result::OK) {
if (i++ > retries) {
ESP_LOGE(TAG, "Failed to sync up");
return false;
}
esp_modem::Task::Delay(1000);
}
ESP_LOGD(TAG, "Modem in sync");
i = 0;
while (setup_data_mode() != true) {
if (i++ > retries) {
ESP_LOGE(TAG, "Failed to setup pdp/data");
return false;
}
esp_modem::Task::Delay(1000);
}
ESP_LOGD(TAG, "PDP configured");
i = 0;
while (net_open() != esp_modem::command_result::OK) {
if (i++ > retries) {
ESP_LOGE(TAG, "Failed to open network");
return false;
}
net_close();
esp_modem::Task::Delay(1000);
}
ESP_LOGD(TAG, "Network opened");
i = 0;
std::string ip_addr;
while (get_ip(ip_addr) != esp_modem::command_result::OK) {
if (i++ > retries) {
ESP_LOGE(TAG, "Failed obtain an IP address");
return false;
}
esp_modem::Task::Delay(5000);
}
ESP_LOGI(TAG, "Got IP %s", ip_addr.c_str());
return true;
}
class Factory: public ::esp_modem::dce_factory::Factory {
public:
static std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte)
{
return esp_modem::dce_factory::Factory::build_module_T<DCE, std::unique_ptr<DCE>>(config, std::move(dte));
}
};
std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte)
{
return Factory::create(config, std::move(dte));
}
/**
* @brief Opens network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result DCE::net_open()
{
return sock_commands::net_open(dte.get());
}
/**
* @brief Closes network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result DCE::net_close()
{
return sock_commands::net_close(dte.get());
}
/**
* @brief Opens a TCP connection
* @param[in] host Host name or IP address to connect to
* @param[in] port Port number
* @param[in] timeout Connection timeout
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result DCE::tcp_open(const std::string &host, int port, int timeout)
{
return sock_commands::tcp_open(dte.get(), host, port, timeout);
}
/**
* @brief Closes opened TCP socket
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result DCE::tcp_close()
{
return sock_commands::tcp_close(dte.get());
}
/**
* @brief Gets modem IP address
* @param[out] addr String representation of modem's IP
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result DCE::get_ip(std::string &addr)
{
return sock_commands::get_ip(dte.get(), addr);
}
/**
* @brief Sets Rx mode
* @param[in] mode 0=auto, 1=manual
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result DCE::set_rx_mode(int mode)
{
return sock_commands::set_rx_mode(dte.get(), mode);
}
} // namespace sock_dce

View File

@@ -0,0 +1,241 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
#include <cxx_include/esp_modem_dce_factory.hpp>
#include "sock_commands.hpp"
#include <sys/socket.h>
#pragma once
namespace sock_dce {
enum class status {
IDLE,
CONNECTING,
SENDING,
RECEIVING,
FAILED,
PENDING
};
class Responder {
public:
enum class ret {
OK, FAIL, IN_PROGRESS, NEED_MORE_DATA, NEED_MORE_TIME
};
Responder(int &s, int &ready_fd, std::shared_ptr<esp_modem::DTE> &dte_arg):
sock(s), data_ready_fd(ready_fd), dte(dte_arg) {}
ret process_data(status state, uint8_t *data, size_t len);
ret check_async_replies(status state, std::string_view &response);
void start_sending(size_t len);
void start_receiving(size_t len);
bool start_connecting(std::string host, int port);
status pending();
uint8_t *get_buf()
{
return &buffer[0];
}
size_t get_buf_len()
{
return buffer_size;
}
void clear_offsets()
{
actual_read = 0;
}
size_t data_available()
{
return actual_read;
}
size_t has_data()
{
return total_len;
}
private:
static constexpr size_t buffer_size = 512;
bool on_read(char *data, size_t len)
{
#ifndef CONFIG_EXAMPLE_CUSTOM_TCP_TRANSPORT
::send(sock, data, len, 0);
#else
::memcpy(&buffer[actual_read], data, len);
actual_read += len;
#endif
return true;
}
ret recv(uint8_t *data, size_t len);
ret send(uint8_t *data, size_t len);
ret send(std::string_view response);
ret connect(std::string_view response);
void send_cmd(std::string_view command)
{
dte->write((uint8_t *) command.begin(), command.size());
}
std::array<uint8_t, buffer_size> buffer;
size_t data_to_recv = 0;
size_t actual_read = 0;
size_t total_len = 0;
bool read_again = false;
int &sock;
int &data_ready_fd;
int send_stat = 0;
size_t data_to_send = 0;
std::shared_ptr<esp_modem::DTE> &dte;
};
class DCE : public ::esp_modem::GenericModule {
using esp_modem::GenericModule::GenericModule;
public:
/**
* @brief Opens network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result net_open();
/**
* @brief Closes network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result net_close();
/**
* @brief Opens a TCP connection
* @param[in] host Host name or IP address to connect to
* @param[in] port Port number
* @param[in] timeout Connection timeout
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result tcp_open(const std::string &host, int port, int timeout);
/**
* @brief Closes opened TCP socket
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result tcp_close();
/**
* @brief Gets modem IP address
* @param[out] addr String representation of modem's IP
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_ip(std::string &addr);
/**
* @brief Sets Rx mode
* @param[in] mode 0=auto, 1=manual
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_rx_mode(int mode);
bool init();
bool connect(std::string host, int port);
void start_listening(int port);
bool perform_sock();
void set_idle()
{
signal.set(IDLE);
}
bool wait_to_idle(uint32_t ms)
{
if (!signal.wait(IDLE, ms)) {
ESP_LOGE("dce", "Failed to get idle");
return false;
}
if (state != status::IDLE) {
ESP_LOGE("dce", "Unexpected state %d", static_cast<int>(state));
return false;
}
return true;
}
int sync_recv(char *buffer, int len, int timeout_ms)
{
if (!wait_to_idle(timeout_ms)) {
return 0;
}
at.clear_offsets();
state = status::RECEIVING;
uint64_t data;
read(data_ready_fd, &data, sizeof(data));
int max_len = std::min(len, (int)at.get_buf_len());
at.start_receiving(max_len);
if (!signal.wait(IDLE, 500 + timeout_ms)) {
return 0;
}
int ret = at.data_available();
if (ret > 0) {
memcpy(buffer, at.get_buf(), ret);
}
set_idle();
return ret;
}
int sync_send(const char *buffer, size_t len, int timeout_ms)
{
int len_to_send = std::min(len, at.get_buf_len());
if (!wait_to_idle(timeout_ms)) {
return -1;
}
state = status::SENDING;
memcpy(at.get_buf(), buffer, len_to_send);
ESP_LOG_BUFFER_HEXDUMP("dce", at.get_buf(), len, ESP_LOG_VERBOSE);
at.start_sending(len_to_send);
if (!signal.wait(IDLE, timeout_ms + 1000)) {
if (state == status::PENDING) {
state = status::IDLE;
} else {
return -1;
}
}
set_idle();
return len_to_send;
}
int wait_to_read(uint32_t ms)
{
if (at.has_data() > 0) {
ESP_LOGD("dce", "Data buffered in modem (len=%d)", at.has_data());
return 1;
}
struct timeval tv = {
.tv_sec = static_cast<time_t>(ms / 1000),
.tv_usec = 0,
};
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(data_ready_fd, &fdset);
int s = select(data_ready_fd + 1, &fdset, nullptr, nullptr, &tv);
if (s == 0) {
return 0;
} else if (s < 0) {
ESP_LOGE("dce", "select error %d", errno);
return -1;
}
if (FD_ISSET(data_ready_fd, &fdset)) {
ESP_LOGD("dce", "select read: modem data available");
return 1;
}
return -1;
}
private:
esp_modem::SignalGroup signal;
void close_sock();
bool accept_sock();
bool sock_to_at();
bool at_to_sock();
void perform_at(uint8_t *data, size_t len);
status state{status::IDLE};
static constexpr uint8_t IDLE = 1;
Responder at{sock, data_ready_fd, dte};
int sock {-1};
int listen_sock {-1};
int data_ready_fd {-1};
};
std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte);
}

View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_types.hpp"
namespace sock_commands {
// --- ESP-MODEM command module starts here ---
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
esp_modem::return_type name(esp_modem::CommandableIf *t ESP_MODEM_COMMAND_PARAMS_AFTER(__VA_ARGS__));
#include "socket_commands.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -304,23 +304,13 @@ std::unique_ptr<DCE> create(const esp_modem::dce_config *config, std::shared_ptr
return Factory::create(config, std::move(dte));
}
// Helper macros to handle multiple arguments of declared API
#define ARGS0
#define ARGS1 , p1
#define ARGS2 , p1 , p2
#define ARGS3 , p1 , p2 , p3
#define EXPAND_ARGS(x) ARGS ## x
#define ARGS(x) EXPAND_ARGS(x)
//
// Repeat all declarations and forward to the AT commands defined in ::sock_commands namespace
//
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, arg_nr, ...) \
esp_modem::return_type DCE::name(__VA_ARGS__) { return sock_commands::name(dte.get() ARGS(arg_nr) ); }
DECLARE_SOCK_COMMANDS(return_type name(...) )
// --- ESP-MODEM command module starts here ---
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
esp_modem::return_type DCE::name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__)) { return sock_commands::name(dte.get() ESP_MODEM_COMMAND_FORWARD_AFTER(__VA_ARGS__) ); }
#include "socket_commands.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
} // namespace sock_dce

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -7,7 +7,6 @@
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
#include <cxx_include/esp_modem_dce_factory.hpp>
#include "socket_commands.inc"
#include "sock_commands.hpp"
#include <sys/socket.h>
@@ -102,11 +101,12 @@ class DCE : public ::esp_modem::GenericModule {
using esp_modem::GenericModule::GenericModule;
public:
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
esp_modem::return_type name(__VA_ARGS__);
DECLARE_SOCK_COMMANDS(declare name(Commandable *p, ...);)
// --- ESP-MODEM command module starts here ---
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
#include "socket_commands.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
bool init();

View File

@@ -0,0 +1,40 @@
/**
* @brief Opens network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
ESP_MODEM_DECLARE_DCE_COMMAND(net_open, command_result)
/**
* @brief Closes network in AT command mode
* @return OK, FAIL or TIMEOUT
*/
ESP_MODEM_DECLARE_DCE_COMMAND(net_close, command_result)
/**
* @brief Opens a TCP connection
* @param[in] host Host name or IP address to connect to
* @param[in] port Port number
* @param[in] timeout Connection timeout
* @return OK, FAIL or TIMEOUT
*/
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_open, command_result, STR_IN(host), INT_IN(port), INT_IN(timeout))
/**
* @brief Closes opened TCP socket
* @return OK, FAIL or TIMEOUT
*/
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_close, command_result)
/**
* @brief Gets modem IP address
* @param[out] addr String representation of modem's IP
* @return OK, FAIL or TIMEOUT
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_ip, command_result, STR_OUT(addr))
/**
* @brief Sets Rx mode
* @param[in] mode 0=auto, 1=manual
* @return OK, FAIL or TIMEOUT
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_rx_mode, command_result, INT_IN(mode))

View File

@@ -1,23 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_types.hpp"
#include "socket_commands.inc"
namespace sock_commands {
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
esp_modem::return_type name(esp_modem::CommandableIf *t, ## __VA_ARGS__);
DECLARE_SOCK_COMMANDS(declare name(Commandable *p, ...);)
#undef ESP_MODEM_DECLARE_DCE_COMMAND
}

View File

@@ -1,58 +0,0 @@
// Copyright 2021-2022 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
#include "generate/esp_modem_command_declare_helper.inc"
#define DECLARE_SOCK_COMMANDS(...) \
/**
* @brief Opens network in AT command mode
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(net_open, command_result, 0) \
\
/**
* @brief Closes network in AT command mode
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(net_close, command_result, 0) \
\
/**
* @brief Opens a TCP connection
* @param[in] host Host name or IP address to connect to
* @param[in] port Port number
* @param[in] timeout Connection timeout
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_open, command_result, 3, STRING_IN(p1, host), INT_IN(p2, port), INT_IN(p3, timeout)) \
\
/**
* @brief Closes opened TCP socket
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(tcp_close, command_result, 0) \
\
/**
* @brief Gets modem IP address
* @param[out] addr String representation of modem's IP
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_ip, command_result, 1, STRING_OUT(p1, addr)) \
\
/**
* @brief Sets Rx mode
* @param[in] mode 0=auto, 1=manual
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_rx_mode, command_result, 1, INT_IN(p1, mode))

View File

@@ -1,5 +1,11 @@
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
set(command_dir "generate")
else()
set(command_dir "command")
endif()
idf_component_register(SRCS "SIM7070_gnss.cpp"
INCLUDE_DIRS "."
INCLUDE_DIRS "." "${command_dir}"
PRIV_REQUIRES esp_modem)
set_target_properties(${COMPONENT_LIB} PROPERTIES

View File

@@ -0,0 +1,474 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
//
// Created on: 23.08.2022
// Author: franz
#pragma once
#include "cxx_include/esp_modem_dce_factory.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_types.hpp"
#include "sim70xx_gps.h"
using PdpContext = esp_modem::PdpContext;
/**
* @brief Definition of a custom SIM7070 class with GNSS capabilities.
* This inherits from the official esp-modem's SIM7070 device which contains all common library methods.
* On top of that, the SIM7070_gnss adds reading GNSS information, which is implemented in a private component.
*/
class SIM7070_gnss: public esp_modem::SIM7070 {
using SIM7070::SIM7070;
public:
esp_modem::command_result get_gnss_information_sim70xx(sim70xx_gps_t &gps);
};
/**
* @brief DCE for the SIM7070_gnss. Here we've got to forward the general commands, aa well as the GNSS one.
*/
class DCE_gnss : public esp_modem::DCE_T<SIM7070_gnss> {
public:
using DCE_T<SIM7070_gnss>::DCE_T;
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result sync()
{
return device->sync();
}
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_operator_name(std::string &name, int &act)
{
return device->get_operator_name(name, act);
}
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result store_profile()
{
return device->store_profile();
}
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_pin(const std::string &pin)
{
return device->set_pin(pin);
}
/**
* @brief Execute the supplied AT command in raw mode (doesn't append '\r' to command, returns everything)
* @param[in] cmd String command that's send to DTE
* @param[out] out Raw output from DTE
* @param[in] pass Pattern in response for the API to return OK
* @param[in] fail Pattern in response for the API to return FAIL
* @param[in] timeout AT command timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result at_raw(const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout)
{
return device->at_raw(cmd, out, pass, fail, timeout);
}
/**
* @brief Execute the supplied AT command
* @param[in] cmd AT command
* @param[out] out Command output string
* @param[in] timeout AT command timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result at(const std::string &cmd, std::string &out, int timeout)
{
return device->at(cmd, out, timeout);
}
/**
* @brief Checks if the SIM needs a PIN
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result read_pin(bool &pin_ok)
{
return device->read_pin(pin_ok);
}
/**
* @brief Sets echo mode
* @param[in] echo_on true if echo mode on (repeats the commands)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_echo(const bool echo_on)
{
return device->set_echo(echo_on);
}
/**
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
* @param[in] txt true if txt mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result sms_txt_mode(const bool txt)
{
return device->sms_txt_mode(txt);
}
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result sms_character_set()
{
return device->sms_character_set();
}
/**
* @brief Sends SMS message in txt mode
* @param[in] number Phone number to send the message to
* @param[in] message Text message to be sent
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result send_sms(const std::string &number, const std::string &message)
{
return device->send_sms(number, message);
}
/**
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result resume_data_mode()
{
return device->resume_data_mode();
}
/**
* @brief Sets php context
* @param[in] p1 PdP context struct to setup modem cellular connection
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_pdp_context(PdpContext &pdp)
{
return device->set_pdp_context(pdp);
}
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_command_mode()
{
return device->set_command_mode();
}
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_cmux()
{
return device->set_cmux();
}
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_imsi(std::string &imsi)
{
return device->get_imsi(imsi);
}
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_imei(std::string &imei)
{
return device->get_imei(imei);
}
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_module_name(std::string &name)
{
return device->get_module_name(name);
}
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_data_mode()
{
return device->set_data_mode();
}
/**
* @brief Get Signal quality
* @param[out] rssi signal strength indication
* @param[out] ber channel bit error rate
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_signal_quality(int &rssi, int &ber)
{
return device->get_signal_quality(rssi, ber);
}
/**
* @brief Sets HW control flow
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_flow_control(int dce_flow, int dte_flow)
{
return device->set_flow_control(dce_flow, dte_flow);
}
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result hang_up()
{
return device->hang_up();
}
/**
* @brief Get voltage levels of modem power up circuitry
* @param[out] voltage Current status in mV
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
* @param[out] bcl 1-100% battery capacity, -1-Not available
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_battery_status(int &voltage, int &bcs, int &bcl)
{
return device->get_battery_status(voltage, bcs, bcl);
}
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result power_down()
{
return device->power_down();
}
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result reset()
{
return device->reset();
}
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_baud(int baud)
{
return device->set_baud(baud);
}
/**
* @brief Force an attempt to connect to a specific operator
* @param[in] mode mode of attempt
* mode=0 - automatic
* mode=1 - manual
* mode=2 - deregister
* mode=3 - set format for read operation
* mode=4 - manual with fallback to automatic
* @param[in] format what format the operator is given in
* format=0 - long format
* format=1 - short format
* format=2 - numeric
* @param[in] oper the operator to connect to
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_operator(int mode, int format, const std::string &oper)
{
return device->set_operator(mode, format, oper);
}
/**
* @brief Attach or detach from the GPRS service
* @param[in] state 1-attach 0-detach
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_network_attachment_state(int state)
{
return device->set_network_attachment_state(state);
}
/**
* @brief Get network attachment state
* @param[out] state 1-attached 0-detached
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_network_attachment_state(int &state)
{
return device->get_network_attachment_state(state);
}
/**
* @brief What mode the radio should be set to
* @param[in] state state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_radio_state(int state)
{
return device->set_radio_state(state);
}
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_radio_state(int &state)
{
return device->get_radio_state(state);
}
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_network_mode(int mode)
{
return device->set_network_mode(mode);
}
/**
* @brief Preferred network mode (CAT-M and/or NB-IoT)
* @param[in] mode preferred selection
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_preferred_mode(int mode)
{
return device->set_preferred_mode(mode);
}
/**
* @brief Set network bands for CAT-M or NB-IoT
* @param[in] mode CAT-M or NB-IoT
* @param[in] bands bitmap in hex representing bands
* @param[in] size size of teh bands bitmap
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_network_bands(const std::string &mode, const int *bands, int size)
{
return device->set_network_bands(mode, bands, size);
}
/**
* @brief Show network system mode
* @param[out] mode current network mode
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_network_system_mode(int &mode)
{
return device->get_network_system_mode(mode);
}
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result set_gnss_power_mode(int mode)
{
return device->set_gnss_power_mode(mode);
}
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result get_gnss_power_mode(int &mode)
{
return device->get_gnss_power_mode(mode);
}
/**
* @brief Configure PSM
* @param[in] mode psm mode (0 - off, 1 - on, 2 - off & discard stored params)
* @return OK, FAIL or TIMEOUT
*/
esp_modem::command_result config_psm(int mode, const std::string &tau, const std::string &active_time)
{
return device->config_psm(mode, tau, active_time);
}
/**
* @brief Configure CEREG urc
* @param[in] value
* value = 0 - Disable network URC
* value = 1 - Enable network URC
* value = 2 - Enable network URC with location information
* value = 3 - Enable network URC with location information and EMM cause
* value = 4 - Enable network URC with location information and PSM value
* value = 5 - Enable network URC with location information and PSM value, EMM cause
*/
esp_modem::command_result config_network_registration_urc(int value)
{
return device->config_network_registration_urc(value);
}
/**
* @brief Gets the current network registration state
* @param[out] state The current network registration state
* state = 0 - Not registered, MT is not currently searching an operator to register to
* state = 1 - Registered, home network
* state = 2 - Not registered, but MT is currently trying to attach or searching an operator to register to
* state = 3 - Registration denied
* state = 4 - Unknown
* state = 5 - Registered, Roaming
* state = 6 - Registered, for SMS only, home network (NB-IoT only)
* state = 7 - Registered, for SMS only, roaming (NB-IoT only)
* state = 8 - Attached for emergency bearer services only
* state = 9 - Registered for CSFB not preferred, home network
* state = 10 - Registered for CSFB not preferred, roaming
*/
esp_modem::command_result get_network_registration_state(int &state)
{
return device->get_network_registration_state(state);
}
/**
* @brief Configures the mobile termination error (+CME ERROR)
* @param[in] mode The form of the final result code
* mode = 0 - Disable, use and send ERROR instead
* mode = 1 - Enable, use numeric error values
* mode = 2 - Enable, result code and use verbose error values
*/
esp_modem::command_result config_mobile_termination_error(int mode)
{
return device->config_mobile_termination_error(mode);
}
/**
* @brief Configure eDRX
* @param[in] mode
* mode = 0 - Disable
* mode = 1 - Enable
* mode = 2 - Enable + URC
* mode = 3 - Disable + Reset parameter.
* @param[in] access_technology
* act = 0 - ACT is not using eDRX (used in URC)
* act = 1 - EC-GSM-IoT (A/Gb mode)
* act = 2 - GSM (A/Gb mode)
* act = 3 - UTRAN (Iu mode)
* act = 4 - E-UTRAN (WB-S1 mode)
* act = 5 - E-UTRAN (NB-S1 mode)
* @param[in] edrx_value nible string containing encoded eDRX time
* @param[in] ptw_value nible string containing encoded Paging Time Window
*/
esp_modem::command_result config_edrx(int mode, int access_technology, const std::string &edrx_value)
{
return device->config_edrx(mode, access_technology, edrx_value);
}
esp_modem::command_result get_gnss_information_sim70xx(sim70xx_gps_t &gps);
esp_modem::command_result get_operator_name(std::string &name)
{
return device->get_operator_name(name);
}
};
/**
* @brief Helper create method which employs the customized DCE factory for building DCE_gnss objects
* @return unique pointer of the specific DCE
*/
std::unique_ptr<DCE_gnss> create_SIM7070_GNSS_dce(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,8 +13,12 @@
#include "cxx_include/esp_modem_dce_factory.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_types.hpp"
#include "sim70xx_gps.h"
using PdpContext = esp_modem::PdpContext;
/**
* @brief Definition of a custom SIM7070 class with GNSS capabilities.
* This inherits from the official esp-modem's SIM7070 device which contains all common library methods.
@@ -33,22 +37,22 @@ class DCE_gnss : public esp_modem::DCE_T<SIM7070_gnss> {
public:
using DCE_T<SIM7070_gnss>::DCE_T;
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
template <typename ...Agrs> \
esp_modem::return_type name(Agrs&&... args) \
{ \
return device->name(std::forward<Agrs>(args)...); \
}
DECLARE_ALL_COMMAND_APIS(forwards name(...)
{
device->name(...);
} )
// --- ESP-MODEM command module starts here ---
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
esp_modem::return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__)) { return device->name(ESP_MODEM_COMMAND_FORWARD(__VA_ARGS__)); }
#include "esp_modem_command_declare.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
esp_modem::command_result get_gnss_information_sim70xx(sim70xx_gps_t &gps);
esp_modem::command_result get_operator_name(std::string &name)
{
return device->get_operator_name(name);
}
};
@@ -57,5 +61,5 @@ public:
* @return unique pointer of the specific DCE
*/
std::unique_ptr<DCE_gnss> create_SIM7070_GNSS_dce(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif);
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif);

View File

@@ -254,7 +254,7 @@ extern "C" void app_main(void)
#if CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070_GNSS == 1
esp_modem_gps_t gps;
sim70xx_gps_t gps;
for (int i = 0; i < 200; ++i) {
if (dce->get_gnss_information_sim70xx(gps) == esp_modem::command_result::OK) {
@@ -267,7 +267,7 @@ extern "C" void app_main(void)
ESP_LOGI(TAG, "gps.tim.hour %i gps.tim.minute %i gps.tim.second %i gps.tim.thousand %i",
gps.tim.hour, gps.tim.minute, gps.tim.second, gps.tim.thousand);
ESP_LOGI(TAG, "gps.latitude %f gps.longitude %f ",
gps.latitude, gps.longitude );
gps.latitude, gps.longitude);
ESP_LOGI(TAG, "gps.altitude %f",
gps.altitude);
ESP_LOGI(TAG, "gps.speed %f",
@@ -277,9 +277,9 @@ extern "C" void app_main(void)
ESP_LOGI(TAG, "gps.fix_mode %i",
gps.fix_mode);
ESP_LOGI(TAG, "gps.dop_h %f gps.dop_p %f gps.dop_v %f ",
gps.dop_h, gps.dop_p, gps.dop_v );
gps.dop_h, gps.dop_p, gps.dop_v);
ESP_LOGI(TAG, "gps.sats_in_view %i",
gps.sats_in_view);
gps.sat.num);
ESP_LOGI(TAG, "gps.hpa %f gps.vpa %f",
gps.hpa, gps.vpa);
}
@@ -291,10 +291,12 @@ extern "C" void app_main(void)
#if CONFIG_EXAMPLE_PERFORM_OTA == 1
esp_http_client_config_t config = { };
esp_https_ota_config_t ota_config = { };
ota_config.http_config = &config;
config.skip_cert_common_name_check = true;
config.url = CONFIG_EXAMPLE_PERFORM_OTA_URI;
esp_err_t ret = esp_https_ota(&config);
esp_err_t ret = esp_https_ota(&ota_config);
if (ret == ESP_OK) {
esp_restart();
} else {