From ae38110d845581e6c8dc8817947c6c4ed9562f76 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 8 Jan 2024 19:00:20 +0100 Subject: [PATCH] feat(modem): Added support for at_raw() command at_raw() sends raw string and supports custom pass/fail phrases for the API to return OK/FAIL. It also returns raw, unprocessed string as output. This allows sending custom requests, such as: * dce->at_raw("", resp, "RDY", "...", 20000) -- waiting for reset * esp_modem_at_raw(dce, "+++", resp, "DISCONNECTED", "ERROR", 5000) -- exits PPP mode Closes https://github.com/espressif/esp-protocols/issues/471 Partially addresses https://github.com/espressif/esp-protocols/issues/468 --- .../generate/esp_modem_command_declare.inc | 12 ++++++++++++ components/esp_modem/src/esp_modem_c_api.cpp | 18 ++++++++++++++++-- .../src/esp_modem_command_library.cpp | 18 +++++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/components/esp_modem/include/generate/esp_modem_command_declare.inc b/components/esp_modem/include/generate/esp_modem_command_declare.inc index 70f3a83be..909d71603 100644 --- a/components/esp_modem/include/generate/esp_modem_command_declare.inc +++ b/components/esp_modem/include/generate/esp_modem_command_declare.inc @@ -44,6 +44,18 @@ ESP_MODEM_DECLARE_DCE_COMMAND(store_profile, command_result, 0) \ */\ ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, 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] cmd String command that's send to DTE + * @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)) \ + \ /** * @brief Execute the supplied AT command * @param[in] cmd AT command diff --git a/components/esp_modem/src/esp_modem_c_api.cpp b/components/esp_modem/src/esp_modem_c_api.cpp index 7178bda1a..6c32cf8c6 100644 --- a/components/esp_modem/src/esp_modem_c_api.cpp +++ b/components/esp_modem/src/esp_modem_c_api.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,7 +17,7 @@ #include "esp_private/c_api_wrapper.hpp" #ifndef ESP_MODEM_C_API_STR_MAX -#define ESP_MODEM_C_API_STR_MAX 64 +#define ESP_MODEM_C_API_STR_MAX 128 #endif #ifndef HAVE_STRLCPY @@ -206,6 +206,20 @@ extern "C" esp_err_t esp_modem_get_imsi(esp_modem_dce_t *dce_wrap, char *p_imsi) return ret; } +extern "C" esp_err_t esp_modem_at_raw(esp_modem_dce_t *dce_wrap, const char *cmd, char *p_out, const char *pass, const char *fail, int timeout) +{ + if (dce_wrap == nullptr || dce_wrap->dce == nullptr) { + return ESP_ERR_INVALID_ARG; + } + std::string out; + auto ret = command_response_to_esp_err(dce_wrap->dce->at_raw(cmd, out, pass, fail, timeout)); + if ((p_out != NULL) && (!out.empty())) { + strlcpy(p_out, out.c_str(), ESP_MODEM_C_API_STR_MAX); + } + return ret; +} + + extern "C" esp_err_t esp_modem_set_flow_control(esp_modem_dce_t *dce_wrap, int dce_flow, int dte_flow) { if (dce_wrap == nullptr || dce_wrap->dce == nullptr) { diff --git a/components/esp_modem/src/esp_modem_command_library.cpp b/components/esp_modem/src/esp_modem_command_library.cpp index 976869e51..6226f151c 100644 --- a/components/esp_modem/src/esp_modem_command_library.cpp +++ b/components/esp_modem/src/esp_modem_command_library.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -394,6 +394,22 @@ command_result at(CommandableIf *t, const std::string &cmd, std::string &out, in return generic_get_string(t, at_command, out, timeout); } +command_result at_raw(CommandableIf *t, const std::string &cmd, std::string &out, const std::string &pass, const std::string &fail, int timeout = 500) +{ + ESP_LOGV(TAG, "%s", __func__ ); + return t->command(cmd, [&](uint8_t *data, size_t len) { + out.assign(reinterpret_cast(data), len); + + if (out.find(pass) != std::string::npos) { + return command_result::OK; + } else if (out.find(fail) != std::string::npos) { + return command_result::FAIL; + } + + return command_result::TIMEOUT; + }, timeout); +} + command_result get_signal_quality(CommandableIf *t, int &rssi, int &ber) { ESP_LOGV(TAG, "%s", __func__ );