Skip to content

Commit 457f833

Browse files
authored
Merge pull request #169 from david-cermak/feat/modem_dce_on_read
fix(esp-modem): Extend CMUX mode to support manual transitions
2 parents 42565ff + 2180ab1 commit 457f833

File tree

7 files changed

+198
-79
lines changed

7 files changed

+198
-79
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,17 @@ extern "C" void app_main(void)
210210
if (c->get_count_of(&SetModeArgs::mode)) {
211211
auto mode = c->get_string_of(&SetModeArgs::mode);
212212
modem_mode dev_mode;
213-
if (mode == "CMD") {
213+
if (mode == "CMUX1") {
214+
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_MODE;
215+
} else if (mode == "CMUX2") {
216+
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_EXIT;
217+
} else if (mode == "CMUX3") {
218+
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_SWAP;
219+
} else if (mode == "CMUX4") {
220+
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_DATA;
221+
} else if (mode == "CMUX5") {
222+
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_COMMAND;
223+
} else if (mode == "CMD") {
214224
dev_mode = esp_modem::modem_mode::COMMAND_MODE;
215225
} else if (mode == "PPP") {
216226
dev_mode = esp_modem::modem_mode::DATA_MODE;

components/esp_modem/include/cxx_include/esp_modem_dte.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ class DTE : public CommandableIf {
116116
Lock internal_lock{}; /*!< Locks DTE operations */
117117
unique_buffer buffer; /*!< DTE buffer */
118118
std::shared_ptr<CMux> cmux_term; /*!< Primary terminal for this DTE */
119-
std::shared_ptr<Terminal> command_term; /*!< Reference to the terminal used for sending commands */
120-
std::shared_ptr<Terminal> data_term; /*!< Secondary terminal for this DTE */
119+
std::shared_ptr<Terminal> primary_term; /*!< Reference to the primary terminal (mostly for sending commands) */
120+
std::shared_ptr<Terminal> secondary_term; /*!< Secondary terminal for this DTE */
121121
modem_mode mode; /*!< DTE operation mode */
122122
SignalGroup signal; /*!< Event group used to signal request-response operations */
123123
command_result result; /*!< Command result of the currently exectuted command */

components/esp_modem/include/cxx_include/esp_modem_types.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@ enum class modem_mode {
2929
UNDEF,
3030
COMMAND_MODE, /*!< Command mode -- the modem is supposed to send AT commands in this mode */
3131
DATA_MODE, /*!< Data mode -- the modem communicates with network interface on PPP protocol */
32-
CMUX_MODE /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
32+
CMUX_MODE, /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
3333
* assigning one solely to command interface and the other to the data mode */
34+
CMUX_MANUAL_MODE, /*!< Enter CMUX mode manually -- just creates two virtual terminals */
35+
CMUX_MANUAL_EXIT, /*!< Exits CMUX mode manually -- just destroys two virtual terminals */
36+
CMUX_MANUAL_DATA, /*!< Sets the primary terminal to DATA mode in manual CMUX */
37+
CMUX_MANUAL_COMMAND, /*!< Sets the primary terminal to COMMAND mode in manual CMUX */
38+
CMUX_MANUAL_SWAP, /*!< Swaps virtual terminals in manual CMUX mode (primary <-> secondary) */
3439
};
3540

3641
/**

components/esp_modem/include/esp_modem_c_api_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ typedef enum esp_modem_dce_mode {
3636
ESP_MODEM_MODE_COMMAND, /**< Default mode after modem startup, used for sending AT commands */
3737
ESP_MODEM_MODE_DATA, /**< Used for switching to PPP mode for the modem to connect to a network */
3838
ESP_MODEM_MODE_CMUX, /**< Multiplexed terminal mode */
39+
ESP_MODEM_MODE_CMUX_MANUAL, /**< CMUX manual mode */
40+
ESP_MODEM_MODE_CMUX_MANUAL_EXIT, /**< Exit CMUX manual mode */
41+
ESP_MODEM_MODE_CMUX_MANUAL_SWAP, /**< Swap terminals in CMUX manual mode */
42+
ESP_MODEM_MODE_CMUX_MANUAL_DATA, /**< Set DATA mode in CMUX manual mode */
43+
ESP_MODEM_MODE_CMUX_MANUAL_COMMAND, /**< Set COMMAND mode in CMUX manual mode */
3944
} esp_modem_dce_mode_t;
4045

4146
/**
@@ -113,6 +118,8 @@ esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce, esp_modem_terminal_error_
113118
*/
114119
esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce, esp_modem_dce_mode_t mode);
115120

121+
esp_err_t esp_modem_command(esp_modem_dce_t *dce, const char *command, esp_err_t(*got_line_cb)(uint8_t *data, size_t len), uint32_t timeout_ms);
122+
116123
/**
117124
* @}
118125
*/

components/esp_modem/src/esp_modem_c_api.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,23 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce
9393
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
9494
return ESP_ERR_INVALID_ARG;
9595
}
96-
if (mode == ESP_MODEM_MODE_DATA) {
96+
switch (mode) {
97+
case ESP_MODEM_MODE_DATA:
9798
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
98-
}
99-
if (mode == ESP_MODEM_MODE_COMMAND) {
99+
case ESP_MODEM_MODE_COMMAND:
100100
return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL;
101-
}
102-
if (mode == ESP_MODEM_MODE_CMUX) {
101+
case ESP_MODEM_MODE_CMUX:
103102
return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL;
103+
case ESP_MODEM_MODE_CMUX_MANUAL:
104+
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_MODE) ? ESP_OK : ESP_FAIL;
105+
case ESP_MODEM_MODE_CMUX_MANUAL_EXIT:
106+
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_EXIT) ? ESP_OK : ESP_FAIL;
107+
case ESP_MODEM_MODE_CMUX_MANUAL_SWAP:
108+
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_SWAP) ? ESP_OK : ESP_FAIL;
109+
case ESP_MODEM_MODE_CMUX_MANUAL_DATA:
110+
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL;
111+
case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND:
112+
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL;
104113
}
105114
return ESP_ERR_NOT_SUPPORTED;
106115
}
@@ -391,3 +400,21 @@ extern "C" esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce_wrap, esp_mo
391400
pdp.protocol_type = c_api_pdp->protocol_type;
392401
return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp));
393402
}
403+
404+
extern "C" esp_err_t esp_modem_command(esp_modem_dce_t *dce_wrap, const char *command, esp_err_t(*got_line_fn)(uint8_t *data, size_t len), uint32_t timeout_ms)
405+
{
406+
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || command == nullptr || got_line_fn == nullptr) {
407+
return ESP_ERR_INVALID_ARG;
408+
}
409+
std::string cmd(command);
410+
return command_response_to_esp_err(dce_wrap->dce->command(cmd, [got_line_fn](uint8_t *data, size_t len) {
411+
switch (got_line_fn(data, len)) {
412+
case ESP_OK:
413+
return command_result::OK;
414+
case ESP_FAIL:
415+
return command_result::FAIL;
416+
default:
417+
return command_result::TIMEOUT;
418+
}
419+
}, timeout_ms));
420+
}

