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

@ -91,3 +91,21 @@ jobs:
run_executable: false
run_coverage: false
pre_run_script: "esp-protocols/components/esp_modem/test/host_test/env.sh"
esp_modem_generated_commands:
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
name: Generated commands compatibility
runs-on: ubuntu-latest
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
- name: Compat check
shell: bash
run: |
sudo apt-get update -y
sudo apt-get install -y astyle
cd components/esp_modem
find examples/ -type f -regex '.*/generate/.*\.\(hpp\|cpp\)' -exec ./scripts/generate.sh {} \;
./scripts/generate.sh
git diff --name-only
git diff --quiet

View File

@ -15,6 +15,13 @@ else()
endif()
if(CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE)
set(command_dir "generate") # using in-place macro expansion with AT commands
else()
set(command_dir "command") # using pre-generated AT commands
endif()
set(srcs ${platform_srcs}
"src/esp_modem_dte.cpp"
"src/esp_modem_dce.cpp"
@ -26,12 +33,10 @@ set(srcs ${platform_srcs}
"src/esp_modem_term_fs.cpp"
"src/esp_modem_vfs_uart_creator.cpp"
"src/esp_modem_vfs_socket_creator.cpp"
"src/esp_modem_modules.cpp")
set(include_dirs "include")
"${command_dir}/src/esp_modem_modules.cpp")
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
INCLUDE_DIRS include ${command_dir}/include
PRIV_INCLUDE_DIRS private_include
REQUIRES ${dependencies})

View File

@ -92,4 +92,15 @@ menu "esp-modem"
If enabled, the library dumps all transmitted and received data.
This option is only used for debugging.
config ESP_MODEM_ENABLE_DEVELOPMENT_MODE
bool "Use development mode"
default n
help
We use pre-generated headers and sources with common AT commands.
This is useful for using ESP-MODEM library with IDEs and code navigation.
When developing ESP-MODEM library, it's usually more convenient
to work with sources directly, using C-preprocessor's metaprogramming.
Set this to 'y' if you're making changes to the actual sources of
the AT command definitions (typically in esp_modem_command_declare.inc)
endmenu

View File

