Skip to content

Commit c61fe1f

Browse files
committed
demo(esp_modem): console uses DCE commandable to handle URC
1 parent a299192 commit c61fe1f

File tree

6 files changed

+189
-7
lines changed

6 files changed

+189
-7
lines changed

components/esp_modem/examples/modem_console/main/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
idf_component_register(SRCS "modem_console_main.cpp"
22
"console_helper.cpp"
3+
"my_module_dce.cpp"
34
"httpget_handle.c"
45
"ping_handle.c"
56
REQUIRES console esp_http_client nvs_flash

components/esp_modem/examples/modem_console/main/modem_console_main.cpp

+20-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ using namespace esp_modem;
5959
static SignalGroup exit_signal;
6060

6161

62+
command_result handle_urc(uint8_t *data, size_t len)
63+
{
64+
ESP_LOG_BUFFER_HEXDUMP("on_read", data, len, ESP_LOG_INFO);
65+
return command_result::TIMEOUT;
66+
}
67+
6268
extern "C" void app_main(void)
6369
{
6470
ESP_ERROR_CHECK(nvs_flash_init());
@@ -216,8 +222,9 @@ extern "C" void app_main(void)
216222

217223
const ConsoleCommand GetOperatorName("get_operator_name", "reads the operator name", no_args, [&](ConsoleCommand * c) {
218224
std::string operator_name;
225+
int act;
219226
ESP_LOGI(TAG, "Reading operator name...");
220-
CHECK_ERR(dce->get_operator_name(operator_name), ESP_LOGI(TAG, "OK. Operator name: %s", operator_name.c_str()));
227+
CHECK_ERR(dce->get_operator_name(operator_name, act), ESP_LOGI(TAG, "OK. Operator name: %s", operator_name.c_str()));
221228
});
222229

223230
const struct GenericCommandArgs {
@@ -269,6 +276,18 @@ extern "C" void app_main(void)
269276
ESP_LOGI(TAG, "Resetting the module...");
270277
CHECK_ERR(dce->reset(), ESP_LOGI(TAG, "OK"));
271278
});
279+
const ConsoleCommand HandleURC("urc", "toggle urc handling", no_args, [&](ConsoleCommand * c) {
280+
static int cnt = 0;
281+
if (++cnt % 2) {
282+
ESP_LOGI(TAG, "Adding URC handler");
283+
dce->set_on_read(handle_urc);
284+
} else {
285+
ESP_LOGI(TAG, "URC removed");
286+
dce->set_on_read(nullptr);
287+
}
288+
return 0;
289+
});
290+
272291
const struct SetApn {
273292
SetApn(): apn(STR1, nullptr, nullptr, "<apn>", "APN (Access Point Name)") {}
274293
CommandArgs apn;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/* Modem console example: Custom DCE
2+
3+
This example code is in the Public Domain (or CC0 licensed, at your option.)
4+
5+
Unless required by applicable law or agreed to in writing, this
6+
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7+
CONDITIONS OF ANY KIND, either express or implied.
8+
*/
9+
10+
#include <cstring>
11+
#include "cxx_include/esp_modem_api.hpp"
12+
#include "cxx_include/esp_modem_dce_module.hpp"
13+
#include "generate/esp_modem_command_declare.inc"
14+
#include "my_module_dce.hpp"
15+
16+
using namespace esp_modem;
17+
18+
//
19+
// Define preprocessor's forwarding to dce_commands definitions
20+
//
21+
22+
// Helper macros to handle multiple arguments of declared API
23+
#define ARGS0
24+
#define ARGS1 , p1
25+
#define ARGS2 , p1 , p2
26+
#define ARGS3 , p1 , p2 , p3
27+
#define ARGS4 , p1 , p2 , p3, p4
28+
#define ARGS5 , p1 , p2 , p3, p4, p5
29+
#define ARGS6 , p1 , p2 , p3, p4, p5, p6
30+
31+
#define _ARGS(x) ARGS ## x
32+
#define ARGS(x) _ARGS(x)
33+
34+
//
35+
// Repeat all declarations and forward to the AT commands defined in esp_modem::dce_commands:: namespace
36+
//
37+
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, arg_nr, ...) \
38+
return_type Shiny::DCE::name(__VA_ARGS__) { return esp_modem::dce_commands::name(this ARGS(arg_nr) ); }
39+
40+
DECLARE_ALL_COMMAND_APIS(return_type name(...) )
41+
42+
#undef ESP_MODEM_DECLARE_DCE_COMMAND
43+
44+
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
45+
std::shared_ptr<esp_modem::DTE> dte,
46+
esp_netif_t *netif)
47+
{
48+
return Shiny::Factory::create(config, std::move(dte), netif);
49+
}
50+
51+
command_result Shiny::DCE::command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms, const char separator)
52+
{
53+
if (!handling_urc) {
54+
return dte->command(cmd, got_line, time_ms, separator);
55+
}
56+
handle_cmd = got_line;
57+
signal.clear(3);
58+
dte->write_cmd((uint8_t *)cmd.c_str(), cmd.length());
59+
signal.wait_any(3, time_ms);
60+
handle_cmd = nullptr;
61+
if (signal.is_any(1)) {
62+
return esp_modem::command_result::OK;
63+
}
64+
if (signal.is_any(2)) {
65+
return esp_modem::command_result::FAIL;
66+
}
67+
return esp_modem::command_result::TIMEOUT;
68+
}
69+
70+
command_result Shiny::DCE::handle_data(uint8_t *data, size_t len)
71+
{
72+
if (std::memchr(data, '\n', len)) {
73+
if (handle_urc) {
74+
handle_urc(data, len);
75+
}
76+
if (handle_cmd) {
77+
auto ret = handle_cmd(data, len);
78+
if (ret == esp_modem::command_result::TIMEOUT) {
79+
return command_result::TIMEOUT;
80+
}
81+
if (ret == esp_modem::command_result::OK) {
82+
signal.set(1);
83+
}
84+
if (ret == esp_modem::command_result::FAIL) {
85+
signal.set(2);
86+
}
87+
}
88+
}
89+
return command_result::TIMEOUT;
90+
}

