Skip to content

Commit

Permalink
Merge pull request #413 from david-cermak/feat/new_modem_cmd
Browse files Browse the repository at this point in the history
Added support for implementing user defined modules in standard C-API
  • Loading branch information
david-cermak authored Nov 16, 2023
2 parents f50edd4 + 020b407 commit cc40cc1
Show file tree
Hide file tree
Showing 11 changed files with 587 additions and 444 deletions.
3 changes: 3 additions & 0 deletions components/esp_modem/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ set_target_properties(${COMPONENT_LIB} PROPERTIES
CXX_EXTENSIONS ON
)

if(CONFIG_ESP_MODEM_ADD_CUSTOM_MODULE)
idf_component_optional_requires(PUBLIC main)
endif()

if(${target} STREQUAL "linux")
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
Expand Down
18 changes: 18 additions & 0 deletions components/esp_modem/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,22 @@ menu "esp-modem"
to make the protocol more robust on noisy environments or when underlying
transport gets corrupted often (for example by Rx buffer overflows)

config ESP_MODEM_ADD_CUSTOM_MODULE
bool "Add support for custom module in C-API"
default n
help
If enabled, we adapt the C-API to create a DCE from a user defined class

config ESP_MODEM_CUSTOM_MODULE_HEADER
string "Header file name which defines custom DCE creation"
depends on ESP_MODEM_ADD_CUSTOM_MODULE
default "custom_module.hpp"
help
Name of the header file in the main component which implements esp_modem_create_custom_dce()
called from C-API for creating esp_modem_dce object.
This header provides definition of the custom module with some additional and/or updated commands
and API. It also defines creation of DCE based on this custom module, typically calling:
dce_factory::Factory::create_unique_dce_from<CustomModule, DCE*>(dce_config, std::move(dte), netif)
Please refer to the pppos_client example for more details.

endmenu
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ menu "Example Configuration"
bool "A7670"
help
A7670X is Multi-Band LTE-FDD/LTE-TDD/GSM/GPRS/EDGE module.

config EXAMPLE_MODEM_DEVICE_CUSTOM
select ESP_MODEM_ADD_CUSTOM_MODULE
bool "Custom device"
help
This demonstrates use of a custom device in C-API.

endchoice

config EXAMPLE_MODEM_PPP_APN
Expand Down
79 changes: 79 additions & 0 deletions components/esp_modem/examples/pppos_client/main/custom_module.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/

#pragma once
#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_command_library_utils.hpp"

/**
* @brief Definition of a custom module based on some already defined module
* Here we use GenericModule, but you can use any kind of device
* that is closer to your CustomModule.
*/
class SIM7600_WITH_TIME: public GenericModule {
/**
* @brief Need to reuse the constructors of our ancestor
*/
using GenericModule::GenericModule;
public:
/**
* @brief New command that is not defined in the GenericModule
*/
command_result get_time(std::string &time)
{
return esp_modem::dce_commands::generic_get_string(dte.get(), "AT+CCLK?\r", time);
}

/**
* @brief This command is already defined in the GenericModule
*
* Here we just modify get_signal_quality() to return zeroes
* for demonstration purpose only, since it's called within this example
*/
command_result get_signal_quality(int &rssi, int &ber) override
{
rssi = ber = 0;
return esp_modem::command_result::OK;
}

};