@ -0,0 +1,347 @@
/*
* SPDX-FileCopyrightText: 2021-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 esp_modem {
namespace dce_commands {
/**
* @defgroup ESP_MODEM_DCE_COMMAND ESP_MODEM DCE command library
* @brief Library of the most useful DCE commands
*/
/** @addtogroup ESP_MODEM_DCE_COMMAND
* @{
*/
/**
* @brief Generic AT command to be send with pass and fail phrases
*
* @param t Commandable object (anything that can accept commands)
* @param command Command to be sent do the commandable object
* @param pass_phrase String to be present in the reply to pass this command
* @param fail_phrase String to be present in the reply to fail this command
* @param timeout_ms Timeout in ms
*/
command_result generic_command(CommandableIf *t, const std::string &command,
const std::string &pass_phrase,
const std::string &fail_phrase, uint32_t timeout_ms);
/**
* @brief Declaration of all commands is generated from esp_modem_command_declare.inc
*/
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
command_result sync(CommandableIf *t);
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/
command_result get_operator_name(CommandableIf *t, std::string &name, int &act);
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/
command_result store_profile(CommandableIf *t);
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
command_result set_pin(CommandableIf *t, 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
*/
command_result at_raw(CommandableIf *t, 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
*/
command_result at(CommandableIf *t, 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
*/
command_result read_pin(CommandableIf *t, bool &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 set_echo(CommandableIf *t, 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
*/
command_result sms_txt_mode(CommandableIf *t, const bool txt);
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/
command_result sms_character_set(CommandableIf *t);
/**
* @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 send_sms(CommandableIf *t, 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
*/
command_result resume_data_mode(CommandableIf *t);
/**
* @brief Sets php context
* @param[in] p1 PdP context struct to setup modem cellular connection
* @return OK, FAIL or TIMEOUT
*/
command_result set_pdp_context(CommandableIf *t, PdpContext &pdp);
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
command_result set_command_mode(CommandableIf *t);
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
command_result set_cmux(CommandableIf *t);
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/
command_result get_imsi(CommandableIf *t, std::string &imsi);
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/
command_result get_imei(CommandableIf *t, std::string &imei);
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/
command_result get_module_name(CommandableIf *t, std::string &name);
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/
command_result set_data_mode(CommandableIf *t);
/**
* @brief Get Signal quality
* @param[out] rssi signal strength indication
* @param[out] ber channel bit error rate
* @return OK, FAIL or TIMEOUT
*/
command_result get_signal_quality(CommandableIf *t, 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
*/
command_result set_flow_control(CommandableIf *t, int dce_flow, int dte_flow);
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/
command_result hang_up(CommandableIf *t);
/**
* @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 get_battery_status(CommandableIf *t, int &voltage, int &bcs, int &bcl);
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/
command_result power_down(CommandableIf *t);
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
command_result reset(CommandableIf *t);
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
command_result set_baud(CommandableIf *t, 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
*/
command_result set_operator(CommandableIf *t, 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
*/
command_result set_network_attachment_state(CommandableIf *t, int state);
/**
* @brief Get network attachment state
* @param[out] state 1-attached 0-detached
* @return OK, FAIL or TIMEOUT
*/
command_result get_network_attachment_state(CommandableIf *t, int &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 set_radio_state(CommandableIf *t, int state);
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
command_result get_radio_state(CommandableIf *t, int &state);
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/
command_result set_network_mode(CommandableIf *t, int mode);
/**
* @brief Preferred network mode (CAT-M and/or NB-IoT)
* @param[in] mode preferred selection
* @return OK, FAIL or TIMEOUT
*/
command_result set_preferred_mode(CommandableIf *t, 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
*/
command_result set_network_bands(CommandableIf *t, 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
*/
command_result get_network_system_mode(CommandableIf *t, int &mode);
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
command_result set_gnss_power_mode(CommandableIf *t, int mode);
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
command_result get_gnss_power_mode(CommandableIf *t, int &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 config_psm(CommandableIf *t, 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
*/
command_result config_network_registration_urc(CommandableIf *t, 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
*/
command_result get_network_registration_state(CommandableIf *t, 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
*/
command_result config_mobile_termination_error(CommandableIf *t, 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
*/
command_result config_edrx(CommandableIf *t, int mode, int access_technology, const std::string &edrx_value);
/**
* @brief Following commands that are different for some specific modules
*/
command_result get_battery_status_sim7xxx(CommandableIf *t, int &voltage, int &bcs, int &bcl);
command_result set_gnss_power_mode_sim76xx(CommandableIf *t, int mode);
command_result power_down_sim76xx(CommandableIf *t);
command_result power_down_sim70xx(CommandableIf *t);
command_result set_network_bands_sim76xx(CommandableIf *t, const std::string &mode, const int *bands, int size);
command_result power_down_sim8xx(CommandableIf *t);
command_result set_data_mode_alt(CommandableIf *t);
command_result set_pdp_context(CommandableIf *t, PdpContext &pdp, uint32_t timeout_ms);
/**
* @}
*/
} // dce_commands
} // esp_modem

View File

@ -0,0 +1,453 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
namespace esp_modem {
/**
* @defgroup ESP_MODEM_DCE
* @brief Definition of DCE abstraction
*/
/** @addtogroup ESP_MODEM_DCE
* @{
*/
/**
* @brief Common abstraction of the modem DCE, specialized by the GenericModule which is a parent class for the supported
* devices and most common modems, as well.
*/
class DCE : public DCE_T<GenericModule> {
public:
command_result get_operator_name(std::string &name)
{
return device->get_operator_name(name);
}
using DCE_T<GenericModule>::DCE_T;
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
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
*/
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
*/
command_result store_profile()
{
return device->store_profile();
}
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
command_result set_pdp_context(PdpContext &pdp)
{
return device->set_pdp_context(pdp);
}
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
command_result set_command_mode()
{
return device->set_command_mode();
}
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
command_result power_down()
{
return device->power_down();
}
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
command_result reset()
{
return device->reset();
}
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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

View File

@ -0,0 +1,461 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <memory>
#include <utility>
//#include "generate/esp_modem_command_declare.inc"
#include "cxx_include/esp_modem_command_library.hpp"
#include "cxx_include/esp_modem_types.hpp"
#include "esp_modem_dce_config.h"
namespace esp_modem {
/**
* @defgroup ESP_MODEM_MODULE
* @brief Definition of modules representing specific modem devices
*/
/** @addtogroup ESP_MODEM_MODULE
* @{
*/
enum class command_result;
class DTE;
struct PdpContext;
/**
* @brief This is a basic building block for custom modules as well as for the supported modules in the esp-modem component
* It derives from the ModuleIf.
*/
class GenericModule: public ModuleIf {
public:
/**
* @brief We can construct a generic device with an existent DTE and it's configuration
* The configuration could be either the dce-config struct or just a pdp context
*/
explicit GenericModule(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp):
dte(std::move(dte)), pdp(std::move(pdp)) {}
explicit GenericModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config *config);
/**
* @brief This is a mandatory method for ModuleIf class, which sets up the device
* to be able to connect to the network. This typically consists of setting basic
* communication parameters and setting the PDP (defining logical access point
* to cellular network)
*/
bool setup_data_mode() override
{
if (set_echo(false) != command_result::OK) {
return false;
}
if (set_pdp_context(*pdp) != command_result::OK) {
return false;
}
return true;
}
/**
* @brief This is a mandatory method of ModuleIf class, which defines
* basic commands for switching between DATA, COMMAND and CMUX modes
*/
bool set_mode(modem_mode mode) override
{
if (mode == modem_mode::DATA_MODE) {
if (set_data_mode() != command_result::OK) {
return resume_data_mode() == command_result::OK;
}
return true;
} else if (mode == modem_mode::COMMAND_MODE) {
Task::Delay(1000); // Mandatory 1s pause before
int retry = 0;
while (retry++ < 3) {
if (set_command_mode() == command_result::OK) {
return true;
}
// send a newline to delimit the escape from the upcoming sync command
uint8_t delim = '\n';
dte->write(&delim, 1);
if (sync() == command_result::OK) {
return true;
}
Task::Delay(1000); // Mandatory 1s pause before escape
}
return false;
} else if (mode == modem_mode::CMUX_MODE) {
return set_cmux() == command_result::OK;
}
return true;
}
/**
* @brief Additional method providing runtime configuration of PDP context
*/
void configure_pdp_context(std::unique_ptr<PdpContext> new_pdp)
{
pdp = std::move(new_pdp);
}
/**
* @brief Simplified version of operator name (without the ACT, which is included in the command library)
*/
command_result get_operator_name(std::string &name)
{
int dummy_act;
return get_operator_name(name, dummy_act);
}
/**
* @brief Common DCE commands generated from the API AT list
*/
// DECLARE_ALL_COMMAND_APIS(virtual return_type name(...); )
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
virtual command_result sync();
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/
virtual command_result get_operator_name(std::string &name, int &act);
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/
virtual command_result store_profile();
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual command_result sms_txt_mode(const bool txt);
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual command_result set_pdp_context(PdpContext &pdp);
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
virtual command_result set_command_mode();
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
virtual command_result set_cmux();
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/
virtual command_result get_imsi(std::string &imsi);
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/
virtual command_result get_imei(std::string &imei);
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/
virtual command_result get_module_name(std::string &name);
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/
virtual 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
*/
virtual 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
*/
virtual command_result set_flow_control(int dce_flow, int dte_flow);
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/
virtual 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
*/
virtual command_result get_battery_status(int &voltage, int &bcs, int &bcl);
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/
virtual command_result power_down();
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
virtual command_result reset();
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual command_result set_radio_state(int state);
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
virtual command_result get_radio_state(int &state);
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual 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
*/
virtual command_result config_edrx(int mode, int access_technology, const std::string &edrx_value);
protected:
std::shared_ptr<DTE> dte; /*!< Generic device needs the DTE as a channel talk to the module using AT commands */
std::unique_ptr<PdpContext> pdp; /*!< It also needs a PDP data, const information used for setting up cellular network */
};
// Definitions of other supported modules with some specific commands overwritten
/**
* @brief Specific definition of the SIM7600 module
*/
class SIM7600: public GenericModule {
using GenericModule::GenericModule;
public:
command_result get_battery_status(int &voltage, int &bcs, int &bcl) override;
command_result power_down() override;
command_result set_gnss_power_mode(int mode) override;
command_result set_network_bands(const std::string &mode, const int *bands, int size) override;
};
/**
* @brief Specific definition of the SIM7070 module
*/
class SIM7070: public GenericModule {
using GenericModule::GenericModule;
public:
command_result power_down() override;
command_result set_data_mode() override;
};
/**
* @brief Specific definition of the SIM7000 module
*/
class SIM7000: public GenericModule {
using GenericModule::GenericModule;
public:
command_result power_down() override;
};
/**
* @brief Specific definition of the SIM800 module
*/
class SIM800: public GenericModule {
using GenericModule::GenericModule;
public:
command_result power_down() override;
};
/**
* @brief Specific definition of the BG96 module
*/
class BG96: public GenericModule {
using GenericModule::GenericModule;
public:
command_result set_pdp_context(PdpContext &pdp) override;
};
class SQNGM02S : public GenericModule {
using GenericModule::GenericModule;
public:
command_result connect(PdpContext &pdp);
bool setup_data_mode() override;
};
/**
* @}
*/
} // namespace esp_modem

View File

@ -0,0 +1,316 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
//#include "generate/esp_modem_command_declare.inc"
#include "esp_modem_c_api_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_sync(esp_modem_dce_t *dce);
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_operator_name(esp_modem_dce_t *dce, char *name, int *act);
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_store_profile(esp_modem_dce_t *dce);
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_pin(esp_modem_dce_t *dce, const char *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_err_t esp_modem_at_raw(esp_modem_dce_t *dce, const char *cmd, char *out, const char *pass, const char *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_err_t esp_modem_at(esp_modem_dce_t *dce, const char *cmd, char *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_err_t esp_modem_read_pin(esp_modem_dce_t *dce, 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_err_t esp_modem_set_echo(esp_modem_dce_t *dce, 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_err_t esp_modem_sms_txt_mode(esp_modem_dce_t *dce, const bool txt);
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_sms_character_set(esp_modem_dce_t *dce);
/**
* @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_err_t esp_modem_send_sms(esp_modem_dce_t *dce, const char *number, const char *message);
/**
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_resume_data_mode(esp_modem_dce_t *dce);
/**
* @brief Sets php context
* @param[in] p1 PdP context struct to setup modem cellular connection
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce, esp_modem_PdpContext_t *pdp);
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_command_mode(esp_modem_dce_t *dce);
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_cmux(esp_modem_dce_t *dce);
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_imsi(esp_modem_dce_t *dce, char *imsi);
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_imei(esp_modem_dce_t *dce, char *imei);
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_module_name(esp_modem_dce_t *dce, char *name);
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_data_mode(esp_modem_dce_t *dce);
/**
* @brief Get Signal quality
* @param[out] rssi signal strength indication
* @param[out] ber channel bit error rate
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_signal_quality(esp_modem_dce_t *dce, 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_err_t esp_modem_set_flow_control(esp_modem_dce_t *dce, int dce_flow, int dte_flow);
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_hang_up(esp_modem_dce_t *dce);
/**
* @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_err_t esp_modem_get_battery_status(esp_modem_dce_t *dce, int *voltage, int *bcs, int *bcl);
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_power_down(esp_modem_dce_t *dce);
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_reset(esp_modem_dce_t *dce);
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_baud(esp_modem_dce_t *dce, 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_err_t esp_modem_set_operator(esp_modem_dce_t *dce, int mode, int format, const char *oper);
/**
* @brief Attach or detach from the GPRS service
* @param[in] state 1-attach 0-detach
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_network_attachment_state(esp_modem_dce_t *dce, int state);
/**
* @brief Get network attachment state
* @param[out] state 1-attached 0-detached
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_network_attachment_state(esp_modem_dce_t *dce, 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_err_t esp_modem_set_radio_state(esp_modem_dce_t *dce, int state);
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_radio_state(esp_modem_dce_t *dce, int *state);
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_network_mode(esp_modem_dce_t *dce, int mode);
/**
* @brief Preferred network mode (CAT-M and/or NB-IoT)
* @param[in] mode preferred selection
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_preferred_mode(esp_modem_dce_t *dce, 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_err_t esp_modem_set_network_bands(esp_modem_dce_t *dce, const char *mode, const int *bands, int size);
/**
* @brief Show network system mode
* @param[out] mode current network mode
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_network_system_mode(esp_modem_dce_t *dce, int *mode);
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_set_gnss_power_mode(esp_modem_dce_t *dce, int mode);
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
esp_err_t esp_modem_get_gnss_power_mode(esp_modem_dce_t *dce, 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_err_t esp_modem_config_psm(esp_modem_dce_t *dce, int mode, const char *tau, const char *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_err_t esp_modem_config_network_registration_urc(esp_modem_dce_t *dce, 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_err_t esp_modem_get_network_registration_state(esp_modem_dce_t *dce, 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_err_t esp_modem_config_mobile_termination_error(esp_modem_dce_t *dce, 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_err_t esp_modem_config_edrx(esp_modem_dce_t *dce, int mode, int access_technology, const char *edrx_value);
// --- ESP-MODEM command module ends here ---
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,512 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx17_include/esp_modem_command_library_17.hpp"
#include "cxx_include/esp_modem_dte.hpp"
namespace esp_modem {
GenericModule::GenericModule(std::shared_ptr<DTE> dte, const dce_config *config) :
dte(std::move(dte)), pdp(std::make_unique<PdpContext>(config->apn)) {}
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::sync()
{
return esp_modem::dce_commands::sync(dte.get());
}
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_operator_name(std::string &name, int &act)
{
return esp_modem::dce_commands::get_operator_name(dte.get(), name, act);
}
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::store_profile()
{
return esp_modem::dce_commands::store_profile(dte.get());
}
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_pin(const std::string &pin)
{
return esp_modem::dce_commands::set_pin(dte.get(), 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 GenericModule::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(dte.get(), 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 GenericModule::at(const std::string &cmd, std::string &out, int timeout)
{
return esp_modem::dce_commands::at(dte.get(), 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 GenericModule::read_pin(bool &pin_ok)
{
return esp_modem::dce_commands::read_pin(dte.get(), 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 GenericModule::set_echo(const bool echo_on)
{
return esp_modem::dce_commands::set_echo(dte.get(), 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 GenericModule::sms_txt_mode(const bool txt)
{
return esp_modem::dce_commands::sms_txt_mode(dte.get(), txt);
}
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::sms_character_set()
{
return esp_modem::dce_commands::sms_character_set(dte.get());
}
/**
* @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 GenericModule::send_sms(const std::string &number, const std::string &message)
{
return esp_modem::dce_commands::send_sms(dte.get(), number, message);
}
/**
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::resume_data_mode()
{
return esp_modem::dce_commands::resume_data_mode(dte.get());
}
/**
* @brief Sets php context
* @param[in] p1 PdP context struct to setup modem cellular connection
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_pdp_context(PdpContext &pdp)
{
return esp_modem::dce_commands::set_pdp_context(dte.get(), pdp);
}
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_command_mode()
{
return esp_modem::dce_commands::set_command_mode(dte.get());
}
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_cmux()
{
return esp_modem::dce_commands::set_cmux(dte.get());
}
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_imsi(std::string &imsi)
{
return esp_modem::dce_commands::get_imsi(dte.get(), imsi);
}
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_imei(std::string &imei)
{
return esp_modem::dce_commands::get_imei(dte.get(), imei);
}
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_module_name(std::string &name)
{
return esp_modem::dce_commands::get_module_name(dte.get(), name);
}
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_data_mode()
{
return esp_modem::dce_commands::set_data_mode(dte.get());
}
/**
* @brief Get Signal quality
* @param[out] rssi signal strength indication
* @param[out] ber channel bit error rate
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_signal_quality(int &rssi, int &ber)
{
return esp_modem::dce_commands::get_signal_quality(dte.get(), 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 GenericModule::set_flow_control(int dce_flow, int dte_flow)
{
return esp_modem::dce_commands::set_flow_control(dte.get(), dce_flow, dte_flow);
}
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::hang_up()
{
return esp_modem::dce_commands::hang_up(dte.get());
}
/**
* @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 GenericModule::get_battery_status(int &voltage, int &bcs, int &bcl)
{
return esp_modem::dce_commands::get_battery_status(dte.get(), voltage, bcs, bcl);
}
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::power_down()
{
return esp_modem::dce_commands::power_down(dte.get());
}
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::reset()
{
return esp_modem::dce_commands::reset(dte.get());
}
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_baud(int baud)
{
return esp_modem::dce_commands::set_baud(dte.get(), 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 GenericModule::set_operator(int mode, int format, const std::string &oper)
{
return esp_modem::dce_commands::set_operator(dte.get(), 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 GenericModule::set_network_attachment_state(int state)
{
return esp_modem::dce_commands::set_network_attachment_state(dte.get(), state);
}
/**
* @brief Get network attachment state
* @param[out] state 1-attached 0-detached
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_network_attachment_state(int &state)
{
return esp_modem::dce_commands::get_network_attachment_state(dte.get(), 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 GenericModule::set_radio_state(int state)
{
return esp_modem::dce_commands::set_radio_state(dte.get(), state);
}
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_radio_state(int &state)
{
return esp_modem::dce_commands::get_radio_state(dte.get(), state);
}
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_network_mode(int mode)
{
return esp_modem::dce_commands::set_network_mode(dte.get(), mode);
}
/**
* @brief Preferred network mode (CAT-M and/or NB-IoT)
* @param[in] mode preferred selection
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_preferred_mode(int mode)
{
return esp_modem::dce_commands::set_preferred_mode(dte.get(), 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 GenericModule::set_network_bands(const std::string &mode, const int *bands, int size)
{
return esp_modem::dce_commands::set_network_bands(dte.get(), mode, bands, size);
}
/**
* @brief Show network system mode
* @param[out] mode current network mode
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_network_system_mode(int &mode)
{
return esp_modem::dce_commands::get_network_system_mode(dte.get(), mode);
}
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::set_gnss_power_mode(int mode)
{
return esp_modem::dce_commands::set_gnss_power_mode(dte.get(), mode);
}
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/
command_result GenericModule::get_gnss_power_mode(int &mode)
{
return esp_modem::dce_commands::get_gnss_power_mode(dte.get(), 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 GenericModule::config_psm(int mode, const std::string &tau, const std::string &active_time)
{
return esp_modem::dce_commands::config_psm(dte.get(), 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 GenericModule::config_network_registration_urc(int value)
{
return esp_modem::dce_commands::config_network_registration_urc(dte.get(), 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 GenericModule::get_network_registration_state(int &state)
{
return esp_modem::dce_commands::get_network_registration_state(dte.get(), 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 GenericModule::config_mobile_termination_error(int mode)
{
return esp_modem::dce_commands::config_mobile_termination_error(dte.get(), 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 GenericModule::config_edrx(int mode, int access_technology, const std::string &edrx_value)
{
return esp_modem::dce_commands::config_edrx(dte.get(), mode, access_technology, edrx_value);
}
// Usage examples:
// Zero arguments
// Helper to apply the correct macro to each parameter
//
// Repeat all declarations and forward to the AT commands defined in esp_modem::dce_commands:: namespace
//
//
// Handle specific commands for specific supported modems
//
command_result SIM7600::get_battery_status(int &voltage, int &bcs, int &bcl)
{
return dce_commands::get_battery_status_sim7xxx(dte.get(), voltage, bcs, bcl);
}
command_result SIM7600::set_network_bands(const std::string &mode, const int *bands, int size)
{
return dce_commands::set_network_bands_sim76xx(dte.get(), mode, bands, size);
}
command_result SIM7600::set_gnss_power_mode(int mode)
{
return dce_commands::set_gnss_power_mode_sim76xx(dte.get(), mode);
}
command_result SIM7600::power_down()
{
return dce_commands::power_down_sim76xx(dte.get());
}
command_result SIM7070::power_down()
{
return dce_commands::power_down_sim70xx(dte.get());
}
command_result SIM7070::set_data_mode()
{
return dce_commands::set_data_mode_alt(dte.get());
}
command_result SIM7000::power_down()
{
return dce_commands::power_down_sim70xx(dte.get());
}
command_result SIM800::power_down()
{
return dce_commands::power_down_sim8xx(dte.get());
}
command_result BG96::set_pdp_context(esp_modem::PdpContext &pdp)
{
return dce_commands::set_pdp_context(dte.get(), pdp, 300);
}
bool SQNGM02S::setup_data_mode()
{
return true;
}
command_result SQNGM02S::connect(PdpContext &pdp)
{
command_result res;
configure_pdp_context(std::make_unique<PdpContext>(pdp));
set_pdp_context(*this->pdp);
res = config_network_registration_urc(1);
if (res != command_result::OK) {
return res;
}
res = set_radio_state(1);
if (res != command_result::OK) {
return res;
}
//wait for +CEREG: 5 or +CEREG: 1.
const auto pass = std::list<std::string_view>({"+CEREG: 1", "+CEREG: 5"});
const auto fail = std::list<std::string_view>({"ERROR"});
res = esp_modem::dce_commands::generic_command(dte.get(), "", pass, fail, 1200000);
if (res != command_result::OK) {
config_network_registration_urc(0);
return res;
}
res = config_network_registration_urc(0);
if (res != command_result::OK) {
return res;
}
return command_result::OK;
}
}

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 {

View File

@ -1,16 +1,16 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_modem_dte.hpp"
#include "esp_modem_dce_module.hpp"
#include "esp_modem_types.hpp"
#include "generate/esp_modem_command_declare.inc"
#include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_types.hpp"
// --- ESP-MODEM command module starts here ---
namespace esp_modem {
namespace dce_commands {
@ -38,10 +38,11 @@ command_result generic_command(CommandableIf *t, const std::string &command,
/**
* @brief Declaration of all commands is generated from esp_modem_command_declare.inc
*/
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
return_type name(CommandableIf *t, ## __VA_ARGS__);
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
return_type name(CommandableIf *t ESP_MODEM_COMMAND_PARAMS_AFTER(__VA_ARGS__));
DECLARE_ALL_COMMAND_APIS(declare name(Commandable *p, ...);)
#include "esp_modem_command_declare.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND

View File

@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
// --- ESP-MODEM command module starts here ---
namespace esp_modem {
/**
* @defgroup ESP_MODEM_DCE
* @brief Definition of DCE abstraction
*/
/** @addtogroup ESP_MODEM_DCE
* @{
*/
/**
* @brief Common abstraction of the modem DCE, specialized by the GenericModule which is a parent class for the supported
* devices and most common modems, as well.
*/
class DCE : public DCE_T<GenericModule> {
public:
command_result get_operator_name(std::string &name)
{
return device->get_operator_name(name);
}
using DCE_T<GenericModule>::DCE_T;
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
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

View File

@ -8,11 +8,13 @@
#include <memory>
#include <utility>
#include "generate/esp_modem_command_declare.inc"
//#include "generate/esp_modem_command_declare.inc"
#include "cxx_include/esp_modem_command_library.hpp"
#include "cxx_include/esp_modem_types.hpp"
#include "esp_modem_dce_config.h"
// --- ESP-MODEM command module starts here ---
namespace esp_modem {
/**
@ -112,10 +114,15 @@ public:
/**
* @brief Common DCE commands generated from the API AT list
*/
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
virtual return_type name(__VA_ARGS__);
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
virtual return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
// DECLARE_ALL_COMMAND_APIS(virtual return_type name(...); )
#include "esp_modem_command_declare.inc"
DECLARE_ALL_COMMAND_APIS(virtual return_type name(...);)
#undef ESP_MODEM_DECLARE_DCE_COMMAND

View File

@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
//#include "generate/esp_modem_command_declare.inc"
#include "esp_modem_c_api_types.h"
#ifdef __cplusplus
extern "C" {
#endif
// --- ESP-MODEM command module starts here ---
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
esp_err_t esp_modem_ ## name(esp_modem_dce_t *dce ESP_MODEM_COMMAND_PARAMS_AFTER(__VA_ARGS__));
#include "esp_modem_command_declare.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
// --- ESP-MODEM command module ends here ---
#ifdef __cplusplus
}
#endif

View File

@ -1,49 +1,30 @@
// 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_ALL_COMMAND_APIS(...) \
/**
* @brief Sends the initial AT sequence to sync up with the device
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(sync, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(sync, command_result)
/**
* @brief Reads the operator name
* @param[out] name operator name
* @param[out] act access technology
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 2, STRING_OUT(p1, name), INT_OUT(p2, act)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, STR_OUT(name), INT_OUT(act))
/**
* @brief Stores current user profile
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(store_profile, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(store_profile, command_result)
/**
* @brief Sets the supplied PIN code
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/\
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, STR_IN(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
@ -52,155 +33,155 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
* @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_DECLARE_DCE_COMMAND(at_raw, command_result, 5, STRING_IN(p1, cmd), STRING_OUT(p2, out), STRING_IN(p3, pass), STRING_IN(p4, fail), INT_IN(p5, timeout)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(at_raw, command_result, STR_IN(cmd), STR_OUT(out), STR_IN(pass), STR_IN(fail), INT_IN(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_DECLARE_DCE_COMMAND(at, command_result, 3, STRING_IN(p1, cmd), STRING_OUT(p2, out), INT_IN(p3, timeout)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(at, command_result, STR_IN(cmd), STR_OUT(out), INT_IN(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_DECLARE_DCE_COMMAND(read_pin, command_result, 1, BOOL_OUT(p1, pin_ok)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(read_pin, command_result, BOOL_OUT(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_DECLARE_DCE_COMMAND(set_echo, command_result, 1, BOOL_IN(p1, echo_on)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_echo, command_result, BOOL_IN(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_DECLARE_DCE_COMMAND(sms_txt_mode, command_result, 1, BOOL_IN(p1, txt)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(sms_txt_mode, command_result, BOOL_IN(txt))
/**
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(sms_character_set, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(sms_character_set, command_result)
/**
* @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_DECLARE_DCE_COMMAND(send_sms, command_result, 2, STRING_IN(p1, number), STRING_IN(p2, message)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(send_sms, command_result, STR_IN(number), STR_IN(message))
/**
* @brief Resumes data mode (Switches back to the data mode, which was temporarily suspended)
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(resume_data_mode, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(resume_data_mode, command_result)
/**
* @brief Sets php context
* @param[in] p1 PdP context struct to setup modem cellular connection
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_pdp_context, command_result, 1, STRUCT_OUT(PdpContext, p1)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_pdp_context, command_result, STRUCT_OUT(PdpContext, pdp))
/**
* @brief Switches to the command mode
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_command_mode, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_command_mode, command_result)
/**
* @brief Switches to the CMUX mode
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_cmux, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_cmux, command_result)
/**
* @brief Reads the IMSI number
* @param[out] imsi Module's IMSI number
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_imsi, command_result, 1, STRING_OUT(p1, imsi)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_imsi, command_result, STR_OUT(imsi))
/**
* @brief Reads the IMEI number
* @param[out] imei Module's IMEI number
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_imei, command_result, 1, STRING_OUT(p1, imei)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_imei, command_result, STR_OUT(imei))
/**
* @brief Reads the module name
* @param[out] name module name
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_module_name, command_result, 1, STRING_OUT(p1, name)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_module_name, command_result, STR_OUT(name))
/**
* @brief Sets the modem to data mode
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_data_mode, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_data_mode, command_result)
/**
* @brief Get Signal quality
* @param[out] rssi signal strength indication
* @param[out] ber channel bit error rate
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_signal_quality, command_result, 2, INT_OUT(p1, rssi), INT_OUT(p2, ber)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_signal_quality, command_result, INT_OUT(rssi), INT_OUT(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_DECLARE_DCE_COMMAND(set_flow_control, command_result, 2, INT_IN(p1, dce_flow), INT_IN(p2, dte_flow)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_flow_control, command_result, INT_IN(dce_flow), INT_IN(dte_flow))
/**
* @brief Hangs up current data call
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(hang_up, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(hang_up, command_result)
/**
* @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_DECLARE_DCE_COMMAND(get_battery_status, command_result, 3, INT_OUT(p1, voltage), INT_OUT(p2, bcs), INT_OUT(p3, bcl)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_battery_status, command_result, INT_OUT(voltage), INT_OUT(bcs), INT_OUT(bcl))
/**
* @brief Power down the module
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(power_down, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(power_down, command_result)
/**
* @brief Reset the module
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(reset, command_result, 0) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(reset, command_result)
/**
* @brief Configures the baudrate
* @param[in] baud Desired baud rate of the DTE
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_baud, command_result, 1, INT_IN(p1, baud)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_baud, command_result, INT_IN(baud))
/**
* @brief Force an attempt to connect to a specific operator
* @param[in] mode mode of attempt
@ -215,88 +196,88 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_baud, command_result, 1, INT_IN(p1, baud)) \
* format=2 - numeric
* @param[in] oper the operator to connect to
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_operator, command_result, 3, INT_IN(p1, mode), INT_IN(p2, format), STRING_IN(p3, oper)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_operator, command_result, INT_IN(mode), INT_IN(format), STR_IN(oper))
/**
* @brief Attach or detach from the GPRS service
* @param[in] state 1-attach 0-detach
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_network_attachment_state, command_result, 1, INT_IN(p1, state)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_network_attachment_state, command_result, INT_IN(state))
/**
* @brief Get network attachment state
* @param[out] state 1-attached 0-detached
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_network_attachment_state, command_result, 1, INT_OUT(p1, state)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_network_attachment_state, command_result, INT_OUT(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_DECLARE_DCE_COMMAND(set_radio_state, command_result, 1, INT_IN(p1, state)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_radio_state, command_result, INT_IN(state))
/**
* @brief Get current radio state
* @param[out] state 1-full 0-minimum ...
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_radio_state, command_result, 1, INT_OUT(p1, state)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_radio_state, command_result, INT_OUT(state))
/**
* @brief Set network mode
* @param[in] mode preferred mode
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_network_mode, command_result, 1, INT_IN(p1, mode)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_network_mode, command_result, INT_IN(mode))
/**
* @brief Preferred network mode (CAT-M and/or NB-IoT)
* @param[in] mode preferred selection
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_preferred_mode, command_result, 1, INT_IN(p1, mode)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_preferred_mode, command_result, INT_IN(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_DECLARE_DCE_COMMAND(set_network_bands, command_result, 3, STRING_IN(p1, mode), INTEGER_LIST_IN(p2, bands), INT_IN(p3, size)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_network_bands, command_result, STR_IN(mode), INT_LIST_IN(bands), INT_IN(size))
/**
* @brief Show network system mode
* @param[out] mode current network mode
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_network_system_mode, command_result, 1, INT_OUT(p1, mode)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_network_system_mode, command_result, INT_OUT(mode))
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(set_gnss_power_mode, command_result, 1, INT_IN(p1, mode)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(set_gnss_power_mode, command_result, INT_IN(mode))
/**
* @brief GNSS power control
* @param[out] mode power mode (0 - off, 1 - on)
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_gnss_power_mode, command_result, 1, INT_OUT(p1, mode)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_gnss_power_mode, command_result, INT_OUT(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_DECLARE_DCE_COMMAND(config_psm, command_result, 3, INT_IN(p1, mode), STRING_IN(p2, tau), STRING_IN(p3, active_time)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(config_psm, command_result, INT_IN(mode), STR_IN(tau), STR_IN(active_time))
/**
* @brief Configure CEREG urc
* @param[in] value
@ -306,9 +287,9 @@ ESP_MODEM_DECLARE_DCE_COMMAND(config_psm, command_result, 3, INT_IN(p1, mode), S
* 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_DECLARE_DCE_COMMAND(config_network_registration_urc, command_result, 1, INT_IN(p1, value)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(config_network_registration_urc, command_result, INT_IN(value))
/**
* @brief Gets the current network registration state
* @param[out] state The current network registration state
@ -323,18 +304,18 @@ ESP_MODEM_DECLARE_DCE_COMMAND(config_network_registration_urc, command_result, 1
* 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_DECLARE_DCE_COMMAND(get_network_registration_state, command_result, 1, INT_OUT(p1,state)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(get_network_registration_state, command_result, INT_OUT(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_DECLARE_DCE_COMMAND(config_mobile_termination_error, command_result, 1, INT_IN(p1, mode)) \
\
*/
ESP_MODEM_DECLARE_DCE_COMMAND(config_mobile_termination_error, command_result, INT_IN(mode))
/**
* @brief Configure eDRX
* @param[in] mode
@ -351,8 +332,8 @@ ESP_MODEM_DECLARE_DCE_COMMAND(config_mobile_termination_error, command_result, 1
* 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_DECLARE_DCE_COMMAND(config_edrx, command_result, 3, INT_IN(p1, mode), INT_IN(p2, access_technology), STRING_IN(p3, edrx_value)) \
*/
ESP_MODEM_DECLARE_DCE_COMMAND(config_edrx, command_result, INT_IN(mode), INT_IN(access_technology), STR_IN(edrx_value))
#ifdef GENERATE_DOCS
// cat ../include/generate/esp_modem_command_declare.inc | clang++ -E -P -CC -xc++ -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p'

View File

@ -0,0 +1,58 @@
#pragma once
#define ESP_MODEM_GET_MACRO(_0, _1, _2, _3, _4, _5, _6, ESP_MODEM_MACRO_NAME, ...) ESP_MODEM_MACRO_NAME
#define ESP_MODEM_COMMAND_PARAMS(...) ESP_MODEM_GET_MACRO(_0, ##__VA_ARGS__, ESP_MODEM_HELPER6, ESP_MODEM_HELPER5, ESP_MODEM_HELPER4, ESP_MODEM_HELPER3, ESP_MODEM_HELPER2, ESP_MODEM_HELPER1, ESP_MODEM_HELPER0)(PARAM_, ESP_MODEM_NO_COMMA, ESP_MODEM_NO_COMMA, ##__VA_ARGS__)
#define ESP_MODEM_COMMAND_PARAMS_AFTER(...) ESP_MODEM_GET_MACRO(_0, ##__VA_ARGS__, ESP_MODEM_HELPER6, ESP_MODEM_HELPER5, ESP_MODEM_HELPER4, ESP_MODEM_HELPER3, ESP_MODEM_HELPER2, ESP_MODEM_HELPER1, ESP_MODEM_HELPER0)(PARAM_, ESP_MODEM_COMMA, ESP_MODEM_NO_COMMA, ##__VA_ARGS__)
#define ESP_MODEM_COMMAND_FORWARD(...) ESP_MODEM_GET_MACRO(_0, ##__VA_ARGS__, ESP_MODEM_HELPER6, ESP_MODEM_HELPER5, ESP_MODEM_HELPER4, ESP_MODEM_HELPER3, ESP_MODEM_HELPER2, ESP_MODEM_HELPER1, ESP_MODEM_HELPER0)(FORWARD_, ESP_MODEM_NO_COMMA, ESP_MODEM_NO_COMMA, ##__VA_ARGS__)
#define ESP_MODEM_COMMAND_FORWARD_AFTER(...) ESP_MODEM_GET_MACRO(_0, ##__VA_ARGS__, ESP_MODEM_HELPER6, ESP_MODEM_HELPER5, ESP_MODEM_HELPER4, ESP_MODEM_HELPER3, ESP_MODEM_HELPER2, ESP_MODEM_HELPER1, ESP_MODEM_HELPER0)(FORWARD_, ESP_MODEM_COMMA, ESP_MODEM_NO_COMMA, ##__VA_ARGS__)
#ifdef __cplusplus
#define PARAM_STR_OUT(name) std::string& name
#define PARAM_STR_IN(name) const std::string& name
#define PARAM_INT_OUT(name) int& name
#define PARAM_INT_IN(name) int name
#define PARAM_BOOL_IN(name) const bool name
#define PARAM_BOOL_OUT(name) bool& name
#define PARAM_STRUCT_OUT(struct_name, name) struct_name& name
#define PARAM_INT_LIST_IN(name) const int* name
#else
#define PARAM_STR_OUT(name) char* name
#define PARAM_STR_IN(name) const char* name
#define PARAM_INT_OUT(name) int* name
#define PARAM_INT_IN(name) int name
#define PARAM_BOOL_IN(name) const bool name
#define PARAM_BOOL_OUT(name) bool* name
#define PARAM_STRUCT_OUT(struct_name, name) esp_modem_ ## struct_name ## _t* name
#define PARAM_INT_LIST_IN(name) const int* name
#endif
#define FORWARD_STR_OUT(name) name
#define FORWARD_STR_IN(name) name
#define FORWARD_INT_OUT(name) name
#define FORWARD_INT_IN(name) name
#define FORWARD_BOOL_IN(name) name
#define FORWARD_BOOL_OUT(name) name
#define FORWARD_STRUCT_OUT(struct_name, name) name
#define FORWARD_INT_LIST_IN(name) name
#define ESP_MODEM_COMMA ,
#define ESP_MODEM_NO_COMMA
#define ESP_MODEM_HELPER_EVAL(x) x
#define ESP_MODEM_HELPER_GENERIC(a, b) ESP_MODEM_HELPER_EVAL(a ## b)
#define ESP_MODEM_HELPER0(prefix, lead_comma, trail_comma)
#define ESP_MODEM_HELPER1(prefix, lead_comma, trail_comma, p1) lead_comma ESP_MODEM_HELPER_GENERIC(prefix, p1) trail_comma
#define ESP_MODEM_HELPER2(prefix, lead_comma, trail_comma, p1, p2) lead_comma ESP_MODEM_HELPER_GENERIC(prefix, p1), ESP_MODEM_HELPER_GENERIC(prefix, p2) trail_comma
#define ESP_MODEM_HELPER3(prefix, lead_comma, trail_comma, p1, p2, p3) lead_comma ESP_MODEM_HELPER_GENERIC(prefix, p1), ESP_MODEM_HELPER_GENERIC(prefix, p2), ESP_MODEM_HELPER_GENERIC(prefix, p3) trail_comma
#define ESP_MODEM_HELPER4(prefix, lead_comma, trail_comma, p1, p2, p3, p4) lead_comma \
ESP_MODEM_HELPER_GENERIC(prefix, p1), \
ESP_MODEM_HELPER_GENERIC(prefix, p2), \
ESP_MODEM_HELPER_GENERIC(prefix, p3), \
ESP_MODEM_HELPER_GENERIC(prefix, p4) trail_comma
#define ESP_MODEM_HELPER5(prefix, lead_comma, trail_comma, p1, p2, p3, p4, p5) lead_comma \
ESP_MODEM_HELPER_GENERIC(prefix, p1), \
ESP_MODEM_HELPER_GENERIC(prefix, p2), \
ESP_MODEM_HELPER_GENERIC(prefix, p3), \
ESP_MODEM_HELPER_GENERIC(prefix, p4), \
ESP_MODEM_HELPER_GENERIC(prefix, p5) trail_comma

View File

@ -6,37 +6,35 @@
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
#include "generate/esp_modem_command_declare.inc"
#include "cxx17_include/esp_modem_command_library_17.hpp"
#include "cxx_include/esp_modem_dte.hpp"
// --- ESP-MODEM command module starts here ---
namespace esp_modem {
GenericModule::GenericModule(std::shared_ptr<DTE> dte, const dce_config *config) :
dte(std::move(dte)), pdp(std::make_unique<PdpContext>(config->apn)) {}
//
// 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
#include "esp_modem_command_declare_helper.inc"
#define _ARGS(x) ARGS ## x
#define ARGS(x) _ARGS(x)
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, type, ...) \
type GenericModule::name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__)) { \
return esp_modem::dce_commands::name(dte.get() ESP_MODEM_COMMAND_FORWARD_AFTER(__VA_ARGS__)); }
#include "esp_modem_command_declare.inc"
// Usage examples:
// Zero arguments
// Helper to apply the correct macro to each parameter
//
// 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 GenericModule::name(__VA_ARGS__) { return esp_modem::dce_commands::name(dte.get() ARGS(arg_nr) ); }
DECLARE_ALL_COMMAND_APIS(return_type name(...))
#undef ESP_MODEM_DECLARE_DCE_COMMAND

View File

@ -6,164 +6,5 @@
#pragma once
#include <utility>
#include "cxx_include/esp_modem_netif.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
namespace esp_modem {
/**
* @defgroup ESP_MODEM_DCE
* @brief Definition of DCE abstraction
*/
/** @addtogroup ESP_MODEM_DCE
* @{
*/
/**
* @brief Helper class responsible for switching modes of the DCE's
*/
class DCE_Mode {
public:
DCE_Mode(): mode(modem_mode::UNDEF) {}
~DCE_Mode() = default;
bool set(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
modem_mode get();
modem_mode guess(DTE *dte, bool with_cmux = false);
private:
bool set_unsafe(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
modem_mode guess_unsafe(DTE *dte, bool with_cmux);
modem_mode mode;
};
/**
* @brief General DCE class templated on a specific module. It is responsible for all the necessary transactions
* related to switching modes and consequent synergy with aggregated objects of DTE, Netif and a specific Module
*/
template<class SpecificModule>
class DCE_T {
static_assert(std::is_base_of<ModuleIf, SpecificModule>::value, "DCE must be instantiated with Module class only");
public:
explicit DCE_T(const std::shared_ptr<DTE> &dte, std::shared_ptr<SpecificModule> dev, esp_netif_t *netif):
dte(dte), device(std::move(dev)), netif(dte, netif)
{ }
~DCE_T() = default;
/**
* @brief Set data mode!
*/
void set_data()
{
set_mode(modem_mode::DATA_MODE);
}
void exit_data()
{
set_mode(modem_mode::COMMAND_MODE);
}
void set_cmux()
{
set_mode(modem_mode::CMUX_MODE);
}
SpecificModule *get_module()
{
return device.get();
}
command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms)
{
return dte->command(command, std::move(got_line), time_ms);
}
modem_mode guess_mode(bool with_cmux = false)
{
return mode.guess(dte.get(), with_cmux);
}
bool set_mode(modem_mode m)
{
return mode.set(dte.get(), device.get(), netif, m);
}
modem_mode get_mode()
{
return mode.get();
}
bool recover()
{
return dte->recover();
}
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
void set_urc(got_line_cb on_read_cb)
{
dte->set_urc_cb(on_read_cb);
}
#endif
/**
* @brief Pauses/Unpauses network temporarily
* @param do_pause true to pause, false to unpause
* @param force true to ignore command failures and continue
* @return command_result of the underlying commands
*/
command_result pause_netif(bool do_pause, bool force = false, int delay = 1000)
{
command_result result;
if (do_pause) {
netif.pause();
Task::Delay(delay); // Mandatory 1s pause before
dte->set_command_callbacks();
result = device->set_command_mode();
} else {
result = device->resume_data_mode();
if (result == command_result::OK || force) {
netif.resume();
}
}
return result;
}
protected:
std::shared_ptr<DTE> dte;
std::shared_ptr<SpecificModule> device;
Netif netif;
DCE_Mode mode;
};
/**
* @brief Common abstraction of the modem DCE, specialized by the GenericModule which is a parent class for the supported
* devices and most common modems, as well.
*/
class DCE : public DCE_T<GenericModule> {
public:
using DCE_T<GenericModule>::DCE_T;
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
template <typename ...Agrs> \
return_type name(Agrs&&... args) \
{ \
return device->name(std::forward<Agrs>(args)...); \
}
DECLARE_ALL_COMMAND_APIS(forwards name(...)
{
device->name(...);
} )
#undef ESP_MODEM_DECLARE_DCE_COMMAND
};
/**
* @}
*/
} // esp_modem
#include "cxx_include/esp_modem_dce_template.hpp"
#include "cxx_include/esp_modem_dce_generic.hpp"

View File

@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <utility>
#include "cxx_include/esp_modem_netif.hpp"
#include "cxx_include/esp_modem_dce_module.hpp"
namespace esp_modem {
/**
* @defgroup ESP_MODEM_DCE
* @brief Definition of DCE abstraction
*/
/** @addtogroup ESP_MODEM_DCE
* @{
*/
/**
* @brief Helper class responsible for switching modes of the DCE's
*/
class DCE_Mode {
public:
DCE_Mode(): mode(modem_mode::UNDEF) {}
~DCE_Mode() = default;
bool set(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
modem_mode get();
modem_mode guess(DTE *dte, bool with_cmux = false);
private:
bool set_unsafe(DTE *dte, ModuleIf *module, Netif &netif, modem_mode m);
modem_mode guess_unsafe(DTE *dte, bool with_cmux);
modem_mode mode;
};
/**
* @brief General DCE class templated on a specific module. It is responsible for all the necessary transactions
* related to switching modes and consequent synergy with aggregated objects of DTE, Netif and a specific Module
*/
template<class SpecificModule>
class DCE_T {
static_assert(std::is_base_of<ModuleIf, SpecificModule>::value, "DCE must be instantiated with Module class only");
public:
explicit DCE_T(const std::shared_ptr<DTE> &dte, std::shared_ptr<SpecificModule> dev, esp_netif_t *netif):
dte(dte), device(std::move(dev)), netif(dte, netif)
{ }
~DCE_T() = default;
/**
* @brief Set data mode!
*/
void set_data()
{
set_mode(modem_mode::DATA_MODE);
}
void exit_data()
{
set_mode(modem_mode::COMMAND_MODE);
}
void set_cmux()
{
set_mode(modem_mode::CMUX_MODE);
}
SpecificModule *get_module()
{
return device.get();
}
command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms)
{
return dte->command(command, std::move(got_line), time_ms);
}
modem_mode guess_mode(bool with_cmux = false)
{
return mode.guess(dte.get(), with_cmux);
}
bool set_mode(modem_mode m)
{
return mode.set(dte.get(), device.get(), netif, m);
}
modem_mode get_mode()
{
return mode.get();
}
bool recover()
{
return dte->recover();
}
#ifdef CONFIG_ESP_MODEM_URC_HANDLER
void set_urc(got_line_cb on_read_cb)
{
dte->set_urc_cb(on_read_cb);
}
#endif
/**
* @brief Pauses/Unpauses network temporarily
* @param do_pause true to pause, false to unpause
* @param force true to ignore command failures and continue
* @return command_result of the underlying commands
*/
command_result pause_netif(bool do_pause, bool force = false, int delay = 1000)
{
command_result result;
if (do_pause) {
netif.pause();
Task::Delay(delay); // Mandatory 1s pause before
dte->set_command_callbacks();
result = device->set_command_mode();
} else {
result = device->resume_data_mode();
if (result == command_result::OK || force) {
netif.resume();
}
}
return result;
}
protected:
std::shared_ptr<DTE> dte;
std::shared_ptr<SpecificModule> device;
Netif netif;
DCE_Mode mode;
};
/**
* @}
*/
} // esp_modem

View File

@ -1,28 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "generate/esp_modem_command_declare.inc"
#include "esp_modem_c_api_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
esp_err_t esp_modem_ ## name(esp_modem_dce_t *dce, ##__VA_ARGS__);
DECLARE_ALL_COMMAND_APIS(declares esp_modem_<API>(esp_modem_t *dce, ...);)
#undef ESP_MODEM_DECLARE_DCE_COMMAND
#ifdef __cplusplus
}
#endif

View File

@ -1,27 +0,0 @@
// Parameters
// * handle different parameters for C++ and C API
// * make parameter unique names, so they could be easily referenced and forwarded
#define INT_IN(param, name) int _ARG(param, name)
#ifdef __cplusplus
#define _ARG(param, name) param
#include <string>
#define STRING_IN(param, name) const std::string& _ARG(param, name)
#define STRING_OUT(param, name) std::string& _ARG(param, name)
#define BOOL_IN(param, name) const bool _ARG(param, name)
#define BOOL_OUT(param, name) bool& _ARG(param, name)
#define INT_OUT(param, name) int& _ARG(param, name)
#define INTEGER_LIST_IN(param, name) const int* _ARG(param, name)
#define STRUCT_OUT(struct_name, p1) struct_name& p1
#else
#define _ARG(param, name) name
#define STRING_IN(param, name) const char* _ARG(param, name)
#define STRING_OUT(param, name) char* _ARG(param, name)
#define BOOL_IN(param, name) const bool _ARG(param, name)
#define BOOL_OUT(param, name) bool* _ARG(param, name)
#define INT_OUT(param, name) int* _ARG(param, name)
#define INTEGER_LIST_IN(param, name) const int* _ARG(param, name)
#define STRUCT_OUT(struct_name, p1) esp_modem_ ## struct_name ## _t* p1
#endif

View File

@ -0,0 +1,62 @@
#!/bin/bash
# Default list of files to process if no arguments are provided
default_files=("generate/include/cxx_include/esp_modem_command_library.hpp"
"generate/include/cxx_include/esp_modem_dce_module.hpp"
"generate/include/cxx_include/esp_modem_dce_generic.hpp"
"generate/src/esp_modem_modules.cpp"
"generate/include/esp_modem_api.h")
# Set the processing directory (defaults to the script's location/..)
script_dir="$(dirname "$(realpath "$0")")"
default_processing_dir="$(realpath "$script_dir/..")"
# Parse optional arguments
if [ -n "$1" ]; then
# If one argument is provided, treat it as a single file to process
files=("$1")
else
# Use default list if no file argument is provided
files=("${default_files[@]}")
fi
# If a second argument is provided, set it as the processing directory
if [ -n "$2" ]; then
processing_dir="$(realpath "$2")"
else
processing_dir="$default_processing_dir"
fi
# Process each file
for file in "${files[@]}"; do
# Determine the input and output paths based on processing directory
in_file="$processing_dir/$file"
out_file="${processing_dir}/${file/generate/command}"
current_file_dir="$(dirname "$in_file")"
# Ensure the output directory exists
mkdir -p "$(dirname "$out_file")"
echo "Processing $in_file"
# Process the header and includes -- just paste the content (without expanding)
sed -n '1,/ESP-MODEM command module starts here/{/ESP-MODEM command module starts here/d;p}' "$in_file" > "$out_file"
# Determine whether to use clang or clang++ based on file extension
if [[ $file == *.cpp || $file == *.hpp ]]; then
compiler="clang++ -E -P -CC -xc++"
elif [[ $file == *.rst ]]; then
compiler="clang -E -P -xc"
else
compiler="clang -E -P -CC -xc"
fi
# Preprocess everything else to expand command prototypes or implementations
sed -n '1,/ESP-MODEM command module starts here/!p' "$in_file" | \
$compiler -I"$script_dir" -I"$processing_dir/generate/include" -I"$processing_dir/include" -I"$current_file_dir" - >> "$out_file"
# Add potential footer (typically closing C++ sentinel)
sed -n '1,/ESP-MODEM command module ends here/!p' "$in_file" >> "$out_file"
if [[ $out_file != *.rst ]]; then
astyle --style=otbs --attach-namespaces --attach-classes --indent=spaces=4 --convert-tabs --align-pointer=name --align-reference=name --keep-one-line-statements --pad-header --pad-oper --unpad-paren --quiet --max-continuation-indent=120 "$out_file"
fi
done

View File

@ -815,22 +815,22 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.
INPUT = \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_api.h \
$(PROJECT_PATH)/../components/esp_modem/command/include/esp_modem_api.h \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_c_api_types.h \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_api.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_config.h \
$(PROJECT_PATH)/../components/esp_modem/include/esp_modem_dce_config.h \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dce_factory.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_command_library.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dce_module.hpp \
$(PROJECT_PATH)/../components/esp_modem/command/include/cxx_include/esp_modem_command_library.hpp \
$(PROJECT_PATH)/../components/esp_modem/command/include/cxx_include/esp_modem_dce_module.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dte.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_netif.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_types.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_terminal.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_cmux.hpp \
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dce.hpp \
$(PROJECT_PATH)/../docs/esp_modem/en/esp_modem_api_commands.h \
$(PROJECT_PATH)/../docs/esp_modem/en/esp_modem_dce.hpp
$(PROJECT_PATH)/../components/esp_modem/include/cxx_include/esp_modem_dce_template.hpp \
$(PROJECT_PATH)/../docs/esp_modem/command/dce.h \
$(PROJECT_PATH)/../docs/esp_modem/command/dce.hpp
# The last two are generated

View File

@ -45,7 +45,7 @@ Note that the functions which implement AT commands returning textual values use
pointer as the return value. The API expects the output data to point to user allocated space of at least
``CONFIG_ESP_MODEM_C_API_STR_MAX`` (128 by default) bytes, it also truncates the output data to this size.
.. doxygenfile:: esp_modem_api_commands.h
.. doxygenfile:: dce.h
.. _api_config:

View File

@ -33,7 +33,10 @@ Mode switching commands
Modem commands
--------------
.. include:: cxx_api_links.rst
.. include:: ../command/dce.rst
.. doxygenclass:: esp_modem::DCE
:members:
.. _cpp_destroy:

View File

@ -0,0 +1,6 @@
// --- ESP-MODEM command module starts here ---
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) return_type esp_modem_ ## name (ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
#include "esp_modem_command_declare.inc"

View File

@ -0,0 +1,16 @@
// --- ESP-MODEM command module starts here ---
class esp_modem::DCE : public DCE_T<GenericModule> {
public:
using DCE_T<GenericModule>::DCE_T;
#include "esp_modem_command_declare_helper.inc"
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
return_type name(ESP_MODEM_COMMAND_PARAMS(__VA_ARGS__));
#include "esp_modem_command_declare.inc"
#undef ESP_MODEM_DECLARE_DCE_COMMAND
};

View File

@ -0,0 +1,7 @@
// --- ESP-MODEM command module starts here ---
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, ...) \
* :cpp:func:`esp_modem::DCE::name`
#include "esp_modem_command_declare.inc"

View File

@ -3,15 +3,14 @@
# Cleanup the generated html
rm -rf html docs
# Generate C++ API header of the DCE
cat ../../components/esp_modem/include/generate/esp_modem_command_declare.inc | clang++ -E -P -CC -xc++ -I../../components/esp_modem/include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > en/esp_modem_dce.hpp
pushd `pwd`
# Generate C API header of the modem_api.h
cat ../../components/esp_modem/include/generate/esp_modem_command_declare.inc | clang -E -P -CC -xc -I../../components/esp_modem/include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > en/esp_modem_api_commands.h
cd ../../components/esp_modem/scripts
./generate.sh ../../docs/esp_modem/generate/dce.rst
./generate.sh ../../docs/esp_modem/generate/dce.hpp
./generate.sh ../../docs/esp_modem/generate/dce.h
# RST with links to C++ API
cat ../../components/esp_modem/include/generate/esp_modem_command_declare.inc | clang -E -P -xc -I../../components/esp_modem/include -DGENERATE_DOCS -DGENERATE_RST_LINKS - | sed 's/NL/\n/g' > en/cxx_api_links.rst
popd
build-docs --target esp32 --language en