Files
esp-protocols/esp_modem/src/esp_modem_dce.c
T

181 lines
6.7 KiB
C

// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_modem_dce.h"
#include "esp_modem_dce_command_lib.h"
#include "esp_modem_dce_common_commands.h"
#include "esp_modem_internal.h"
#include "esp_log.h"
static const char *TAG = "esp_modem_dce";
esp_err_t esp_modem_dce_generic_command(esp_modem_dce_t *dce, const char * command, uint32_t timeout, esp_modem_dce_handle_line_t handle_line, void *ctx)
{
esp_modem_dte_t *dte = dce->dte;
ESP_LOGD(TAG, "%s(%d): Sending command:%s\n", __func__, __LINE__, command );
dce->handle_line = handle_line;
dce->handle_line_ctx = ctx;
if (dte->send_cmd(dte, command, timeout) != ESP_OK) {
ESP_LOGW(TAG, "%s(%d): Command:%s response timeout", __func__, __LINE__, command );
return ESP_ERR_TIMEOUT;
}
if (dce->state == ESP_MODEM_STATE_FAIL) {
ESP_LOGW(TAG, "%s(%d): Command:%s\n...failed", __func__, __LINE__, command );
return ESP_FAIL;
}
ESP_LOGD(TAG, "%s(%d): Command:%s\n succeeded", __func__, __LINE__, command );
return ESP_OK;
}
esp_err_t esp_modem_dce_set_params(esp_modem_dce_t *dce, esp_modem_dce_config_t* config)
{
// save the config
memcpy(&dce->config, config, sizeof(esp_modem_dce_config_t));
return ESP_OK;
}
esp_err_t esp_modem_dce_default_init(esp_modem_dce_t *dce, esp_modem_dce_config_t* config)
{
// Check parameters
ESP_MODEM_ERR_CHECK(dce && config, "dce object or configuration is NULL", err);
// Set default commands needed for the DCE to operate
// note: command links will be overwritten if cmd-list enabled
dce->set_data_mode = esp_modem_dce_set_data_mode;
dce->resume_data_mode = esp_modem_dce_resume_data_mode;
dce->set_command_mode = esp_modem_dce_set_command_mode;
dce->set_pdp_context = esp_modem_dce_set_pdp_context;
dce->hang_up = esp_modem_dce_hang_up;
dce->set_echo = esp_modem_dce_set_echo;
dce->sync = esp_modem_dce_sync;
dce->set_flow_ctrl = esp_modem_dce_set_flow_ctrl;
dce->store_profile = esp_modem_dce_store_profile;
ESP_MODEM_ERR_CHECK(esp_modem_dce_set_params(dce, config) == ESP_OK, "Failed to configure dce object", err);
// set DCE basic API
dce->start_up = esp_modem_dce_default_start_up;
dce->deinit = esp_modem_dce_default_destroy;
dce->set_working_mode = esp_modem_dce_set_working_mode;
// initialize the list if enabled
if (config->populate_command_list) {
dce->dce_cmd_list = esp_modem_command_list_create();
ESP_MODEM_ERR_CHECK(dce->dce_cmd_list, "Allocation of dce internal object has failed", err);
}
return ESP_OK;
err:
return ESP_ERR_NO_MEM;
}
esp_err_t esp_modem_dce_default_destroy(esp_modem_dce_t *dce)
{
ESP_MODEM_ERR_CHECK(esp_modem_command_list_deinit(dce) == ESP_OK, "failed", err);
free(dce);
return ESP_OK;
err:
return ESP_FAIL;
}
esp_err_t esp_modem_dce_handle_response_default(esp_modem_dce_t *dce, const char *line)
{
esp_err_t err = ESP_FAIL;
if (strstr(line, MODEM_RESULT_CODE_SUCCESS)) {
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_SUCCESS);
} else if (strstr(line, MODEM_RESULT_CODE_ERROR)) {
err = esp_modem_process_command_done(dce, ESP_MODEM_STATE_FAIL);
}
return err;
}
esp_err_t esp_modem_process_command_done(esp_modem_dce_t *dce, esp_modem_state_t state)
{
dce->state = state;
return dce->dte->process_cmd_done(dce->dte);
}
static esp_err_t esp_modem_switch_to_command_mode(esp_modem_dce_t *dce)
{
esp_modem_wait_ms(1000); // 1s delay for the device to recognize the data escape sequence
if (dce->set_command_mode(dce, NULL, NULL) != ESP_OK) {
// exiting data mode could fail if the modem is already in command mode via PPP netif closed
ESP_MODEM_ERR_CHECK(dce->sync(dce, NULL, NULL) == ESP_OK, "sync after PPP exit failed", err);
} else {
// hang-up if exit PPP succeeded
dce->mode = ESP_MODEM_COMMAND_MODE;
ESP_MODEM_ERR_CHECK(dce->hang_up(dce, NULL, NULL) == ESP_OK, "hang-up after PPP exit failed", err);
}
dce->mode = ESP_MODEM_COMMAND_MODE;
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t esp_modem_switch_to_data_mode(esp_modem_dce_t *dce)
{
// before going to data mode, set the PDP data context
ESP_MODEM_ERR_CHECK(dce->set_pdp_context(dce, &dce->config.pdp_context, NULL) == ESP_OK, "setting pdp context failed", err);
// now set the data mode
if (dce->set_data_mode(dce, NULL, NULL) != ESP_OK) {
// Initiate PPP mode could fail, if we've already "dialed" the data call before.
// in that case we retry to just resume the data mode
ESP_LOGD(TAG, "set_data_mode, retry with resume_data_mode");
ESP_MODEM_ERR_CHECK(dce->resume_data_mode(dce, NULL, NULL) == ESP_OK, "setting data mode failed", err);
}
dce->mode = ESP_MODEM_PPP_MODE;
return ESP_OK;
err:
return ESP_FAIL;
}
/**
* @brief Set Working Mode
*
* @param dce Modem DCE object
* @param mode working mode
* @return esp_err_t
* - ESP_OK on success
* - ESP_FAIL on error
*/
esp_err_t esp_modem_dce_set_working_mode(esp_modem_dce_t *dce, esp_modem_mode_t mode)
{
switch (mode) {
case ESP_MODEM_COMMAND_MODE:
ESP_MODEM_ERR_CHECK(esp_modem_switch_to_command_mode(dce) == ESP_OK, "Setting command mode failed", err);
break;
case ESP_MODEM_PPP_MODE:
ESP_MODEM_ERR_CHECK(esp_modem_switch_to_data_mode(dce) == ESP_OK, "Setting data mode failed", err);
break;
default:
ESP_LOGW(TAG, "unsupported working mode: %d", mode);
goto err;
}
return ESP_OK;
err:
return ESP_FAIL;
}
esp_err_t esp_modem_dce_default_start_up(esp_modem_dce_t *dce)
{
ESP_MODEM_ERR_CHECK(dce->sync(dce, NULL, NULL) == ESP_OK, "sending sync failed", err);
ESP_MODEM_ERR_CHECK(dce->set_echo(dce, (void*)false, NULL) == ESP_OK, "set_echo failed", err);
ESP_MODEM_ERR_CHECK(dce->set_flow_ctrl(dce, (void*)ESP_MODEM_FLOW_CONTROL_NONE, NULL) == ESP_OK, "set_flow_ctrl failed", err);
ESP_MODEM_ERR_CHECK(dce->store_profile(dce, NULL, NULL) == ESP_OK, "store_profile failed", err);
return ESP_OK;
err:
return ESP_FAIL;
}