esp_modem.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/param.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "freertos/task.h"
  11. #include "freertos/semphr.h"
  12. #include "esp_modem.h"
  13. #include "esp_log.h"
  14. #include "sdkconfig.h"
  15. #define ESP_MODEM_EVENT_QUEUE_SIZE (16)
  16. /**
  17. * @brief This sets the threshold for receiving data events when UART RX buffer reaches
  18. * this level. Decreasing the number causes more events and lowers changes of UART overflows,
  19. * but more allocations in lwIP. You can increase this number if you're using slower baudrates
  20. * or having the UART ISR in IRAM.
  21. */
  22. #define ESP_MODEM_UART_RX_FULL_THRESHOLD (64)
  23. /**
  24. * @brief Macro defined for error checking
  25. *
  26. */
  27. static const char *MODEM_TAG = "esp-modem";
  28. #define MODEM_CHECK(a, str, goto_tag, ...) \
  29. do \
  30. { \
  31. if (!(a)) \
  32. { \
  33. ESP_LOGE(MODEM_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
  34. goto goto_tag; \
  35. } \
  36. } while (0)
  37. ESP_EVENT_DEFINE_BASE(ESP_MODEM_EVENT);
  38. /**
  39. * @brief ESP32 Modem DTE
  40. *
  41. */
  42. typedef struct {
  43. uart_port_t uart_port; /*!< UART port */
  44. uint8_t *buffer; /*!< Internal buffer to store response lines/data from DCE */
  45. QueueHandle_t event_queue; /*!< UART event queue handle */
  46. esp_event_loop_handle_t event_loop_hdl; /*!< Event loop handle */
  47. TaskHandle_t uart_event_task_hdl; /*!< UART event task handle */
  48. SemaphoreHandle_t process_sem; /*!< Semaphore used for indicating processing status */
  49. SemaphoreHandle_t exit_sem; /*!< Semaphore used for indicating PPP mode has stopped */
  50. modem_dte_t parent; /*!< DTE interface that should extend */
  51. esp_modem_on_receive receive_cb; /*!< ptr to data reception */
  52. void *receive_cb_ctx; /*!< ptr to rx fn context data */
  53. int buffer_size; /*!< internal buffer size */
  54. int consumed; /*!< index to the consumed buffer pointer */
  55. } esp_modem_dte_t;
  56. /**
  57. * @brief Returns true if the supplied string contains only <CR> characters
  58. *
  59. * @param str string to check
  60. * @param len length of string
  61. */
  62. static inline bool is_only_cr(const char *str, uint32_t len)
  63. {
  64. for (int i=0; i<len; ++i) {
  65. if (str[i] != '\r') {
  66. return false;
  67. }
  68. }
  69. return true;
  70. }
  71. static inline void report_unknown_line(esp_modem_dte_t *esp_dte, char *line, int line_len)
  72. {
  73. /* Send ESP_MODEM_EVENT_UNKNOWN signal to event loop */
  74. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_UNKNOWN,
  75. (void *)line, line_len + 1, pdMS_TO_TICKS(100));
  76. }
  77. esp_err_t esp_modem_set_rx_cb(modem_dte_t *dte, esp_modem_on_receive receive_cb, void *receive_cb_ctx)
  78. {
  79. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  80. esp_dte->receive_cb_ctx = receive_cb_ctx;
  81. esp_dte->receive_cb = receive_cb;
  82. return ESP_OK;
  83. }
  84. /**
  85. * @brief Handle one line in DTE
  86. *
  87. * @param esp_dte ESP modem DTE object
  88. * @return esp_err_t
  89. * - ESP_OK on success
  90. * - ESP_FAIL on error
  91. */
  92. static esp_err_t esp_dte_handle_line(esp_modem_dte_t *esp_dte, char * line, size_t len, char separator)
  93. {
  94. esp_err_t err = ESP_FAIL;
  95. modem_dce_t *dce = esp_dte->parent.dce;
  96. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  97. if (separator != '\n' && dce->handle_line) {
  98. /* If waiting for a specific separator, just pass the entire string */
  99. MODEM_CHECK(dce->handle_line(dce, line) == ESP_OK, "handle line failed", post_event_unknown);
  100. return ESP_OK;
  101. }
  102. /* Tokenize the data to call handlers separately for each *line* */
  103. char *str_ptr = NULL;
  104. char *p = strtok_r(line, "\n", &str_ptr);
  105. while (p) {
  106. int plen = strlen(p);
  107. if (plen > 1 && !is_only_cr(p, plen)) {
  108. ESP_LOGD(MODEM_TAG, "Handling line: >>%s\n<<", p);
  109. if (dce->handle_line == NULL) {
  110. /* Received an asynchronous line, but no handler waiting this this */
  111. ESP_LOGD(MODEM_TAG, "No handler for line: %s", p);
  112. report_unknown_line(esp_dte, p, plen);
  113. return ESP_OK; /* Not an error, just propagate the line to user handler */
  114. }
  115. if (dce->handle_line(dce, p) != ESP_OK) {
  116. ESP_LOGE(MODEM_TAG, "handle line failed");
  117. report_unknown_line(esp_dte, p, plen);
  118. }
  119. }
  120. p = strtok_r(NULL, "\n", &str_ptr);
  121. }
  122. return ESP_OK;
  123. post_event_unknown:
  124. report_unknown_line(esp_dte, line, strlen(line));
  125. err:
  126. return err;
  127. }
  128. /**
  129. * @brief Handle when new data received by UART
  130. *
  131. * @param esp_dte ESP32 Modem DTE object
  132. */
  133. static void esp_handle_uart_data(esp_modem_dte_t *esp_dte)
  134. {
  135. size_t length = 0;
  136. uart_get_buffered_data_len(esp_dte->uart_port, &length);
  137. ESP_LOGV(MODEM_TAG, "uart_get_buffered_data_len()=%d", length);
  138. if (esp_dte->parent.dce->mode != MODEM_PPP_MODE && length) {
  139. // Read the data and process it using `handle_line` logic
  140. length = MIN(esp_dte->buffer_size - 1, length);
  141. length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer + esp_dte->consumed, length - esp_dte->consumed, portMAX_DELAY);
  142. const char separator = esp_dte->parent.dce->prompt == NULL ? '\n' : (esp_dte->parent.dce->prompt)[strlen(esp_dte->parent.dce->prompt)-1];
  143. if (memchr(esp_dte->buffer + esp_dte->consumed, separator, length)) {
  144. esp_dte->buffer[length] = '\0';
  145. ESP_LOG_BUFFER_HEXDUMP("esp-modem: pattern-detection", esp_dte->buffer, length, ESP_LOG_VERBOSE);
  146. if (esp_dte->parent.dce->handle_line) {
  147. /* Send new line to handle if handler registered */
  148. if (esp_dte_handle_line(esp_dte, (char*)esp_dte->buffer, length, separator) == ESP_OK) {
  149. esp_dte->consumed = 0;
  150. return;
  151. }
  152. }
  153. esp_dte->consumed += length;
  154. }
  155. return;
  156. }
  157. length = MIN(esp_dte->buffer_size, length);
  158. length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
  159. /* pass the input data to configured callback */
  160. if (length) {
  161. esp_dte->receive_cb(esp_dte->buffer, length, esp_dte->receive_cb_ctx);
  162. }
  163. }
  164. /**
  165. * @brief UART Event Task Entry
  166. *
  167. * @param param task parameter
  168. */
  169. static void uart_event_task_entry(void *param)
  170. {
  171. esp_modem_dte_t *esp_dte = (esp_modem_dte_t *)param;
  172. uart_event_t event;
  173. while (1) {
  174. /* Drive the event loop */
  175. esp_event_loop_run(esp_dte->event_loop_hdl, pdMS_TO_TICKS(0));
  176. /* Process UART events */
  177. if (xQueueReceive(esp_dte->event_queue, &event, pdMS_TO_TICKS(100))) {
  178. if (esp_dte->parent.dce == NULL) {
  179. ESP_LOGD(MODEM_TAG, "Ignore UART event for DTE with no DCE attached");
  180. // No action on any uart event with null DCE.
  181. // This might happen before DCE gets initialized and attached to running DTE,
  182. // or after destroying the DCE when DTE is up and gets a data event.
  183. uart_flush(esp_dte->uart_port);
  184. continue;
  185. }
  186. switch (event.type) {
  187. case UART_DATA:
  188. esp_handle_uart_data(esp_dte);
  189. break;
  190. case UART_FIFO_OVF:
  191. ESP_LOGW(MODEM_TAG, "HW FIFO Overflow");
  192. uart_flush_input(esp_dte->uart_port);
  193. xQueueReset(esp_dte->event_queue);
  194. break;
  195. case UART_BUFFER_FULL:
  196. ESP_LOGW(MODEM_TAG, "Ring Buffer Full");
  197. uart_flush_input(esp_dte->uart_port);
  198. xQueueReset(esp_dte->event_queue);
  199. break;
  200. case UART_BREAK:
  201. ESP_LOGW(MODEM_TAG, "Rx Break");
  202. break;
  203. case UART_PARITY_ERR:
  204. ESP_LOGE(MODEM_TAG, "Parity Error");
  205. break;
  206. case UART_FRAME_ERR:
  207. ESP_LOGE(MODEM_TAG, "Frame Error");
  208. break;
  209. default:
  210. ESP_LOGW(MODEM_TAG, "unknown uart event type: %d", event.type);
  211. break;
  212. }
  213. }
  214. }
  215. }
  216. /**
  217. * @brief Send command to DCE
  218. *
  219. * @param dte Modem DTE object
  220. * @param command command string
  221. * @param timeout timeout value, unit: ms
  222. * @return esp_err_t
  223. * - ESP_OK on success
  224. * - ESP_FAIL on error
  225. */
  226. static esp_err_t esp_modem_dte_send_cmd(modem_dte_t *dte, const char *command, uint32_t timeout)
  227. {
  228. esp_err_t ret = ESP_FAIL;
  229. modem_dce_t *dce = dte->dce;
  230. ESP_LOGD(MODEM_TAG, "Sending command:%s", command);
  231. MODEM_CHECK(dce, "DTE has not yet bind with DCE", errdce);
  232. MODEM_CHECK(command, "command is NULL", err);
  233. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  234. esp_dte->consumed = 0;
  235. /* Calculate timeout clock tick */
  236. /* Reset runtime information */
  237. dce->state = MODEM_STATE_PROCESSING;
  238. /* Send command via UART */
  239. uart_write_bytes(esp_dte->uart_port, command, strlen(command));
  240. /* Check timeout */
  241. MODEM_CHECK(xSemaphoreTake(esp_dte->process_sem, pdMS_TO_TICKS(timeout)) == pdTRUE, "process command timeout", err);
  242. ret = ESP_OK;
  243. err:
  244. dce->handle_line = NULL;
  245. errdce:
  246. return ret;
  247. }
  248. /**
  249. * @brief Send data to DCE
  250. *
  251. * @param dte Modem DTE object
  252. * @param data data buffer
  253. * @param length length of data to send
  254. * @return int actual length of data that has been send out
  255. */
  256. static int esp_modem_dte_send_data(modem_dte_t *dte, const char *data, uint32_t length)
  257. {
  258. MODEM_CHECK(data, "data is NULL", err);
  259. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  260. if (esp_dte->parent.dce->mode == MODEM_TRANSITION_MODE) {
  261. ESP_LOGD(MODEM_TAG, "Not sending data in transition mode");
  262. return -1;
  263. }
  264. return uart_write_bytes(esp_dte->uart_port, data, length);
  265. err:
  266. return -1;
  267. }
  268. /**
  269. * @brief Handle response from send data and wait from prompt.
  270. */
  271. static esp_err_t esp_modem_dte_send_wait_default_handler(modem_dce_t *dce, const char *line)
  272. {
  273. esp_err_t err = ESP_FAIL;
  274. if (!strncmp(line, dce->prompt, strlen(dce->prompt))) {
  275. dce->state = MODEM_STATE_SUCCESS;
  276. err = dce->dte->process_cmd_done(dce->dte);
  277. } else {
  278. dce->state = MODEM_STATE_FAIL;
  279. err = dce->dte->process_cmd_done(dce->dte);
  280. }
  281. return err;
  282. }
  283. /**
  284. * @brief Send data and wait for prompt from DCE
  285. *
  286. * @param dte Modem DTE object
  287. * @param data data buffer
  288. * @param length length of data to send
  289. * @param prompt pointer of specific prompt
  290. * @param timeout timeout value (unit: ms)
  291. * @return esp_err_t
  292. * ESP_OK on success
  293. * ESP_FAIL on error
  294. */
  295. static esp_err_t esp_modem_dte_send_wait(modem_dte_t *dte, const char *data, uint32_t length,
  296. const char *prompt, uint32_t timeout)
  297. {
  298. MODEM_CHECK(data, "data is NULL", err_param);
  299. MODEM_CHECK(prompt, "prompt is NULL", err_param);
  300. modem_dce_t *dce = dte->dce;
  301. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err_param);
  302. dce->prompt = prompt; // the last character of this prompt will be used as a separator to call the line handker
  303. dce->handle_line = esp_modem_dte_send_wait_default_handler;
  304. MODEM_CHECK(dte->send_cmd(dte, data, timeout) == ESP_OK, "wait for prompt timeout", err);
  305. MODEM_CHECK(dce->state == MODEM_STATE_SUCCESS, "wait for prompt failed", err);
  306. dce->prompt = NULL;
  307. return ESP_OK;
  308. err:
  309. dce->prompt = NULL;
  310. err_param:
  311. return ESP_FAIL;
  312. }
  313. /**
  314. * @brief Change Modem's working mode
  315. *
  316. * @param dte Modem DTE object
  317. * @param new_mode new working mode
  318. * @return esp_err_t
  319. * - ESP_OK on success
  320. * - ESP_FAIL on error
  321. */
  322. static esp_err_t esp_modem_dte_change_mode(modem_dte_t *dte, modem_mode_t new_mode)
  323. {
  324. modem_dce_t *dce = dte->dce;
  325. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  326. modem_mode_t current_mode = dce->mode;
  327. MODEM_CHECK(current_mode != new_mode, "already in mode: %d", err, new_mode);
  328. dce->mode = MODEM_TRANSITION_MODE; // mode switching will be finished in set_working_mode() on success
  329. // (or restored on failure)
  330. MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err_restore_mode, new_mode);
  331. return ESP_OK;
  332. err_restore_mode:
  333. dce->mode = current_mode;
  334. err:
  335. return ESP_FAIL;
  336. }
  337. static esp_err_t esp_modem_dte_process_cmd_done(modem_dte_t *dte)
  338. {
  339. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  340. return xSemaphoreGive(esp_dte->process_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
  341. }
  342. /**
  343. * @brief Deinitialize a Modem DTE object
  344. *
  345. * @param dte Modem DTE object
  346. * @return esp_err_t
  347. * - ESP_OK on success
  348. * - ESP_FAIL on error
  349. */
  350. static esp_err_t esp_modem_dte_deinit(modem_dte_t *dte)
  351. {
  352. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  353. /* Delete UART event task */
  354. vTaskDelete(esp_dte->uart_event_task_hdl);
  355. /* Delete semaphores */
  356. vSemaphoreDelete(esp_dte->process_sem);
  357. vSemaphoreDelete(esp_dte->exit_sem);
  358. /* Delete event loop */
  359. esp_event_loop_delete(esp_dte->event_loop_hdl);
  360. /* Uninstall UART Driver */
  361. uart_driver_delete(esp_dte->uart_port);
  362. /* Free memory */
  363. free(esp_dte->buffer);
  364. if (dte->dce) {
  365. dte->dce->dte = NULL;
  366. }
  367. free(esp_dte);
  368. return ESP_OK;
  369. }
  370. modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config)
  371. {
  372. esp_err_t res;
  373. /* malloc memory for esp_dte object */
  374. esp_modem_dte_t *esp_dte = calloc(1, sizeof(esp_modem_dte_t));
  375. MODEM_CHECK(esp_dte, "calloc esp_dte failed", err_dte_mem);
  376. /* malloc memory to storing lines from modem dce */
  377. esp_dte->buffer_size = config->dte_buffer_size;
  378. esp_dte->buffer = calloc(1, config->dte_buffer_size);
  379. MODEM_CHECK(esp_dte->buffer, "calloc line memory failed", err_line_mem);
  380. /* Set attributes */
  381. esp_dte->uart_port = config->port_num;
  382. esp_dte->parent.flow_ctrl = config->flow_control;
  383. /* Bind methods */
  384. esp_dte->parent.send_cmd = esp_modem_dte_send_cmd;
  385. esp_dte->parent.send_data = esp_modem_dte_send_data;
  386. esp_dte->parent.send_wait = esp_modem_dte_send_wait;
  387. esp_dte->parent.change_mode = esp_modem_dte_change_mode;
  388. esp_dte->parent.process_cmd_done = esp_modem_dte_process_cmd_done;
  389. esp_dte->parent.deinit = esp_modem_dte_deinit;
  390. /* Config UART */
  391. uart_config_t uart_config = {
  392. .baud_rate = config->baud_rate,
  393. .data_bits = config->data_bits,
  394. .parity = config->parity,
  395. .stop_bits = config->stop_bits,
  396. #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
  397. .source_clk = UART_SCLK_REF_TICK,
  398. #else
  399. .source_clk = UART_SCLK_XTAL,
  400. #endif
  401. .flow_ctrl = (config->flow_control == MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE
  402. };
  403. MODEM_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config);
  404. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  405. res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
  406. config->rts_io_num, config->cts_io_num);
  407. } else {
  408. res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
  409. UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  410. }
  411. MODEM_CHECK(res == ESP_OK, "config uart gpio failed", err_uart_config);
  412. /* Set flow control threshold */
  413. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  414. res = uart_set_hw_flow_ctrl(esp_dte->uart_port, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
  415. } else if (config->flow_control == MODEM_FLOW_CONTROL_SW) {
  416. res = uart_set_sw_flow_ctrl(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8);
  417. }
  418. MODEM_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config);
  419. /* Install UART driver and get event queue used inside driver */
  420. res = uart_driver_install(esp_dte->uart_port, config->rx_buffer_size, config->tx_buffer_size,
  421. config->event_queue_size, &(esp_dte->event_queue), 0);
  422. MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config);
  423. res = uart_set_rx_timeout(esp_dte->uart_port, 1);
  424. MODEM_CHECK(res == ESP_OK, "set rx timeout failed", err_uart_config);
  425. res = uart_set_rx_full_threshold(config->port_num, ESP_MODEM_UART_RX_FULL_THRESHOLD);
  426. MODEM_CHECK(res == ESP_OK, "config rx full threshold failed", err_uart_config);
  427. /* Create Event loop */
  428. esp_event_loop_args_t loop_args = {
  429. .queue_size = ESP_MODEM_EVENT_QUEUE_SIZE,
  430. .task_name = NULL
  431. };
  432. MODEM_CHECK(esp_event_loop_create(&loop_args, &esp_dte->event_loop_hdl) == ESP_OK, "create event loop failed", err_eloop);
  433. /* Create semaphore */
  434. esp_dte->process_sem = xSemaphoreCreateBinary();
  435. MODEM_CHECK(esp_dte->process_sem, "create process semaphore failed", err_sem1);
  436. esp_dte->exit_sem = xSemaphoreCreateBinary();
  437. MODEM_CHECK(esp_dte->exit_sem, "create exit semaphore failed", err_sem);
  438. /* Create UART Event task */
  439. BaseType_t ret = xTaskCreate(uart_event_task_entry, //Task Entry
  440. "uart_event", //Task Name
  441. config->event_task_stack_size, //Task Stack Size(Bytes)
  442. esp_dte, //Task Parameter
  443. config->event_task_priority, //Task Priority
  444. & (esp_dte->uart_event_task_hdl) //Task Handler
  445. );
  446. MODEM_CHECK(ret == pdTRUE, "create uart event task failed", err_tsk_create);
  447. return &(esp_dte->parent);
  448. /* Error handling */
  449. err_tsk_create:
  450. vSemaphoreDelete(esp_dte->exit_sem);
  451. err_sem:
  452. vSemaphoreDelete(esp_dte->process_sem);
  453. err_sem1:
  454. esp_event_loop_delete(esp_dte->event_loop_hdl);
  455. err_eloop:
  456. uart_driver_delete(esp_dte->uart_port);
  457. err_uart_config:
  458. free(esp_dte->buffer);
  459. err_line_mem:
  460. free(esp_dte);
  461. err_dte_mem:
  462. return NULL;
  463. }
  464. esp_err_t esp_modem_set_event_handler(modem_dte_t *dte, esp_event_handler_t handler, int32_t event_id, void *handler_args)
  465. {
  466. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  467. return esp_event_handler_register_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, event_id, handler, handler_args);
  468. }
  469. esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t handler)
  470. {
  471. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  472. return esp_event_handler_unregister_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_EVENT_ANY_ID, handler);
  473. }
  474. esp_err_t esp_modem_start_ppp(modem_dte_t *dte)
  475. {
  476. modem_dce_t *dce = dte->dce;
  477. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  478. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  479. /* Set PDP Context */
  480. MODEM_CHECK(dce->define_pdp_context(dce, 1, "IP", CONFIG_EXAMPLE_COMPONENT_MODEM_APN) == ESP_OK, "set MODEM APN failed", err);
  481. /* Enter PPP mode */
  482. MODEM_CHECK(dte->change_mode(dte, MODEM_PPP_MODE) == ESP_OK, "enter ppp mode failed", err);
  483. /* post PPP mode started event */
  484. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_START, NULL, 0, 0);
  485. return ESP_OK;
  486. err:
  487. return ESP_FAIL;
  488. }
  489. esp_err_t esp_modem_stop_ppp(modem_dte_t *dte)
  490. {
  491. modem_dce_t *dce = dte->dce;
  492. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  493. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  494. /* Enter command mode */
  495. MODEM_CHECK(dte->change_mode(dte, MODEM_COMMAND_MODE) == ESP_OK, "enter command mode failed", err);
  496. /* post PPP mode stopped event */
  497. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_STOP, NULL, 0, 0);
  498. /* Hang up */
  499. MODEM_CHECK(dce->hang_up(dce) == ESP_OK, "hang up failed", err);
  500. /* wait for the PPP mode to exit gracefully */
  501. if (xSemaphoreTake(esp_dte->exit_sem, pdMS_TO_TICKS(20000)) != pdTRUE) {
  502. ESP_LOGW(MODEM_TAG, "Failed to exit the PPP mode gracefully");
  503. }
  504. return ESP_OK;
  505. err:
  506. return ESP_FAIL;
  507. }
  508. esp_err_t esp_modem_notify_ppp_netif_closed(modem_dte_t *dte)
  509. {
  510. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  511. return xSemaphoreGive(esp_dte->exit_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
  512. }