fix(esp_modem): Cleanup custom lib-commands and factory

This commit is contained in:
David Cermak
2022-10-18 16:57:42 +02:00
parent 652314e73d
commit 65c0e0e195
9 changed files with 113 additions and 94 deletions

View File

@ -96,20 +96,6 @@ menu "Example Configuration"
help help
Pin to unlock the SIM Pin to unlock the SIM
choice EXAMPLE_FLOW_CONTROL
bool "Set preferred modem control flow"
default EXAMPLE_FLOW_CONTROL_NONE
help
Set the modem's preferred control flow
config EXAMPLE_FLOW_CONTROL_NONE
bool "No control flow"
config EXAMPLE_FLOW_CONTROL_SW
bool "SW control flow"
config EXAMPLE_FLOW_CONTROL_HW
bool "HW control flow"
endchoice
menu "UART Configuration" menu "UART Configuration"
depends on EXAMPLE_SERIAL_CONFIG_UART depends on EXAMPLE_SERIAL_CONFIG_UART
config EXAMPLE_MODEM_UART_TX_PIN config EXAMPLE_MODEM_UART_TX_PIN
@ -181,6 +167,21 @@ menu "Example Configuration"
default 1024 default 1024
help help
Buffer size of UART RX buffer. Buffer size of UART RX buffer.
choice EXAMPLE_FLOW_CONTROL
bool "Set preferred modem control flow"
default EXAMPLE_FLOW_CONTROL_NONE
help
Set the modem's preferred control flow
config EXAMPLE_FLOW_CONTROL_NONE
bool "No control flow"
config EXAMPLE_FLOW_CONTROL_SW
bool "SW control flow"
config EXAMPLE_FLOW_CONTROL_HW
bool "HW control flow"
endchoice
endmenu endmenu
endmenu endmenu

View File

@ -197,6 +197,15 @@ void app_main(void)
ESP_LOGI(TAG, "Initializing esp_modem for a generic module..."); ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
esp_modem_dce_t *dce = esp_modem_new(&dte_config, &dce_config, esp_netif); esp_modem_dce_t *dce = esp_modem_new(&dte_config, &dce_config, esp_netif);
#endif #endif
assert(dce);
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
esp_err_t err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
return;
}
ESP_LOGI(TAG, "HW set_flow_control OK");
}
#elif defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB) #elif defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
while (1) { while (1) {
@ -205,26 +214,17 @@ void app_main(void)
const esp_modem_dte_config_t dte_usb_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config); const esp_modem_dte_config_t dte_usb_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
ESP_LOGI(TAG, "Waiting for USB device connection..."); ESP_LOGI(TAG, "Waiting for USB device connection...");
esp_modem_dce_t *dce = esp_modem_new_dev_usb(ESP_MODEM_DCE_BG96, &dte_usb_config, &dce_config, esp_netif); esp_modem_dce_t *dce = esp_modem_new_dev_usb(ESP_MODEM_DCE_BG96, &dte_usb_config, &dce_config, esp_netif);
assert(dce);
esp_modem_set_error_cb(dce, usb_terminal_error_handler); esp_modem_set_error_cb(dce, usb_terminal_error_handler);
vTaskDelay(pdMS_TO_TICKS(1000)); // Although the DTE should be ready after USB enumeration, sometimes it fails to respond without this delay vTaskDelay(pdMS_TO_TICKS(1000)); // Although the DTE should be ready after USB enumeration, sometimes it fails to respond without this delay
#else #else
#error Invalid serial connection to modem. #error Invalid serial connection to modem.
#endif #endif
assert(dce);
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT); xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT);
/* Run the modem demo app */ /* Run the modem demo app */
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
esp_err_t err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
return;
}
ESP_LOGI(TAG, "set_flow_control OK");
}
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1 #if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
// check if PIN needed // check if PIN needed
bool pin_ok = false; bool pin_ok = false;

View File

