esp_modem.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/param.h>
  17. #include "freertos/FreeRTOS.h"
  18. #include "freertos/task.h"
  19. #include "freertos/semphr.h"
  20. #include "esp_modem.h"
  21. #include "esp_log.h"
  22. #include "sdkconfig.h"
  23. #define ESP_MODEM_EVENT_QUEUE_SIZE (16)
  24. #define MIN_PATTERN_INTERVAL (9)
  25. #define MIN_POST_IDLE (0)
  26. #define MIN_PRE_IDLE (0)
  27. /**
  28. * @brief Macro defined for error checking
  29. *
  30. */
  31. static const char *MODEM_TAG = "esp-modem";
  32. #define MODEM_CHECK(a, str, goto_tag, ...) \
  33. do \
  34. { \
  35. if (!(a)) \
  36. { \
  37. ESP_LOGE(MODEM_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
  38. goto goto_tag; \
  39. } \
  40. } while (0)
  41. ESP_EVENT_DEFINE_BASE(ESP_MODEM_EVENT);
  42. /**
  43. * @brief ESP32 Modem DTE
  44. *
  45. */
  46. typedef struct {
  47. uart_port_t uart_port; /*!< UART port */
  48. uint8_t *buffer; /*!< Internal buffer to store response lines/data from DCE */
  49. QueueHandle_t event_queue; /*!< UART event queue handle */
  50. esp_event_loop_handle_t event_loop_hdl; /*!< Event loop handle */
  51. TaskHandle_t uart_event_task_hdl; /*!< UART event task handle */
  52. SemaphoreHandle_t process_sem; /*!< Semaphore used for indicating processing status */
  53. modem_dte_t parent; /*!< DTE interface that should extend */
  54. esp_modem_on_receive receive_cb; /*!< ptr to data reception */
  55. void *receive_cb_ctx; /*!< ptr to rx fn context data */
  56. int line_buffer_size; /*!< line buffer size in commnad mode */
  57. int pattern_queue_size; /*!< UART pattern queue size */
  58. } esp_modem_dte_t;
  59. esp_err_t esp_modem_set_rx_cb(modem_dte_t *dte, esp_modem_on_receive receive_cb, void *receive_cb_ctx)
  60. {
  61. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  62. esp_dte->receive_cb_ctx = receive_cb_ctx;
  63. esp_dte->receive_cb = receive_cb;
  64. return ESP_OK;
  65. }
  66. /**
  67. * @brief Handle one line in DTE
  68. *
  69. * @param esp_dte ESP modem DTE object
  70. * @return esp_err_t
  71. * - ESP_OK on success
  72. * - ESP_FAIL on error
  73. */
  74. static esp_err_t esp_dte_handle_line(esp_modem_dte_t *esp_dte)
  75. {
  76. modem_dce_t *dce = esp_dte->parent.dce;
  77. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  78. const char *line = (const char *)(esp_dte->buffer);
  79. /* Skip pure "\r\n" lines */
  80. if (strlen(line) > 2) {
  81. MODEM_CHECK(dce->handle_line, "no handler for line", err_handle);
  82. MODEM_CHECK(dce->handle_line(dce, line) == ESP_OK, "handle line failed", err_handle);
  83. }
  84. return ESP_OK;
  85. err_handle:
  86. /* Send ESP_MODEM_EVENT_UNKNOWN signal to event loop */
  87. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_UNKNOWN,
  88. (void *)line, strlen(line) + 1, pdMS_TO_TICKS(100));
  89. err:
  90. return ESP_FAIL;
  91. }
  92. /**
  93. * @brief Handle when a pattern has been detected by UART
  94. *
  95. * @param esp_dte ESP32 Modem DTE object
  96. */
  97. static void esp_handle_uart_pattern(esp_modem_dte_t *esp_dte)
  98. {
  99. int pos = uart_pattern_pop_pos(esp_dte->uart_port);
  100. int read_len = 0;
  101. if (pos != -1) {
  102. if (pos < esp_dte->line_buffer_size - 1) {
  103. /* read one line(include '\n') */
  104. read_len = pos + 1;
  105. } else {
  106. ESP_LOGW(MODEM_TAG, "ESP Modem Line buffer too small");
  107. read_len = esp_dte->line_buffer_size - 1;
  108. }
  109. read_len = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, read_len, pdMS_TO_TICKS(100));
  110. if (read_len) {
  111. /* make sure the line is a standard string */
  112. esp_dte->buffer[read_len] = '\0';
  113. /* Send new line to handle */
  114. esp_dte_handle_line(esp_dte);
  115. } else {
  116. ESP_LOGE(MODEM_TAG, "uart read bytes failed");
  117. }
  118. } else {
  119. ESP_LOGW(MODEM_TAG, "Pattern Queue Size too small");
  120. uart_flush(esp_dte->uart_port);
  121. }
  122. }
  123. /**
  124. * @brief Handle when new data received by UART
  125. *
  126. * @param esp_dte ESP32 Modem DTE object
  127. */
  128. static void esp_handle_uart_data(esp_modem_dte_t *esp_dte)
  129. {
  130. if (esp_dte->parent.dce->mode != MODEM_PPP_MODE) {
  131. ESP_LOGE(MODEM_TAG, "Error: Got data event in PPP mode");
  132. /* pattern detection mode -> ignore date event on uart
  133. * (should never happen, but if it does, we could still
  134. * read the valid data once pattern detect event fired) */
  135. return;
  136. }
  137. size_t length = 0;
  138. uart_get_buffered_data_len(esp_dte->uart_port, &length);
  139. length = MIN(esp_dte->line_buffer_size, length);
  140. length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
  141. /* pass the input data to configured callback */
  142. if (length) {
  143. esp_dte->receive_cb(esp_dte->buffer, length, esp_dte->receive_cb_ctx);
  144. }
  145. }
  146. /**
  147. * @brief UART Event Task Entry
  148. *
  149. * @param param task parameter
  150. */
  151. static void uart_event_task_entry(void *param)
  152. {
  153. esp_modem_dte_t *esp_dte = (esp_modem_dte_t *)param;
  154. uart_event_t event;
  155. while (1) {
  156. if (xQueueReceive(esp_dte->event_queue, &event, pdMS_TO_TICKS(100))) {
  157. switch (event.type) {
  158. case UART_DATA:
  159. esp_handle_uart_data(esp_dte);
  160. break;
  161. case UART_FIFO_OVF:
  162. ESP_LOGW(MODEM_TAG, "HW FIFO Overflow");
  163. uart_flush_input(esp_dte->uart_port);
  164. xQueueReset(esp_dte->event_queue);
  165. break;
  166. case UART_BUFFER_FULL:
  167. ESP_LOGW(MODEM_TAG, "Ring Buffer Full");
  168. uart_flush_input(esp_dte->uart_port);
  169. xQueueReset(esp_dte->event_queue);
  170. break;
  171. case UART_BREAK:
  172. ESP_LOGW(MODEM_TAG, "Rx Break");
  173. break;
  174. case UART_PARITY_ERR:
  175. ESP_LOGE(MODEM_TAG, "Parity Error");
  176. break;
  177. case UART_FRAME_ERR:
  178. ESP_LOGE(MODEM_TAG, "Frame Error");
  179. break;
  180. case UART_PATTERN_DET:
  181. esp_handle_uart_pattern(esp_dte);
  182. break;
  183. default:
  184. ESP_LOGW(MODEM_TAG, "unknown uart event type: %d", event.type);
  185. break;
  186. }
  187. }
  188. /* Drive the event loop */
  189. esp_event_loop_run(esp_dte->event_loop_hdl, pdMS_TO_TICKS(50));
  190. }
  191. vTaskDelete(NULL);
  192. }
  193. /**
  194. * @brief Send command to DCE
  195. *
  196. * @param dte Modem DTE object
  197. * @param command command string
  198. * @param timeout timeout value, unit: ms
  199. * @return esp_err_t
  200. * - ESP_OK on success
  201. * - ESP_FAIL on error
  202. */
  203. static esp_err_t esp_modem_dte_send_cmd(modem_dte_t *dte, const char *command, uint32_t timeout)
  204. {
  205. esp_err_t ret = ESP_FAIL;
  206. modem_dce_t *dce = dte->dce;
  207. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  208. MODEM_CHECK(command, "command is NULL", err);
  209. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  210. /* Calculate timeout clock tick */
  211. /* Reset runtime information */
  212. dce->state = MODEM_STATE_PROCESSING;
  213. /* Send command via UART */
  214. uart_write_bytes(esp_dte->uart_port, command, strlen(command));
  215. /* Check timeout */
  216. MODEM_CHECK(xSemaphoreTake(esp_dte->process_sem, pdMS_TO_TICKS(timeout)) == pdTRUE, "process command timeout", err);
  217. ret = ESP_OK;
  218. err:
  219. dce->handle_line = NULL;
  220. return ret;
  221. }
  222. /**
  223. * @brief Send data to DCE
  224. *
  225. * @param dte Modem DTE object
  226. * @param data data buffer
  227. * @param length length of data to send
  228. * @return int actual length of data that has been send out
  229. */
  230. static int esp_modem_dte_send_data(modem_dte_t *dte, const char *data, uint32_t length)
  231. {
  232. MODEM_CHECK(data, "data is NULL", err);
  233. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  234. return uart_write_bytes(esp_dte->uart_port, data, length);
  235. err:
  236. return -1;
  237. }
  238. /**
  239. * @brief Send data and wait for prompt from DCE
  240. *
  241. * @param dte Modem DTE object
  242. * @param data data buffer
  243. * @param length length of data to send
  244. * @param prompt pointer of specific prompt
  245. * @param timeout timeout value (unit: ms)
  246. * @return esp_err_t
  247. * ESP_OK on success
  248. * ESP_FAIL on error
  249. */
  250. static esp_err_t esp_modem_dte_send_wait(modem_dte_t *dte, const char *data, uint32_t length,
  251. const char *prompt, uint32_t timeout)
  252. {
  253. MODEM_CHECK(data, "data is NULL", err_param);
  254. MODEM_CHECK(prompt, "prompt is NULL", err_param);
  255. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  256. // We'd better disable pattern detection here for a moment in case prompt string contains the pattern character
  257. uart_disable_pattern_det_intr(esp_dte->uart_port);
  258. // uart_disable_rx_intr(esp_dte->uart_port);
  259. MODEM_CHECK(uart_write_bytes(esp_dte->uart_port, data, length) >= 0, "uart write bytes failed", err_write);
  260. uint32_t len = strlen(prompt);
  261. uint8_t *buffer = calloc(len + 1, sizeof(uint8_t));
  262. int res = uart_read_bytes(esp_dte->uart_port, buffer, len, pdMS_TO_TICKS(timeout));
  263. MODEM_CHECK(res >= len, "wait prompt [%s] timeout", err, prompt);
  264. MODEM_CHECK(!strncmp(prompt, (const char *)buffer, len), "get wrong prompt: %s", err, buffer);
  265. free(buffer);
  266. uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  267. return ESP_OK;
  268. err:
  269. free(buffer);
  270. err_write:
  271. uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  272. err_param:
  273. return ESP_FAIL;
  274. }
  275. /**
  276. * @brief Change Modem's working mode
  277. *
  278. * @param dte Modem DTE object
  279. * @param new_mode new working mode
  280. * @return esp_err_t
  281. * - ESP_OK on success
  282. * - ESP_FAIL on error
  283. */
  284. static esp_err_t esp_modem_dte_change_mode(modem_dte_t *dte, modem_mode_t new_mode)
  285. {
  286. modem_dce_t *dce = dte->dce;
  287. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  288. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  289. MODEM_CHECK(dce->mode != new_mode, "already in mode: %d", err, new_mode);
  290. switch (new_mode) {
  291. case MODEM_PPP_MODE:
  292. MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err, new_mode);
  293. uart_disable_pattern_det_intr(esp_dte->uart_port);
  294. uart_enable_rx_intr(esp_dte->uart_port);
  295. break;
  296. case MODEM_COMMAND_MODE:
  297. uart_disable_rx_intr(esp_dte->uart_port);
  298. uart_flush(esp_dte->uart_port);
  299. uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  300. uart_pattern_queue_reset(esp_dte->uart_port, esp_dte->pattern_queue_size);
  301. MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err, new_mode);
  302. break;
  303. default:
  304. break;
  305. }
  306. return ESP_OK;
  307. err:
  308. return ESP_FAIL;
  309. }
  310. static esp_err_t esp_modem_dte_process_cmd_done(modem_dte_t *dte)
  311. {
  312. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  313. return xSemaphoreGive(esp_dte->process_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
  314. }
  315. /**
  316. * @brief Deinitialize a Modem DTE object
  317. *
  318. * @param dte Modem DTE object
  319. * @return esp_err_t
  320. * - ESP_OK on success
  321. * - ESP_FAIL on error
  322. */
  323. static esp_err_t esp_modem_dte_deinit(modem_dte_t *dte)
  324. {
  325. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  326. /* Delete UART event task */
  327. vTaskDelete(esp_dte->uart_event_task_hdl);
  328. /* Delete semaphore */
  329. vSemaphoreDelete(esp_dte->process_sem);
  330. /* Delete event loop */
  331. esp_event_loop_delete(esp_dte->event_loop_hdl);
  332. /* Uninstall UART Driver */
  333. uart_driver_delete(esp_dte->uart_port);
  334. /* Free memory */
  335. free(esp_dte->buffer);
  336. if (dte->dce) {
  337. dte->dce->dte = NULL;
  338. }
  339. free(esp_dte);
  340. return ESP_OK;
  341. }
  342. modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config)
  343. {
  344. esp_err_t res;
  345. /* malloc memory for esp_dte object */
  346. esp_modem_dte_t *esp_dte = calloc(1, sizeof(esp_modem_dte_t));
  347. MODEM_CHECK(esp_dte, "calloc esp_dte failed", err_dte_mem);
  348. /* malloc memory to storing lines from modem dce */
  349. esp_dte->line_buffer_size = config->line_buffer_size;
  350. esp_dte->buffer = calloc(1, config->line_buffer_size);
  351. MODEM_CHECK(esp_dte->buffer, "calloc line memory failed", err_line_mem);
  352. /* Set attributes */
  353. esp_dte->uart_port = config->port_num;
  354. esp_dte->parent.flow_ctrl = config->flow_control;
  355. /* Bind methods */
  356. esp_dte->parent.send_cmd = esp_modem_dte_send_cmd;
  357. esp_dte->parent.send_data = esp_modem_dte_send_data;
  358. esp_dte->parent.send_wait = esp_modem_dte_send_wait;
  359. esp_dte->parent.change_mode = esp_modem_dte_change_mode;
  360. esp_dte->parent.process_cmd_done = esp_modem_dte_process_cmd_done;
  361. esp_dte->parent.deinit = esp_modem_dte_deinit;
  362. /* Config UART */
  363. uart_config_t uart_config = {
  364. .baud_rate = config->baud_rate,
  365. .data_bits = config->data_bits,
  366. .parity = config->parity,
  367. .stop_bits = config->stop_bits,
  368. .source_clk = UART_SCLK_REF_TICK,
  369. .flow_ctrl = (config->flow_control == MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE
  370. };
  371. MODEM_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config);
  372. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  373. res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
  374. config->rts_io_num, config->cts_io_num);
  375. } else {
  376. res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
  377. UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  378. }
  379. MODEM_CHECK(res == ESP_OK, "config uart gpio failed", err_uart_config);
  380. /* Set flow control threshold */
  381. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  382. res = uart_set_hw_flow_ctrl(esp_dte->uart_port, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
  383. } else if (config->flow_control == MODEM_FLOW_CONTROL_SW) {
  384. res = uart_set_sw_flow_ctrl(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8);
  385. }
  386. MODEM_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config);
  387. /* Install UART driver and get event queue used inside driver */
  388. res = uart_driver_install(esp_dte->uart_port, config->rx_buffer_size, config->tx_buffer_size,
  389. config->event_queue_size, &(esp_dte->event_queue), 0);
  390. MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config);
  391. /* Set pattern interrupt, used to detect the end of a line. */
  392. res = uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  393. /* Set pattern queue size */
  394. esp_dte->pattern_queue_size = config->pattern_queue_size;
  395. res |= uart_pattern_queue_reset(esp_dte->uart_port, config->pattern_queue_size);
  396. /* Starting in command mode -> explicitly disable RX interrupt */
  397. uart_disable_rx_intr(esp_dte->uart_port);
  398. MODEM_CHECK(res == ESP_OK, "config uart pattern failed", err_uart_pattern);
  399. /* Create Event loop */
  400. esp_event_loop_args_t loop_args = {
  401. .queue_size = ESP_MODEM_EVENT_QUEUE_SIZE,
  402. .task_name = NULL
  403. };
  404. MODEM_CHECK(esp_event_loop_create(&loop_args, &esp_dte->event_loop_hdl) == ESP_OK, "create event loop failed", err_eloop);
  405. /* Create semaphore */
  406. esp_dte->process_sem = xSemaphoreCreateBinary();
  407. MODEM_CHECK(esp_dte->process_sem, "create process semaphore failed", err_sem);
  408. /* Create UART Event task */
  409. BaseType_t ret = xTaskCreate(uart_event_task_entry, //Task Entry
  410. "uart_event", //Task Name
  411. config->event_task_stack_size, //Task Stack Size(Bytes)
  412. esp_dte, //Task Parameter
  413. config->event_task_priority, //Task Priority
  414. & (esp_dte->uart_event_task_hdl) //Task Handler
  415. );
  416. MODEM_CHECK(ret == pdTRUE, "create uart event task failed", err_tsk_create);
  417. return &(esp_dte->parent);
  418. /* Error handling */
  419. err_tsk_create:
  420. vSemaphoreDelete(esp_dte->process_sem);
  421. err_sem:
  422. esp_event_loop_delete(esp_dte->event_loop_hdl);
  423. err_eloop:
  424. uart_disable_pattern_det_intr(esp_dte->uart_port);
  425. err_uart_pattern:
  426. uart_driver_delete(esp_dte->uart_port);
  427. err_uart_config:
  428. free(esp_dte->buffer);
  429. err_line_mem:
  430. free(esp_dte);
  431. err_dte_mem:
  432. return NULL;
  433. }
  434. esp_err_t esp_modem_set_event_handler(modem_dte_t *dte, esp_event_handler_t handler, int32_t event_id, void *handler_args)
  435. {
  436. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  437. return esp_event_handler_register_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, event_id, handler, handler_args);
  438. }
  439. esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t handler)
  440. {
  441. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  442. return esp_event_handler_unregister_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_EVENT_ANY_ID, handler);
  443. }
  444. esp_err_t esp_modem_start_ppp(modem_dte_t *dte)
  445. {
  446. modem_dce_t *dce = dte->dce;
  447. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  448. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  449. /* Set PDP Context */
  450. MODEM_CHECK(dce->define_pdp_context(dce, 1, "IP", CONFIG_EXAMPLE_COMPONENT_MODEM_APN) == ESP_OK, "set MODEM APN failed", err);
  451. /* Enter PPP mode */
  452. MODEM_CHECK(dte->change_mode(dte, MODEM_PPP_MODE) == ESP_OK, "enter ppp mode failed", err);
  453. /* post PPP mode started event */
  454. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_START, NULL, 0, 0);
  455. return ESP_OK;
  456. err:
  457. return ESP_FAIL;
  458. }
  459. esp_err_t esp_modem_stop_ppp(modem_dte_t *dte)
  460. {
  461. modem_dce_t *dce = dte->dce;
  462. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  463. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  464. /* post PPP mode stopped event */
  465. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_STOP, NULL, 0, 0);
  466. /* Enter command mode */
  467. MODEM_CHECK(dte->change_mode(dte, MODEM_COMMAND_MODE) == ESP_OK, "enter command mode failed", err);
  468. /* Hang up */
  469. MODEM_CHECK(dce->hang_up(dce) == ESP_OK, "hang up failed", err);
  470. return ESP_OK;
  471. err:
  472. return ESP_FAIL;
  473. }