components/esp_modem/src/esp_modem_dce.cpp

Lines changed: 92 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,59 @@
1414

1515
namespace esp_modem {
1616

17+
namespace transitions {
18+
19+
static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
20+
{
21+
netif.stop();
22+
auto signal = std::make_shared<SignalGroup>();
23+
std::weak_ptr<SignalGroup> weak_signal = signal;
24+
dte.set_read_cb([weak_signal](uint8_t *data, size_t len) -> bool {
25+
if (memchr(data, '\n', len))
26+
{
27+
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
28+
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
29+
std::string_view response((char *) data, len);
30+
for (auto &it : pass)
31+
if (response.find(it) != std::string::npos) {
32+
if (auto signal = weak_signal.lock()) {
33+
signal->set(1);
34+
}
35+
return true;
36+
}
37+
}
38+
return false;
39+
});
40+
netif.wait_until_ppp_exits();
41+
if (!signal->wait(1, 2000)) {
42+
if (!device.set_mode(modem_mode::COMMAND_MODE)) {
43+
return false;
44+
}
45+
}
46+
dte.set_read_cb(nullptr);
47+
if (!dte.set_mode(modem_mode::COMMAND_MODE)) {
48+
return false;
49+
}
50+
return true;
51+
}
52+
53+
static bool enter_data(DTE &dte, ModuleIf &device, Netif &netif)
54+
{
55+
if (!device.setup_data_mode()) {
56+
return false;
57+
}
58+
if (!device.set_mode(modem_mode::DATA_MODE)) {
59+
return false;
60+
}
61+
if (!dte.set_mode(modem_mode::DATA_MODE)) {
62+
return false;
63+
}
64+
netif.start();
65+
return true;
66+
}
67+
68+
} // namespace transitions
69+
1770
/**
1871
* Set mode while the entire DTE is locked
1972
*/
@@ -36,8 +89,8 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
3689
switch (m) {
3790
case modem_mode::UNDEF:
3891
break;
39-
case modem_mode::COMMAND_MODE: {
40-
if (mode == modem_mode::COMMAND_MODE) {
92+
case modem_mode::COMMAND_MODE:
93+
if (mode == modem_mode::COMMAND_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
4194
return false;
4295
}
4396
if (mode == modem_mode::CMUX_MODE) {
@@ -49,59 +102,23 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
49102
mode = m;
50103
return true;
51104
}
52-
netif.stop();
53-
auto signal = std::make_shared<SignalGroup>();
54-
std::weak_ptr<SignalGroup> weak_signal = signal;
55-
dte->set_read_cb([weak_signal](uint8_t *data, size_t len) -> bool {
56-
if (memchr(data, '\n', len))
57-
{
58-
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
59-
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
60-
std::string_view response((char *) data, len);
61-
for (auto &it : pass)
62-
if (response.find(it) != std::string::npos) {
63-
if (auto signal = weak_signal.lock()) {
64-
signal->set(1);
65-
}
66-
return true;
67-
}
68-
}
69-
return false;
70-
});
71-
netif.wait_until_ppp_exits();
72-
if (!signal->wait(1, 2000)) {
73-
if (!device->set_mode(modem_mode::COMMAND_MODE)) {
74-
mode = modem_mode::UNDEF;
75-
return false;
76-
}
77-
}
78-
dte->set_read_cb(nullptr);
79-
if (!dte->set_mode(modem_mode::COMMAND_MODE)) {
105+
if (!transitions::exit_data(*dte, *device, netif)) {
80106
mode = modem_mode::UNDEF;
81107
return false;
82108
}
83109
mode = m;
84110
return true;
85-
}
86-
break;
87111
case modem_mode::DATA_MODE:
88-
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE) {
89-
return false;
90-
}
91-
if (!device->setup_data_mode()) {
112+
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
92113
return false;
93114
}
94-
if (!device->set_mode(modem_mode::DATA_MODE)) {
115+
if (!transitions::enter_data(*dte, *device, netif)) {
95116
return false;
96117
}
97-
if (!dte->set_mode(modem_mode::DATA_MODE)) {
98-
return false;
99-
}
100-
netif.start();
101118
mode = m;
102119
return true;
103120
case modem_mode::CMUX_MODE:
104-
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE) {
121+
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
105122
return false;
106123
}
107124
device->set_mode(modem_mode::CMUX_MODE); // switch the device into CMUX mode
@@ -111,17 +128,46 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
111128
return false;
112129
}
113130
mode = modem_mode::CMUX_MODE;
114-
if (!device->setup_data_mode()) {
131+
return transitions::enter_data(*dte, *device, netif);
132+
case modem_mode::CMUX_MANUAL_MODE:
133+
if (mode != modem_mode::COMMAND_MODE && mode != modem_mode::UNDEF) {
134+
return false;
135+
}
136+
device->set_mode(modem_mode::CMUX_MODE);
137+
usleep(100'000);
138+
139+
if (!dte->set_mode(m)) {
115140
return false;
116141
}
117-
if (!device->set_mode(modem_mode::DATA_MODE)) {
142+
mode = modem_mode::CMUX_MANUAL_MODE;
143+
return true;
144+
case modem_mode::CMUX_MANUAL_EXIT:
145+
if (mode != modem_mode::CMUX_MANUAL_MODE) {
146+
return false;
147+
}
148+
if (!dte->set_mode(m)) {
149+
return false;
150+
}
151+
mode = modem_mode::COMMAND_MODE;
152+
return true;
153+
case modem_mode::CMUX_MANUAL_SWAP:
154+
if (mode != modem_mode::CMUX_MANUAL_MODE) {
118155
return false;
119156
}
120-
if (!dte->set_mode(modem_mode::DATA_MODE)) {
157+
if (!dte->set_mode(m)) {
121158
return false;
122159
}
123-
netif.start();
124160
return true;
161+
case modem_mode::CMUX_MANUAL_DATA:
162+
if (mode != modem_mode::CMUX_MANUAL_MODE) {
163+
return false;
164+
}
165+
return transitions::enter_data(*dte, *device, netif);
166+
case modem_mode::CMUX_MANUAL_COMMAND:
167+
if (mode != modem_mode::CMUX_MANUAL_MODE) {
168+
return false;
169+
}
170+
return transitions::exit_data(*dte, *device, netif);
125171
}
126172
return false;
127173
}

0 commit comments

Comments
 (0)