@ -7,36 +7,37 @@
// Created on: 23.08.2022 // Created on: 23.08.2022
// Author: franz // Author: franz
#include <cstdio>
#include <cstring>
#include <map>
#include <string_view> #include <string_view>
#include <vector>
#include <charconv> #include <charconv>
#include <list> #include <list>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_event.h"
#include "cxx_include/esp_modem_dte.hpp" #include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/esp_modem_dce.hpp" #include "cxx_include/esp_modem_dce.hpp"
#include "esp_modem_config.h" #include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp" #include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/command_library.hpp" #include "cxx_include/esp_modem_command_library_utils.hpp"
#include "esp_log.h" #include "esp_log.h"
#include "SIM7070_gnss.hpp" #include "SIM7070_gnss.hpp"
constexpr auto const TAG = "SIM7070_gnss";
const static char *const TAG = "SIM7070_gnss";
class LocalFactory: public esp_modem::dce_factory::Factory { namespace gnss_factory {
using namespace esp_modem;
using namespace dce_factory;
class LocalFactory: public Factory {
using DCE_gnss_ret = std::unique_ptr<DCE_gnss>; // this custom Factory manufactures only unique_ptr<DCE>'s
public: public:
static std::unique_ptr<DCE_gnss> create(const esp_modem::dce_config *config, std::shared_ptr<esp_modem::DTE> dte, esp_netif_t *netif) static DCE_gnss_ret create(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
{ {
return esp_modem::dce_factory::Factory::build_generic_DCE<SIM7070_gnss, DCE_gnss, std::unique_ptr<DCE_gnss>>(config, dte, netif); return Factory::build_generic_DCE<SIM7070_gnss, DCE_gnss, DCE_gnss_ret>
(config, std::move(dte), netif);
} }
}; };
} // namespace gnss_factory
/** /**
* @brief Helper create method which employs the DCE factory for creating DCE objects templated by a custom module * @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 * @return unique pointer of the resultant DCE
@ -45,19 +46,19 @@ std::unique_ptr<DCE_gnss> create_SIM7070_GNSS_dce(const esp_modem::dce_config *c
std::shared_ptr<esp_modem::DTE> dte, std::shared_ptr<esp_modem::DTE> dte,
esp_netif_t *netif) esp_netif_t *netif)
{ {
return LocalFactory::create(config, std::move(dte), netif); return gnss_factory::LocalFactory::create(config, std::move(dte), netif);
} }
esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::CommandableIf *t, gps_t &gps) esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::CommandableIf *t, esp_modem_gps_t &gps)
{ {
ESP_LOGV(TAG, "%s", __func__ ); ESP_LOGV(TAG, "%s", __func__ );
std::string_view out; std::string str_out;
auto ret = esp_modem::dce_commands::generic_get_string(t, "AT+CGNSINF\r", out); auto ret = esp_modem::dce_commands::generic_get_string(t, "AT+CGNSINF\r", str_out);
if (ret != esp_modem::command_result::OK) { if (ret != esp_modem::command_result::OK) {
return ret; return ret;
} }
std::string_view out(str_out);
constexpr std::string_view pattern = "+CGNSINF: "; constexpr std::string_view pattern = "+CGNSINF: ";
@ -329,12 +330,12 @@ esp_modem::command_result get_gnss_information_sim70xx_lib(esp_modem::Commandabl
return esp_modem::command_result::OK; return esp_modem::command_result::OK;
} }
esp_modem::command_result SIM7070_gnss::get_gnss_information_sim70xx(gps_t &gps) esp_modem::command_result SIM7070_gnss::get_gnss_information_sim70xx(esp_modem_gps_t &gps)
{ {
return get_gnss_information_sim70xx_lib(dte.get(), gps); return get_gnss_information_sim70xx_lib(dte.get(), gps);
} }
esp_modem::command_result DCE_gnss::get_gnss_information_sim70xx(gps_t &gps) esp_modem::command_result DCE_gnss::get_gnss_information_sim70xx(esp_modem_gps_t &gps)
{ {
return device->get_gnss_information_sim70xx(gps); return device->get_gnss_information_sim70xx(gps);
} }

View File

@ -16,15 +16,19 @@
#include "nmea_parser.h" #include "nmea_parser.h"
/** /**
* @brief Definition of a custom modem which inherits from the GenericModule, uses all its methods * @brief Definition of a custom SIM7070 class with GNSS capabilities.
* and could override any of them. Here, for demonstration purposes only, we redefine just `get_module_name()` * 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 { class SIM7070_gnss: public esp_modem::SIM7070 {
using SIM7070::SIM7070; using SIM7070::SIM7070;
public: public:
esp_modem::command_result get_gnss_information_sim70xx(gps_t &gps); esp_modem::command_result get_gnss_information_sim70xx(esp_modem_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> { class DCE_gnss : public esp_modem::DCE_T<SIM7070_gnss> {
public: public:
@ -43,14 +47,14 @@ public:
#undef ESP_MODEM_DECLARE_DCE_COMMAND #undef ESP_MODEM_DECLARE_DCE_COMMAND
esp_modem::command_result get_gnss_information_sim70xx(gps_t &gps); esp_modem::command_result get_gnss_information_sim70xx(esp_modem_gps_t &gps);
}; };
/** /**
* @brief Helper create method which employs the DCE factory for creating DCE objects templated by a custom module * @brief Helper create method which employs the customized DCE factory for building DCE_gnss objects
* @return unique pointer of the resultant DCE * @return unique pointer of the specific DCE
*/ */
std::unique_ptr<DCE_gnss> create_SIM7070_GNSS_dce(const esp_modem::dce_config *config, std::unique_ptr<DCE_gnss> create_SIM7070_GNSS_dce(const esp_modem::dce_config *config,
std::shared_ptr<esp_modem::DTE> dte, std::shared_ptr<esp_modem::DTE> dte,

View File

@ -97,7 +97,7 @@ typedef enum {
* @brief GPS object * @brief GPS object
* *
*/ */
struct gps_s { struct esp_modem_gps {
float latitude; /*!< Latitude (degrees) */ float latitude; /*!< Latitude (degrees) */
float longitude; /*!< Longitude (degrees) */ float longitude; /*!< Longitude (degrees) */
float altitude; /*!< Altitude (meters) */ float altitude; /*!< Altitude (meters) */
@ -117,11 +117,7 @@ struct gps_s {
float vpa; /*!< Vertical Position Accuracy */ float vpa; /*!< Vertical Position Accuracy */
}; };
typedef struct gps_s gps_t; typedef struct esp_modem_gps esp_modem_gps_t;
typedef struct gps_s esp_modem_gps_s_t;
/** /**
* @brief NMEA Parser Event ID * @brief NMEA Parser Event ID

View File

@ -195,7 +195,7 @@ extern "C" void app_main(void)
#if CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070_GNSS == 1 #if CONFIG_EXAMPLE_MODEM_DEVICE_SIM7070_GNSS == 1
gps_t gps; esp_modem_gps_t gps;
for (int i = 0; i < 200; ++i) { for (int i = 0; i < 200; ++i) {
if (dce->get_gnss_information_sim70xx(gps) == esp_modem::command_result::OK) { if (dce->get_gnss_information_sim70xx(gps) == esp_modem::command_result::OK) {

View File

@ -1,27 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
namespace esp_modem::dce_commands {
command_result generic_command(CommandableIf *t, const std::string &command,
const std::list<std::string_view> &pass_phrase,
const std::list<std::string_view> &fail_phrase,
uint32_t timeout_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);
command_result generic_get_string(CommandableIf *t, const std::string &command, std::string_view &output, uint32_t timeout_ms = 500);
command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms = 500);
command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout = 500);
} // esp_modem::dce_commands

View File

@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
namespace esp_modem::dce_commands {
/**
* @brief Generic command that passes on supplied pass_phrase, and fails on fail_phrase
* @param t Any "Command-able" class that implements "command()" method
* @param command Command to issue
* @param pass_phrase Pattern to find in replies to complete the command successfully
* @param fail_phrase If this pattern found the command fails immediately
* @param timeout_ms Command timeout in ms
* @return Generic command return type (OK, FAIL, TIMEOUT)
*/
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 Utility command to send command and return reply (after DCE says OK)
* @param t Anything that is "command-able"
* @param command Command to issue
* @param output String to return
* @param timeout_ms
* @param timeout_ms Command timeout in ms
* @return Generic command return type (OK, FAIL, TIMEOUT)
*/
command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms = 500);
/**
* @brief Generic command that passes on "OK" and fails on "ERROR"
* @param t Anything that is "command-able"
* @param command Command to issue
* @param timeout
* @param timeout_ms Command timeout in ms
* @return Generic command return type (OK, FAIL, TIMEOUT)
*/
command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout_ms = 500);
} // esp_modem::dce_commands

View File

@ -10,17 +10,16 @@
#include "cxx_include/esp_modem_dte.hpp" #include "cxx_include/esp_modem_dte.hpp"
#include "cxx_include/esp_modem_dce_module.hpp" #include "cxx_include/esp_modem_dce_module.hpp"
#include "cxx_include/esp_modem_command_library.hpp" #include "cxx_include/esp_modem_command_library.hpp"
#include "cxx_include/command_library.hpp" #include "cxx_include/esp_modem_command_library_utils.hpp"
namespace esp_modem::dce_commands { namespace esp_modem::dce_commands {
static const char *TAG = "command_lib"; static const char *TAG = "command_lib";
command_result generic_command(CommandableIf *t, const std::string &command, static command_result generic_command(CommandableIf *t, const std::string &command,
const std::list<std::string_view> &pass_phrase, const std::list<std::string_view> &pass_phrase,
const std::list<std::string_view> &fail_phrase, const std::list<std::string_view> &fail_phrase,
uint32_t timeout_ms) uint32_t timeout_ms)
{ {
ESP_LOGD(TAG, "%s command %s\n", __func__, command.c_str()); ESP_LOGD(TAG, "%s command %s\n", __func__, command.c_str());
return t->command(command, [&](uint8_t *data, size_t len) { return t->command(command, [&](uint8_t *data, size_t len) {
@ -52,7 +51,7 @@ command_result generic_command(CommandableIf *t, const std::string &command,
return generic_command(t, command, pass, fail, timeout_ms); return generic_command(t, command, pass, fail, timeout_ms);
} }
command_result generic_get_string(CommandableIf *t, const std::string &command, std::string_view &output, uint32_t timeout_ms) static command_result generic_get_string(CommandableIf *t, const std::string &command, std::string_view &output, uint32_t timeout_ms = 500)
{ {
ESP_LOGV(TAG, "%s", __func__ ); ESP_LOGV(TAG, "%s", __func__ );
return t->command(command, [&](uint8_t *data, size_t len) { return t->command(command, [&](uint8_t *data, size_t len) {
@ -91,10 +90,10 @@ command_result generic_get_string(CommandableIf *t, const std::string &command,
} }
command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout) command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout_ms)
{ {
ESP_LOGV(TAG, "%s", __func__ ); ESP_LOGV(TAG, "%s", __func__ );
return generic_command(t, command, "OK", "ERROR", timeout); return generic_command(t, command, "OK", "ERROR", timeout_ms);
} }
command_result sync(CommandableIf *t) command_result sync(CommandableIf *t)