components/esp_modem/examples/modem_console/main/my_module_dce.hpp

+71-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#pragma once
1111

1212

13+
#include <utility>
14+
1315
#include "cxx_include/esp_modem_dce_factory.hpp"
1416
#include "cxx_include/esp_modem_dce_module.hpp"
1517

@@ -27,13 +29,76 @@ class MyShinyModem: public esp_modem::GenericModule {
2729
}
2830
};
2931

32+
namespace Shiny {
33+
34+
using namespace esp_modem;
35+
36+
class DCE : public esp_modem::DCE_T<MyShinyModem>, public CommandableIf {
37+
public:
38+
using DCE_T<MyShinyModem>::DCE_T;
39+
40+
command_result
41+
command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms) override {
42+
return command(cmd, got_line, time_ms, '\n');
43+
}
44+
45+
command_result
46+
command(const std::string &cmd, got_line_cb got_line, uint32_t time_ms, const char separator) override;
47+
48+
int write(uint8_t *data, size_t len) override { return dte->write(data, len); }
49+
50+
void on_read(got_line_cb on_data) override { return dte->on_read(on_data); }
51+
52+
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
53+
esp_modem::return_type name(__VA_ARGS__);
54+
55+
DECLARE_ALL_COMMAND_APIS(forwards name(...))
56+
57+
#undef ESP_MODEM_DECLARE_DCE_COMMAND
58+
59+
void set_on_read(esp_modem::got_line_cb on_read_cb) {
60+
if (on_read_cb == nullptr) {
61+
handling_urc = false;
62+
handle_urc = nullptr;
63+
dte->on_read(nullptr);
64+
return;
65+
}
66+
handle_urc = std::move(on_read_cb);
67+
dte->on_read([this](uint8_t *data, size_t len) {
68+
this->handle_data(data, len);
69+
return command_result::TIMEOUT;
70+
});
71+
handling_urc = true;
72+
}
73+
74+
private:
75+
got_line_cb handle_urc{nullptr};
76+
got_line_cb handle_cmd{nullptr};
77+
SignalGroup signal;
78+
bool handling_urc {false};
79+
80+
command_result handle_data(uint8_t *data, size_t len);
81+
82+
};
83+
84+
class Factory: public ::esp_modem::dce_factory::Factory{
85+
public:
86+
87+
static std::unique_ptr<DCE> create(const esp_modem::dce_config *config,
88+
std::shared_ptr<esp_modem::DTE> dte,
89+
esp_netif_t *netif)
90+
{
91+
return build_generic_DCE<MyShinyModem, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
92+
}
93+
94+
};
95+
96+
} // namespace Shiny
97+
3098
/**
3199
* @brief Helper create method which employs the DCE factory for creating DCE objects templated by a custom module
32100
* @return unique pointer of the resultant DCE
33101
*/
34-
std::unique_ptr<esp_modem::DCE> create_shiny_dce(const esp_modem::dce_config *config,
35-
std::shared_ptr<esp_modem::DTE> dte,
36-
esp_netif_t *netif)
37-
{
38-
return esp_modem::dce_factory::Factory::build_unique<MyShinyModem>(config, std::move(dte), netif);
39-
}
102+
std::unique_ptr<Shiny::DCE> create_shiny_dce(const esp_modem::dce_config *config,
103+
std::shared_ptr<esp_modem::DTE> dte,
104+
esp_netif_t *netif);

components/esp_modem/include/cxx_include/esp_modem_dte.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class DTE : public CommandableIf {
6161
*/
6262
int write(uint8_t *data, size_t len) override;
6363

64+
int write_cmd(uint8_t *data, size_t len);
65+
6466
/**
6567
* @brief Reading from the underlying terminal
6668
* @param d Returning the data pointer of the received payload

components/esp_modem/src/esp_modem_dte.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ int DTE::write(uint8_t *data, size_t len)
176176
return data_term->write(data, len);
177177
}
178178

179+
int DTE::write_cmd(uint8_t *data, size_t len)
180+
{
181+
return command_term->write(data, len);
182+
}
183+
179184
void DTE::on_read(got_line_cb on_read_cb)
180185
{
181186
if (on_read_cb == nullptr) {

0 commit comments

Comments
 (0)