esp_modem: Fixed race condition on exiting PPP mode

esp_modem_stop_ppp() stops both ppp netif and switches the modem back to
command mode. IF these two actions are not synchronised, we might
experience issues of
* active PPP session trying to send/receive uart-data
* command mode already active before modem switched to it
both resulting in crashes.
Fixed by introducing the transition mode and running these actions in sequence
* set esp-modem to transition mode
* enter command mode, wait for the reply or re-sync
* close the PPP netif
* wait until the netif closes
Other fixes include ignoring certain events if modem component not ready
or not in appropriate mode:
* ignoring all UART events comming from DTE with no DCE attached
* ignore pattern detection in PPP mode

Closes https://github.com/espressif/esp-idf/issues/6013
Closes https://github.com/espressif/esp-idf/issues/5737
Closes https://github.com/espressif/esp-idf/issues/6024
Closes https://github.com/espressif/esp-idf/issues/6058
Closes https://github.com/espressif/esp-idf/issues/5563
Closes https://github.com/espressif/esp-idf/issues/5695
Closes https://github.com/espressif/esp-idf/issues/5633
Closes https://github.com/espressif/esp-idf/issues/4482
Related https://github.com/espressif/esp-idf/pull/4849
Related https://github.com/espressif/esp-idf/pull/4653
This commit is contained in:
David Cermak
2020-10-26 11:50:06 +01:00
parent c3cc5b17e0
commit 55d41c3377
6 changed files with 179 additions and 29 deletions

View File

@@ -294,15 +294,31 @@ static esp_err_t sim800_set_working_mode(modem_dce_t *dce, modem_mode_t mode)
switch (mode) {
case MODEM_COMMAND_MODE:
dce->handle_line = sim800_handle_exit_data_mode;
DCE_CHECK(dte->send_cmd(dte, "+++", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter command mode failed", err);
vTaskDelay(pdMS_TO_TICKS(1000)); // spec: 1s delay for the modem to recognize the escape sequence
if (dte->send_cmd(dte, "+++", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) != ESP_OK) {
// "+++" Could fail if we are already in the command mode.
// in that case we ignore the timeout and re-sync the modem
ESP_LOGI(DCE_TAG, "Sending \"+++\" command failed");
dce->handle_line = esp_modem_dce_handle_response_default;
DCE_CHECK(dte->send_cmd(dte, "AT\r", MODEM_COMMAND_TIMEOUT_DEFAULT) == ESP_OK, "send command failed", err);
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "sync failed", err);
} else {
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter command mode failed", err);
}
ESP_LOGD(DCE_TAG, "enter command mode ok");
dce->mode = MODEM_COMMAND_MODE;
break;
case MODEM_PPP_MODE:
dce->handle_line = sim800_handle_atd_ppp;
DCE_CHECK(dte->send_cmd(dte, "ATD*99#\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter ppp mode failed", err);
if (dce->state != MODEM_STATE_SUCCESS) {
// Initiate PPP mode could fail, if we've already "dialed" the data call before.
// in that case we retry with "ATO" to just resume the data mode
ESP_LOGD(DCE_TAG, "enter ppp mode failed, retry with ATO");
dce->handle_line = sim800_handle_atd_ppp;
DCE_CHECK(dte->send_cmd(dte, "ATO\r", MODEM_COMMAND_TIMEOUT_MODE_CHANGE) == ESP_OK, "send command failed", err);
DCE_CHECK(dce->state == MODEM_STATE_SUCCESS, "enter ppp mode failed", err);
}
ESP_LOGD(DCE_TAG, "enter ppp mode ok");
dce->mode = MODEM_PPP_MODE;
break;