/**
* @brief esp_modem_create_custom_dce() needs to be defined, as it is called in C-API wrapper when creating esp_modem_dce
*
* This uses public factory function for creating a common DCE with our CustomModule. Creating raw DCE pointer is only needed
* for the C-API wrapper; C++API users would create DCE (any kind of smart pointer) directly with
* Factory::create_unique_dce_from<CustomModule>(dce_config, std::move(dte), netif);
*/
DCE *esp_modem_create_custom_dce(const esp_modem_dce_config_t *dce_config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
{
return dce_factory::Factory::create_unique_dce_from<SIM7600_WITH_TIME, DCE *>(dce_config, std::move(dte), netif);
}

/**
* @brief This API is only needed for extending standard C-API, since we added get_time() method to our CustomModule
*
* @note This header is included from esp_modem_c_api.cpp, so it could use ESP_MODEM_C_API_STR_MAX macro
* indicating maximum C-API string size
*
* @note In order to access the newly added API get_time(), we have to static_cast<> the GenericModule from DCE
* to our CustomModule.
* Alternatively we could use the modem Factory to build our specific DCE_T<CustomModule>, but in that case
* we couldn't use our C-API wrappers which expect DCE type, DCE_T<GenericModule> with lib commands (this alternative
* is cleaner, but more suitable for C++ users)
*/
extern "C" esp_err_t esp_modem_get_time(esp_modem_dce_t *dce_wrap, char *p_time)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string time{ESP_MODEM_C_API_STR_MAX};
auto ret = command_response_to_esp_err(static_cast<SIM7600_WITH_TIME *>(dce_wrap->dce->get_module())->get_time(time));
if (ret == ESP_OK && !time.empty()) {
strlcpy(p_time, time.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ static const int CONNECT_BIT = BIT0;
static const int GOT_DATA_BIT = BIT2;
static const int USB_DISCONNECTED_BIT = BIT3; // Used only with USB DTE but we define it unconditionally, to avoid too many #ifdefs in the code

#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_CUSTOM
esp_err_t esp_modem_get_time(esp_modem_dce_t *dce_wrap, char *p_time);
#endif

#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
#include "esp_modem_usb_c_api.h"
#include "esp_modem_usb_config.h"
Expand Down Expand Up @@ -192,6 +196,9 @@ void app_main(void)
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7600 module...");
esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM7600, &dte_config, &dce_config, esp_netif);
#elif CONFIG_EXAMPLE_MODEM_DEVICE_CUSTOM == 1
ESP_LOGI(TAG, "Initializing esp_modem with custom module...");
esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_CUSTOM, &dte_config, &dce_config, esp_netif);
#else
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
esp_modem_dce_t *dce = esp_modem_new(&dte_config, &dce_config, esp_netif);
Expand Down Expand Up @@ -258,6 +265,18 @@ void app_main(void)
}
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);

#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_CUSTOM
{
char time[64];
err = esp_modem_get_time(dce, time);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_modem_get_time failed with %d %s", err, esp_err_to_name(err));
return;
}
ESP_LOGI(TAG, "esp_modem_get_time: %s", time);
}
#endif

#if CONFIG_EXAMPLE_SEND_MSG
if (esp_modem_sms_txt_mode(dce, true) != ESP_OK || esp_modem_sms_character_set(dce) != ESP_OK) {
ESP_LOGE(TAG, "Setting text mode or GSM character set failed");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -12,6 +12,7 @@
* @brief DCE modem factory
*/

#define esp_modem_create_dce_from dce_factory::Factory::create_unique_dce_from

namespace esp_modem::dce_factory {

Expand Down Expand Up @@ -236,12 +237,12 @@ class Factory {
return nullptr;
}

template <typename T_Module>
static std::unique_ptr<DCE> create_unique_dce_from(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
template <typename T_Module, typename Ptr = std::unique_ptr<DCE>>
static Ptr create_unique_dce_from(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif)
{
return build_generic_DCE<T_Module, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
return build_generic_DCE<T_Module, DCE, Ptr>(config, std::move(dte), netif);
}

private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class CommandableIf {
* @param command Command to be sent
* @param got_line callback if a line received
* @param time_ms timeout in milliseconds
* @param separator Character treated as a line separator, typically '\n'
* @return OK, FAIL or TIMEOUT
*/
virtual command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator) = 0;
Expand Down
1 change: 1 addition & 0 deletions components/esp_modem/include/esp_modem_c_api_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ typedef enum esp_modem_dce_device {
ESP_MODEM_DCE_SIM7000,
ESP_MODEM_DCE_BG96,
ESP_MODEM_DCE_SIM800,
ESP_MODEM_DCE_CUSTOM
} esp_modem_dce_device_t;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ ESP_MODEM_DECLARE_DCE_COMMAND(sync, command_result, 0) \
\
/**
* @brief Reads the operator name
* @param[out] operator name
* @param[out] access technology
* @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)) \
Expand All @@ -46,7 +46,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
\
/**
* @brief Execute the supplied AT command
* @param[in] at 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
Expand Down Expand Up @@ -252,6 +252,8 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_preferred_mode, command_result, 1, INT_IN(p1,
/**
* @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)) \
Expand Down
Loading

0 comments on commit cc40cc1

Please sign in to comment.