mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-16 12:02:11 +02:00
Merge pull request #169 from david-cermak/feat/modem_dce_on_read
fix(esp-modem): Extend CMUX mode to support manual transitions
This commit is contained in:
@ -210,7 +210,17 @@ extern "C" void app_main(void)
|
|||||||
if (c->get_count_of(&SetModeArgs::mode)) {
|
if (c->get_count_of(&SetModeArgs::mode)) {
|
||||||
auto mode = c->get_string_of(&SetModeArgs::mode);
|
auto mode = c->get_string_of(&SetModeArgs::mode);
|
||||||
modem_mode dev_mode;
|
modem_mode dev_mode;
|
||||||
if (mode == "CMD") {
|
if (mode == "CMUX1") {
|
||||||
|
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_MODE;
|
||||||
|
} else if (mode == "CMUX2") {
|
||||||
|
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_EXIT;
|
||||||
|
} else if (mode == "CMUX3") {
|
||||||
|
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_SWAP;
|
||||||
|
} else if (mode == "CMUX4") {
|
||||||
|
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_DATA;
|
||||||
|
} else if (mode == "CMUX5") {
|
||||||
|
dev_mode = esp_modem::modem_mode::CMUX_MANUAL_COMMAND;
|
||||||
|
} else if (mode == "CMD") {
|
||||||
dev_mode = esp_modem::modem_mode::COMMAND_MODE;
|
dev_mode = esp_modem::modem_mode::COMMAND_MODE;
|
||||||
} else if (mode == "PPP") {
|
} else if (mode == "PPP") {
|
||||||
dev_mode = esp_modem::modem_mode::DATA_MODE;
|
dev_mode = esp_modem::modem_mode::DATA_MODE;
|
||||||
|
@ -116,8 +116,8 @@ private:
|
|||||||
Lock internal_lock{}; /*!< Locks DTE operations */
|
Lock internal_lock{}; /*!< Locks DTE operations */
|
||||||
unique_buffer buffer; /*!< DTE buffer */
|
unique_buffer buffer; /*!< DTE buffer */
|
||||||
std::shared_ptr<CMux> cmux_term; /*!< Primary terminal for this DTE */
|
std::shared_ptr<CMux> cmux_term; /*!< Primary terminal for this DTE */
|
||||||
std::shared_ptr<Terminal> command_term; /*!< Reference to the terminal used for sending commands */
|
std::shared_ptr<Terminal> primary_term; /*!< Reference to the primary terminal (mostly for sending commands) */
|
||||||
std::shared_ptr<Terminal> data_term; /*!< Secondary terminal for this DTE */
|
std::shared_ptr<Terminal> secondary_term; /*!< Secondary terminal for this DTE */
|
||||||
modem_mode mode; /*!< DTE operation mode */
|
modem_mode mode; /*!< DTE operation mode */
|
||||||
SignalGroup signal; /*!< Event group used to signal request-response operations */
|
SignalGroup signal; /*!< Event group used to signal request-response operations */
|
||||||
command_result result; /*!< Command result of the currently exectuted command */
|
command_result result; /*!< Command result of the currently exectuted command */
|
||||||
|
@ -29,8 +29,13 @@ enum class modem_mode {
|
|||||||
UNDEF,
|
UNDEF,
|
||||||
COMMAND_MODE, /*!< Command mode -- the modem is supposed to send AT commands in this mode */
|
COMMAND_MODE, /*!< Command mode -- the modem is supposed to send AT commands in this mode */
|
||||||
DATA_MODE, /*!< Data mode -- the modem communicates with network interface on PPP protocol */
|
DATA_MODE, /*!< Data mode -- the modem communicates with network interface on PPP protocol */
|
||||||
CMUX_MODE /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
|
CMUX_MODE, /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
|
||||||
* assigning one solely to command interface and the other to the data mode */
|
* assigning one solely to command interface and the other to the data mode */
|
||||||
|
CMUX_MANUAL_MODE, /*!< Enter CMUX mode manually -- just creates two virtual terminals */
|
||||||
|
CMUX_MANUAL_EXIT, /*!< Exits CMUX mode manually -- just destroys two virtual terminals */
|
||||||
|
CMUX_MANUAL_DATA, /*!< Sets the primary terminal to DATA mode in manual CMUX */
|
||||||
|
CMUX_MANUAL_COMMAND, /*!< Sets the primary terminal to COMMAND mode in manual CMUX */
|
||||||
|
CMUX_MANUAL_SWAP, /*!< Swaps virtual terminals in manual CMUX mode (primary <-> secondary) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +36,11 @@ typedef enum esp_modem_dce_mode {
|
|||||||
ESP_MODEM_MODE_COMMAND, /**< Default mode after modem startup, used for sending AT commands */
|
ESP_MODEM_MODE_COMMAND, /**< Default mode after modem startup, used for sending AT commands */
|
||||||
ESP_MODEM_MODE_DATA, /**< Used for switching to PPP mode for the modem to connect to a network */
|
ESP_MODEM_MODE_DATA, /**< Used for switching to PPP mode for the modem to connect to a network */
|
||||||
ESP_MODEM_MODE_CMUX, /**< Multiplexed terminal mode */
|
ESP_MODEM_MODE_CMUX, /**< Multiplexed terminal mode */
|
||||||
|
ESP_MODEM_MODE_CMUX_MANUAL, /**< CMUX manual mode */
|
||||||
|
ESP_MODEM_MODE_CMUX_MANUAL_EXIT, /**< Exit CMUX manual mode */
|
||||||
|
ESP_MODEM_MODE_CMUX_MANUAL_SWAP, /**< Swap terminals in CMUX manual mode */
|
||||||
|
ESP_MODEM_MODE_CMUX_MANUAL_DATA, /**< Set DATA mode in CMUX manual mode */
|
||||||
|
ESP_MODEM_MODE_CMUX_MANUAL_COMMAND, /**< Set COMMAND mode in CMUX manual mode */
|
||||||
} esp_modem_dce_mode_t;
|
} esp_modem_dce_mode_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,6 +118,8 @@ esp_err_t esp_modem_set_error_cb(esp_modem_dce_t *dce, esp_modem_terminal_error_
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce, esp_modem_dce_mode_t mode);
|
esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce, esp_modem_dce_mode_t mode);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
@ -93,14 +93,23 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce
|
|||||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if (mode == ESP_MODEM_MODE_DATA) {
|
switch (mode) {
|
||||||
|
case ESP_MODEM_MODE_DATA:
|
||||||
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
|
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
|
||||||
}
|
case ESP_MODEM_MODE_COMMAND:
|
||||||
if (mode == ESP_MODEM_MODE_COMMAND) {
|
|
||||||
return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL;
|
return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL;
|
||||||
}
|
case ESP_MODEM_MODE_CMUX:
|
||||||
if (mode == ESP_MODEM_MODE_CMUX) {
|
|
||||||
return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL;
|
return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL;
|
||||||
|
case ESP_MODEM_MODE_CMUX_MANUAL:
|
||||||
|
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_MODE) ? ESP_OK : ESP_FAIL;
|
||||||
|
case ESP_MODEM_MODE_CMUX_MANUAL_EXIT:
|
||||||
|
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_EXIT) ? ESP_OK : ESP_FAIL;
|
||||||
|
case ESP_MODEM_MODE_CMUX_MANUAL_SWAP:
|
||||||
|
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_SWAP) ? ESP_OK : ESP_FAIL;
|
||||||
|
case ESP_MODEM_MODE_CMUX_MANUAL_DATA:
|
||||||
|
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL;
|
||||||
|
case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND:
|
||||||
|
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL;
|
||||||
}
|
}
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
@ -391,3 +400,21 @@ extern "C" esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce_wrap, esp_mo
|
|||||||
pdp.protocol_type = c_api_pdp->protocol_type;
|
pdp.protocol_type = c_api_pdp->protocol_type;
|
||||||
return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp));
|
return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || command == nullptr || got_line_fn == nullptr) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
std::string cmd(command);
|
||||||
|
return command_response_to_esp_err(dce_wrap->dce->command(cmd, [got_line_fn](uint8_t *data, size_t len) {
|
||||||
|
switch (got_line_fn(data, len)) {
|
||||||
|
case ESP_OK:
|
||||||
|
return command_result::OK;
|
||||||
|
case ESP_FAIL:
|
||||||
|
return command_result::FAIL;
|
||||||
|
default:
|
||||||
|
return command_result::TIMEOUT;
|
||||||
|
}
|
||||||
|
}, timeout_ms));
|
||||||
|
}
|
||||||
|
@ -14,6 +14,59 @@
|
|||||||
|
|
||||||
namespace esp_modem {
|
namespace esp_modem {
|
||||||
|
|
||||||
|
namespace transitions {
|
||||||
|
|
||||||
|
static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||||
|
{
|
||||||
|
netif.stop();
|
||||||
|
auto signal = std::make_shared<SignalGroup>();
|
||||||
|
std::weak_ptr<SignalGroup> weak_signal = signal;
|
||||||
|
dte.set_read_cb([weak_signal](uint8_t *data, size_t len) -> bool {
|
||||||
|
if (memchr(data, '\n', len))
|
||||||
|
{
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
|
||||||
|
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
|
||||||
|
std::string_view response((char *) data, len);
|
||||||
|
for (auto &it : pass)
|
||||||
|
if (response.find(it) != std::string::npos) {
|
||||||
|
if (auto signal = weak_signal.lock()) {
|
||||||
|
signal->set(1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
netif.wait_until_ppp_exits();
|
||||||
|
if (!signal->wait(1, 2000)) {
|
||||||
|
if (!device.set_mode(modem_mode::COMMAND_MODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dte.set_read_cb(nullptr);
|
||||||
|
if (!dte.set_mode(modem_mode::COMMAND_MODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool enter_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||||
|
{
|
||||||
|
if (!device.setup_data_mode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!device.set_mode(modem_mode::DATA_MODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!dte.set_mode(modem_mode::DATA_MODE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
netif.start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace transitions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set mode while the entire DTE is locked
|
* Set mode while the entire DTE is locked
|
||||||
*/
|
*/
|
||||||
@ -36,8 +89,8 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
|
|||||||
switch (m) {
|
switch (m) {
|
||||||
case modem_mode::UNDEF:
|
case modem_mode::UNDEF:
|
||||||
break;
|
break;
|
||||||
case modem_mode::COMMAND_MODE: {
|
case modem_mode::COMMAND_MODE:
|
||||||
if (mode == modem_mode::COMMAND_MODE) {
|
if (mode == modem_mode::COMMAND_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mode == modem_mode::CMUX_MODE) {
|
if (mode == modem_mode::CMUX_MODE) {
|
||||||
@ -49,59 +102,23 @@ bool DCE_Mode::set_unsafe(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m
|
|||||||
mode = m;
|
mode = m;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
netif.stop();
|
if (!transitions::exit_data(*dte, *device, netif)) {
|
||||||
auto signal = std::make_shared<SignalGroup>();
|
|
||||||
std::weak_ptr<SignalGroup> weak_signal = signal;
|
|
||||||
dte->set_read_cb([weak_signal](uint8_t *data, size_t len) -> bool {
|
|
||||||
if (memchr(data, '\n', len))
|
|
||||||
{
|
|
||||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_DEBUG);
|
|
||||||
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
|
|
||||||
std::string_view response((char *) data, len);
|
|
||||||
for (auto &it : pass)
|
|
||||||
if (response.find(it) != std::string::npos) {
|
|
||||||
if (auto signal = weak_signal.lock()) {
|
|
||||||
signal->set(1);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
netif.wait_until_ppp_exits();
|
|
||||||
if (!signal->wait(1, 2000)) {
|
|
||||||
if (!device->set_mode(modem_mode::COMMAND_MODE)) {
|
|
||||||
mode = modem_mode::UNDEF;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dte->set_read_cb(nullptr);
|
|
||||||
if (!dte->set_mode(modem_mode::COMMAND_MODE)) {
|
|
||||||
mode = modem_mode::UNDEF;
|
mode = modem_mode::UNDEF;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mode = m;
|
mode = m;
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
break;
|
|
||||||
case modem_mode::DATA_MODE:
|
case modem_mode::DATA_MODE:
|
||||||
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE) {
|
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!device->setup_data_mode()) {
|
if (!transitions::enter_data(*dte, *device, netif)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!device->set_mode(modem_mode::DATA_MODE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!dte->set_mode(modem_mode::DATA_MODE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
netif.start();
|
|
||||||
mode = m;
|
mode = m;
|
||||||
return true;
|
return true;
|
||||||
case modem_mode::CMUX_MODE:
|
case modem_mode::CMUX_MODE:
|
||||||
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE) {
|
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE || mode >= modem_mode::CMUX_MANUAL_MODE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
device->set_mode(modem_mode::CMUX_MODE); // switch the device into CMUX mode
|
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
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mode = modem_mode::CMUX_MODE;
|
mode = modem_mode::CMUX_MODE;
|
||||||
if (!device->setup_data_mode()) {
|
return transitions::enter_data(*dte, *device, netif);
|
||||||
|
case modem_mode::CMUX_MANUAL_MODE:
|
||||||
|
if (mode != modem_mode::COMMAND_MODE && mode != modem_mode::UNDEF) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!device->set_mode(modem_mode::DATA_MODE)) {
|
device->set_mode(modem_mode::CMUX_MODE);
|
||||||
|
usleep(100'000);
|
||||||
|
|
||||||
|
if (!dte->set_mode(m)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!dte->set_mode(modem_mode::DATA_MODE)) {
|
mode = modem_mode::CMUX_MANUAL_MODE;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
netif.start();
|
|
||||||
return true;
|
return true;
|
||||||
|
case modem_mode::CMUX_MANUAL_EXIT:
|
||||||
|
if (mode != modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!dte->set_mode(m)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mode = modem_mode::COMMAND_MODE;
|
||||||
|
return true;
|
||||||
|
case modem_mode::CMUX_MANUAL_SWAP:
|
||||||
|
if (mode != modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!dte->set_mode(m)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case modem_mode::CMUX_MANUAL_DATA:
|
||||||
|
if (mode != modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return transitions::enter_data(*dte, *device, netif);
|
||||||
|
case modem_mode::CMUX_MANUAL_COMMAND:
|
||||||
|
if (mode != modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return transitions::exit_data(*dte, *device, netif);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,12 @@ static const size_t dte_default_buffer_size = 1000;
|
|||||||
|
|
||||||
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal):
|
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal):
|
||||||
buffer(config->dte_buffer_size),
|
buffer(config->dte_buffer_size),
|
||||||
cmux_term(nullptr), command_term(std::move(terminal)), data_term(command_term),
|
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
|
||||||
mode(modem_mode::UNDEF) {}
|
mode(modem_mode::UNDEF) {}
|
||||||
|
|
||||||
DTE::DTE(std::unique_ptr<Terminal> terminal):
|
DTE::DTE(std::unique_ptr<Terminal> terminal):
|
||||||
buffer(dte_default_buffer_size),
|
buffer(dte_default_buffer_size),
|
||||||
cmux_term(nullptr), command_term(std::move(terminal)), data_term(command_term),
|
cmux_term(nullptr), primary_term(std::move(terminal)), secondary_term(primary_term),
|
||||||
mode(modem_mode::UNDEF) {}
|
mode(modem_mode::UNDEF) {}
|
||||||
|
|
||||||
command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator)
|
command_result DTE::command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator)
|
||||||
@ -29,10 +29,10 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
|
|||||||
Scoped<Lock> l(internal_lock);
|
Scoped<Lock> l(internal_lock);
|
||||||
result = command_result::TIMEOUT;
|
result = command_result::TIMEOUT;
|
||||||
signal.clear(GOT_LINE);
|
signal.clear(GOT_LINE);
|
||||||
command_term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) {
|
primary_term->set_read_cb([this, got_line, separator](uint8_t *data, size_t len) {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
data = buffer.get();
|
data = buffer.get();
|
||||||
len = command_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
|
len = primary_term->read(data + buffer.consumed, buffer.size - buffer.consumed);
|
||||||
} else {
|
} else {
|
||||||
buffer.consumed = 0; // if the underlying terminal contains data, we cannot fragment
|
buffer.consumed = 0; // if the underlying terminal contains data, we cannot fragment
|
||||||
}
|
}
|
||||||
@ -46,13 +46,13 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
|
|||||||
buffer.consumed += len;
|
buffer.consumed += len;
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
command_term->write((uint8_t *)command.c_str(), command.length());
|
primary_term->write((uint8_t *)command.c_str(), command.length());
|
||||||
auto got_lf = signal.wait(GOT_LINE, time_ms);
|
auto got_lf = signal.wait(GOT_LINE, time_ms);
|
||||||
if (got_lf && result == command_result::TIMEOUT) {
|
if (got_lf && result == command_result::TIMEOUT) {
|
||||||
ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE);
|
ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE);
|
||||||
}
|
}
|
||||||
buffer.consumed = 0;
|
buffer.consumed = 0;
|
||||||
command_term->set_read_cb(nullptr);
|
primary_term->set_read_cb(nullptr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,26 +68,26 @@ bool DTE::exit_cmux()
|
|||||||
}
|
}
|
||||||
auto ejected = cmux_term->detach();
|
auto ejected = cmux_term->detach();
|
||||||
// return the ejected terminal and buffer back to this DTE
|
// return the ejected terminal and buffer back to this DTE
|
||||||
command_term = std::move(ejected.first);
|
primary_term = std::move(ejected.first);
|
||||||
buffer = std::move(ejected.second);
|
buffer = std::move(ejected.second);
|
||||||
data_term = command_term;
|
secondary_term = primary_term;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DTE::setup_cmux()
|
bool DTE::setup_cmux()
|
||||||
{
|
{
|
||||||
cmux_term = std::make_shared<CMux>(command_term, std::move(buffer));
|
cmux_term = std::make_shared<CMux>(primary_term, std::move(buffer));
|
||||||
if (cmux_term == nullptr) {
|
if (cmux_term == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!cmux_term->init()) {
|
if (!cmux_term->init()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
command_term = std::make_unique<CMuxInstance>(cmux_term, 0);
|
primary_term = std::make_unique<CMuxInstance>(cmux_term, 0);
|
||||||
if (command_term == nullptr) {
|
if (primary_term == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
data_term = std::make_unique<CMuxInstance>(cmux_term, 1);
|
secondary_term = std::make_unique<CMuxInstance>(cmux_term, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,14 +106,12 @@ bool DTE::set_mode(modem_mode m)
|
|||||||
}
|
}
|
||||||
// transitions (COMMAND|CMUX|UNDEF) -> DATA
|
// transitions (COMMAND|CMUX|UNDEF) -> DATA
|
||||||
if (m == modem_mode::DATA_MODE) {
|
if (m == modem_mode::DATA_MODE) {
|
||||||
if (mode == modem_mode::CMUX_MODE) {
|
if (mode == modem_mode::CMUX_MODE || mode == modem_mode::CMUX_MANUAL_MODE) {
|
||||||
// mode stays the same, but need to swap terminals (as command has been switch)
|
// mode stays the same, but need to swap terminals (as command has been switched)
|
||||||
data_term.swap(command_term);
|
secondary_term.swap(primary_term);
|
||||||
} else {
|
} else {
|
||||||
mode = m;
|
mode = m;
|
||||||
}
|
}
|
||||||
// prepare the data terminal's callback to the configured std::function (used by netif)
|
|
||||||
data_term->set_read_cb(on_data);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// transitions (DATA|CMUX|UNDEF) -> COMMAND
|
// transitions (DATA|CMUX|UNDEF) -> COMMAND
|
||||||
@ -125,21 +123,47 @@ bool DTE::set_mode(modem_mode m)
|
|||||||
}
|
}
|
||||||
mode = modem_mode::UNDEF;
|
mode = modem_mode::UNDEF;
|
||||||
return false;
|
return false;
|
||||||
|
} if (mode == modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
mode = m;
|
mode = m;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// manual CMUX transitions: Enter CMUX
|
||||||
|
if (m == modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
if (setup_cmux()) {
|
||||||
|
mode = m;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
mode = modem_mode::UNDEF;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// manual CMUX transitions: Exit CMUX
|
||||||
|
if (m == modem_mode::CMUX_MANUAL_EXIT && mode == modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
if (exit_cmux()) {
|
||||||
|
mode = modem_mode::COMMAND_MODE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mode = modem_mode::UNDEF;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// manual CMUX transitions: Swap terminals
|
||||||
|
if (m == modem_mode::CMUX_MANUAL_SWAP && mode == modem_mode::CMUX_MANUAL_MODE) {
|
||||||
|
secondary_term.swap(primary_term);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
mode = modem_mode::UNDEF;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
|
void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
|
||||||
{
|
{
|
||||||
on_data = std::move(f);
|
on_data = std::move(f);
|
||||||
data_term->set_read_cb([this](uint8_t *data, size_t len) {
|
secondary_term->set_read_cb([this](uint8_t *data, size_t len) {
|
||||||
if (!data) { // if no data available from terminal callback -> need to explicitly read some
|
if (!data) { // if no data available from terminal callback -> need to explicitly read some
|
||||||
data = buffer.get();
|
data = buffer.get();
|
||||||
len = data_term->read(buffer.get(), buffer.size);
|
len = secondary_term->read(buffer.get(), buffer.size);
|
||||||
}
|
}
|
||||||
if (on_data) {
|
if (on_data) {
|
||||||
return on_data(data, len);
|
return on_data(data, len);
|
||||||
@ -150,22 +174,22 @@ void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
|
|||||||
|
|
||||||
void DTE::set_error_cb(std::function<void(terminal_error err)> f)
|
void DTE::set_error_cb(std::function<void(terminal_error err)> f)
|
||||||
{
|
{
|
||||||
data_term->set_error_cb(f);
|
secondary_term->set_error_cb(f);
|
||||||
command_term->set_error_cb(f);
|
primary_term->set_error_cb(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DTE::read(uint8_t **d, size_t len)
|
int DTE::read(uint8_t **d, size_t len)
|
||||||
{
|
{
|
||||||
auto data_to_read = std::min(len, buffer.size);
|
auto data_to_read = std::min(len, buffer.size);
|
||||||
auto data = buffer.get();
|
auto data = buffer.get();
|
||||||
auto actual_len = data_term->read(data, data_to_read);
|
auto actual_len = secondary_term->read(data, data_to_read);
|
||||||
*d = data;
|
*d = data;
|
||||||
return actual_len;
|
return actual_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DTE::write(uint8_t *data, size_t len)
|
int DTE::write(uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
return data_term->write(data, len);
|
return secondary_term->write(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user