esp_modem.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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. SemaphoreHandle_t exit_sem; /*!< Semaphore used for indicating PPP mode has stopped */
  54. modem_dte_t parent; /*!< DTE interface that should extend */
  55. esp_modem_on_receive receive_cb; /*!< ptr to data reception */
  56. void *receive_cb_ctx; /*!< ptr to rx fn context data */
  57. int line_buffer_size; /*!< line buffer size in commnad mode */
  58. int pattern_queue_size; /*!< UART pattern queue size */
  59. } esp_modem_dte_t;
  60. /**
  61. * @brief Returns true if the supplied string contains only CR or LF
  62. *
  63. * @param str string to check
  64. * @param len length of string
  65. */
  66. static inline bool is_only_cr_lf(const char *str, uint32_t len)
  67. {
  68. for (int i=0; i<len; ++i) {
  69. if (str[i] != '\r' && str[i] != '\n') {
  70. return false;
  71. }
  72. }
  73. return true;
  74. }
  75. esp_err_t esp_modem_set_rx_cb(modem_dte_t *dte, esp_modem_on_receive receive_cb, void *receive_cb_ctx)
  76. {
  77. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  78. esp_dte->receive_cb_ctx = receive_cb_ctx;
  79. esp_dte->receive_cb = receive_cb;
  80. return ESP_OK;
  81. }
  82. /**
  83. * @brief Handle one line in DTE
  84. *
  85. * @param esp_dte ESP modem DTE object
  86. * @return esp_err_t
  87. * - ESP_OK on success
  88. * - ESP_FAIL on error
  89. */
  90. static esp_err_t esp_dte_handle_line(esp_modem_dte_t *esp_dte)
  91. {
  92. esp_err_t err = ESP_FAIL;
  93. modem_dce_t *dce = esp_dte->parent.dce;
  94. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  95. const char *line = (const char *)(esp_dte->buffer);
  96. size_t len = strlen(line);
  97. /* Skip pure "\r\n" lines */
  98. if (len > 2 && !is_only_cr_lf(line, len)) {
  99. if (dce->handle_line == NULL) {
  100. /* Received an asynchronous line, but no handler waiting this this */
  101. ESP_LOGD(MODEM_TAG, "No handler for line: %s", line);
  102. err = ESP_OK; /* Not an error, just propagate the line to user handler */
  103. goto post_event_unknown;
  104. }
  105. MODEM_CHECK(dce->handle_line(dce, line) == ESP_OK, "handle line failed", post_event_unknown);
  106. }
  107. return ESP_OK;
  108. post_event_unknown:
  109. /* Send ESP_MODEM_EVENT_UNKNOWN signal to event loop */
  110. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_UNKNOWN,
  111. (void *)line, strlen(line) + 1, pdMS_TO_TICKS(100));
  112. err:
  113. return err;
  114. }
  115. /**
  116. * @brief Handle when a pattern has been detected by UART
  117. *
  118. * @param esp_dte ESP32 Modem DTE object
  119. */
  120. static void esp_handle_uart_pattern(esp_modem_dte_t *esp_dte)
  121. {
  122. int pos = uart_pattern_pop_pos(esp_dte->uart_port);
  123. int read_len = 0;
  124. if (esp_dte->parent.dce->mode == MODEM_PPP_MODE) {
  125. ESP_LOGD(MODEM_TAG, "Pattern event in PPP mode ignored");
  126. // Ignore potential pattern detection events in PPP mode
  127. // Note 1: the interrupt is disabled, but some events might still be pending
  128. // Note 2: checking the mode *after* uart_pattern_pop_pos() to consume the event
  129. return;
  130. }
  131. if (pos != -1) {
  132. if (pos < esp_dte->line_buffer_size - 1) {
  133. /* read one line(include '\n') */
  134. read_len = pos + 1;
  135. } else {
  136. ESP_LOGW(MODEM_TAG, "ESP Modem Line buffer too small");
  137. read_len = esp_dte->line_buffer_size - 1;
  138. }
  139. read_len = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, read_len, pdMS_TO_TICKS(100));
  140. if (read_len) {
  141. /* make sure the line is a standard string */
  142. esp_dte->buffer[read_len] = '\0';
  143. /* Send new line to handle */
  144. esp_dte_handle_line(esp_dte);
  145. } else {
  146. ESP_LOGE(MODEM_TAG, "uart read bytes failed");
  147. }
  148. } else {
  149. size_t length = 0;
  150. uart_get_buffered_data_len(esp_dte->uart_port, &length);
  151. if (length) {
  152. ESP_LOGD(MODEM_TAG, "Pattern not found in the pattern queue, uart data length = %d", length);
  153. length = MIN(esp_dte->line_buffer_size-1, length);
  154. length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
  155. ESP_LOG_BUFFER_HEXDUMP("esp-modem-pattern: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG);
  156. }
  157. uart_flush(esp_dte->uart_port);
  158. }
  159. }
  160. /**
  161. * @brief Handle when new data received by UART
  162. *
  163. * @param esp_dte ESP32 Modem DTE object
  164. */
  165. static void esp_handle_uart_data(esp_modem_dte_t *esp_dte)
  166. {
  167. size_t length = 0;
  168. uart_get_buffered_data_len(esp_dte->uart_port, &length);
  169. if (esp_dte->parent.dce->mode != MODEM_PPP_MODE && length) {
  170. // Check if matches the pattern to process the data as pattern
  171. int pos = uart_pattern_get_pos(esp_dte->uart_port);
  172. if (pos > -1) {
  173. esp_handle_uart_pattern(esp_dte);
  174. return;
  175. }
  176. // Read the data and process it using `handle_line` logic
  177. length = MIN(esp_dte->line_buffer_size-1, length);
  178. length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
  179. esp_dte->buffer[length] = '\0';
  180. if (strchr((char*)esp_dte->buffer, '\n') == NULL) {
  181. size_t max = esp_dte->line_buffer_size-1;
  182. size_t bytes;
  183. // if pattern not found in the data,
  184. // continue reading as long as the modem is in MODEM_STATE_PROCESSING, checking for the pattern
  185. while (length < max && esp_dte->buffer[length-1] != '\n' &&
  186. esp_dte->parent.dce->state == MODEM_STATE_PROCESSING) {
  187. bytes = uart_read_bytes(esp_dte->uart_port,
  188. esp_dte->buffer + length, 1, pdMS_TO_TICKS(100));
  189. length += bytes;
  190. ESP_LOGV("esp-modem: debug_data", "Continuous read in non-data mode: length: %d char: %x", length, esp_dte->buffer[length-1]);
  191. }
  192. esp_dte->buffer[length] = '\0';
  193. }
  194. ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", esp_dte->buffer, length, ESP_LOG_DEBUG);
  195. if (esp_dte->parent.dce->handle_line) {
  196. /* Send new line to handle if handler registered */
  197. esp_dte_handle_line(esp_dte);
  198. }
  199. return;
  200. }
  201. length = MIN(esp_dte->line_buffer_size, length);
  202. length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
  203. /* pass the input data to configured callback */
  204. if (length) {
  205. esp_dte->receive_cb(esp_dte->buffer, length, esp_dte->receive_cb_ctx);
  206. }
  207. }
  208. /**
  209. * @brief UART Event Task Entry
  210. *
  211. * @param param task parameter
  212. */
  213. static void uart_event_task_entry(void *param)
  214. {
  215. esp_modem_dte_t *esp_dte = (esp_modem_dte_t *)param;
  216. uart_event_t event;
  217. while (1) {
  218. /* Drive the event loop */
  219. esp_event_loop_run(esp_dte->event_loop_hdl, pdMS_TO_TICKS(0));
  220. /* Process UART events */
  221. if (xQueueReceive(esp_dte->event_queue, &event, pdMS_TO_TICKS(100))) {
  222. if (esp_dte->parent.dce == NULL) {
  223. ESP_LOGD(MODEM_TAG, "Ignore UART event for DTE with no DCE attached");
  224. // No action on any uart event with null DCE.
  225. // This might happen before DCE gets initialized and attached to running DTE,
  226. // or after destroying the DCE when DTE is up and gets a data event.
  227. uart_flush(esp_dte->uart_port);
  228. continue;
  229. }
  230. switch (event.type) {
  231. case UART_DATA:
  232. esp_handle_uart_data(esp_dte);
  233. break;
  234. case UART_FIFO_OVF:
  235. ESP_LOGW(MODEM_TAG, "HW FIFO Overflow");
  236. uart_flush_input(esp_dte->uart_port);
  237. xQueueReset(esp_dte->event_queue);
  238. break;
  239. case UART_BUFFER_FULL:
  240. ESP_LOGW(MODEM_TAG, "Ring Buffer Full");
  241. uart_flush_input(esp_dte->uart_port);
  242. xQueueReset(esp_dte->event_queue);
  243. break;
  244. case UART_BREAK:
  245. ESP_LOGW(MODEM_TAG, "Rx Break");
  246. break;
  247. case UART_PARITY_ERR:
  248. ESP_LOGE(MODEM_TAG, "Parity Error");
  249. break;
  250. case UART_FRAME_ERR:
  251. ESP_LOGE(MODEM_TAG, "Frame Error");
  252. break;
  253. case UART_PATTERN_DET:
  254. esp_handle_uart_pattern(esp_dte);
  255. break;
  256. default:
  257. ESP_LOGW(MODEM_TAG, "unknown uart event type: %d", event.type);
  258. break;
  259. }
  260. }
  261. }
  262. vTaskDelete(NULL);
  263. }
  264. /**
  265. * @brief Send command to DCE
  266. *
  267. * @param dte Modem DTE object
  268. * @param command command string
  269. * @param timeout timeout value, unit: ms
  270. * @return esp_err_t
  271. * - ESP_OK on success
  272. * - ESP_FAIL on error
  273. */
  274. static esp_err_t esp_modem_dte_send_cmd(modem_dte_t *dte, const char *command, uint32_t timeout)
  275. {
  276. esp_err_t ret = ESP_FAIL;
  277. modem_dce_t *dce = dte->dce;
  278. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  279. MODEM_CHECK(command, "command is NULL", err);
  280. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  281. /* Calculate timeout clock tick */
  282. /* Reset runtime information */
  283. dce->state = MODEM_STATE_PROCESSING;
  284. /* Send command via UART */
  285. uart_write_bytes(esp_dte->uart_port, command, strlen(command));
  286. /* Check timeout */
  287. MODEM_CHECK(xSemaphoreTake(esp_dte->process_sem, pdMS_TO_TICKS(timeout)) == pdTRUE, "process command timeout", err);
  288. ret = ESP_OK;
  289. err:
  290. dce->handle_line = NULL;
  291. return ret;
  292. }
  293. /**
  294. * @brief Send data to DCE
  295. *
  296. * @param dte Modem DTE object
  297. * @param data data buffer
  298. * @param length length of data to send
  299. * @return int actual length of data that has been send out
  300. */
  301. static int esp_modem_dte_send_data(modem_dte_t *dte, const char *data, uint32_t length)
  302. {
  303. MODEM_CHECK(data, "data is NULL", err);
  304. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  305. if (esp_dte->parent.dce->mode == MODEM_TRANSITION_MODE) {
  306. ESP_LOGD(MODEM_TAG, "Not sending data in transition mode");
  307. return -1;
  308. }
  309. return uart_write_bytes(esp_dte->uart_port, data, length);
  310. err:
  311. return -1;
  312. }
  313. /**
  314. * @brief Send data and wait for prompt from DCE
  315. *
  316. * @param dte Modem DTE object
  317. * @param data data buffer
  318. * @param length length of data to send
  319. * @param prompt pointer of specific prompt
  320. * @param timeout timeout value (unit: ms)
  321. * @return esp_err_t
  322. * ESP_OK on success
  323. * ESP_FAIL on error
  324. */
  325. static esp_err_t esp_modem_dte_send_wait(modem_dte_t *dte, const char *data, uint32_t length,
  326. const char *prompt, uint32_t timeout)
  327. {
  328. MODEM_CHECK(data, "data is NULL", err_param);
  329. MODEM_CHECK(prompt, "prompt is NULL", err_param);
  330. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  331. // We'd better disable pattern detection here for a moment in case prompt string contains the pattern character
  332. uart_disable_pattern_det_intr(esp_dte->uart_port);
  333. // uart_disable_rx_intr(esp_dte->uart_port);
  334. MODEM_CHECK(uart_write_bytes(esp_dte->uart_port, data, length) >= 0, "uart write bytes failed", err_write);
  335. uint32_t len = strlen(prompt);
  336. uint8_t *buffer = calloc(len + 1, sizeof(uint8_t));
  337. int res = uart_read_bytes(esp_dte->uart_port, buffer, len, pdMS_TO_TICKS(timeout));
  338. MODEM_CHECK(res >= len, "wait prompt [%s] timeout", err, prompt);
  339. MODEM_CHECK(!strncmp(prompt, (const char *)buffer, len), "get wrong prompt: %s", err, buffer);
  340. free(buffer);
  341. uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  342. return ESP_OK;
  343. err:
  344. free(buffer);
  345. err_write:
  346. uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  347. err_param:
  348. return ESP_FAIL;
  349. }
  350. /**
  351. * @brief Change Modem's working mode
  352. *
  353. * @param dte Modem DTE object
  354. * @param new_mode new working mode
  355. * @return esp_err_t
  356. * - ESP_OK on success
  357. * - ESP_FAIL on error
  358. */
  359. static esp_err_t esp_modem_dte_change_mode(modem_dte_t *dte, modem_mode_t new_mode)
  360. {
  361. modem_dce_t *dce = dte->dce;
  362. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  363. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  364. modem_mode_t current_mode = dce->mode;
  365. MODEM_CHECK(current_mode != new_mode, "already in mode: %d", err, new_mode);
  366. dce->mode = MODEM_TRANSITION_MODE; // mode switching will be finished in set_working_mode() on success
  367. // (or restored on failure)
  368. switch (new_mode) {
  369. case MODEM_PPP_MODE:
  370. MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err_restore_mode, new_mode);
  371. uart_disable_pattern_det_intr(esp_dte->uart_port);
  372. uart_enable_rx_intr(esp_dte->uart_port);
  373. break;
  374. case MODEM_COMMAND_MODE:
  375. MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err_restore_mode, new_mode);
  376. uart_disable_rx_intr(esp_dte->uart_port);
  377. uart_flush(esp_dte->uart_port);
  378. uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  379. uart_pattern_queue_reset(esp_dte->uart_port, esp_dte->pattern_queue_size);
  380. break;
  381. default:
  382. break;
  383. }
  384. return ESP_OK;
  385. err_restore_mode:
  386. dce->mode = current_mode;
  387. err:
  388. return ESP_FAIL;
  389. }
  390. static esp_err_t esp_modem_dte_process_cmd_done(modem_dte_t *dte)
  391. {
  392. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  393. return xSemaphoreGive(esp_dte->process_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
  394. }
  395. /**
  396. * @brief Deinitialize a Modem DTE object
  397. *
  398. * @param dte Modem DTE object
  399. * @return esp_err_t
  400. * - ESP_OK on success
  401. * - ESP_FAIL on error
  402. */
  403. static esp_err_t esp_modem_dte_deinit(modem_dte_t *dte)
  404. {
  405. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  406. /* Delete UART event task */
  407. vTaskDelete(esp_dte->uart_event_task_hdl);
  408. /* Delete semaphores */
  409. vSemaphoreDelete(esp_dte->process_sem);
  410. vSemaphoreDelete(esp_dte->exit_sem);
  411. /* Delete event loop */
  412. esp_event_loop_delete(esp_dte->event_loop_hdl);
  413. /* Uninstall UART Driver */
  414. uart_driver_delete(esp_dte->uart_port);
  415. /* Free memory */
  416. free(esp_dte->buffer);
  417. if (dte->dce) {
  418. dte->dce->dte = NULL;
  419. }
  420. free(esp_dte);
  421. return ESP_OK;
  422. }
  423. modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config)
  424. {
  425. esp_err_t res;
  426. /* malloc memory for esp_dte object */
  427. esp_modem_dte_t *esp_dte = calloc(1, sizeof(esp_modem_dte_t));
  428. MODEM_CHECK(esp_dte, "calloc esp_dte failed", err_dte_mem);
  429. /* malloc memory to storing lines from modem dce */
  430. esp_dte->line_buffer_size = config->line_buffer_size;
  431. esp_dte->buffer = calloc(1, config->line_buffer_size);
  432. MODEM_CHECK(esp_dte->buffer, "calloc line memory failed", err_line_mem);
  433. /* Set attributes */
  434. esp_dte->uart_port = config->port_num;
  435. esp_dte->parent.flow_ctrl = config->flow_control;
  436. /* Bind methods */
  437. esp_dte->parent.send_cmd = esp_modem_dte_send_cmd;
  438. esp_dte->parent.send_data = esp_modem_dte_send_data;
  439. esp_dte->parent.send_wait = esp_modem_dte_send_wait;
  440. esp_dte->parent.change_mode = esp_modem_dte_change_mode;
  441. esp_dte->parent.process_cmd_done = esp_modem_dte_process_cmd_done;
  442. esp_dte->parent.deinit = esp_modem_dte_deinit;
  443. /* Config UART */
  444. uart_config_t uart_config = {
  445. .baud_rate = config->baud_rate,
  446. .data_bits = config->data_bits,
  447. .parity = config->parity,
  448. .stop_bits = config->stop_bits,
  449. .source_clk = UART_SCLK_REF_TICK,
  450. .flow_ctrl = (config->flow_control == MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE
  451. };
  452. MODEM_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config);
  453. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  454. res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
  455. config->rts_io_num, config->cts_io_num);
  456. } else {
  457. res = uart_set_pin(esp_dte->uart_port, config->tx_io_num, config->rx_io_num,
  458. UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  459. }
  460. MODEM_CHECK(res == ESP_OK, "config uart gpio failed", err_uart_config);
  461. /* Set flow control threshold */
  462. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  463. res = uart_set_hw_flow_ctrl(esp_dte->uart_port, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
  464. } else if (config->flow_control == MODEM_FLOW_CONTROL_SW) {
  465. res = uart_set_sw_flow_ctrl(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8);
  466. }
  467. MODEM_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config);
  468. /* Install UART driver and get event queue used inside driver */
  469. res = uart_driver_install(esp_dte->uart_port, config->rx_buffer_size, config->tx_buffer_size,
  470. config->event_queue_size, &(esp_dte->event_queue), 0);
  471. MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config);
  472. res = uart_set_rx_timeout(esp_dte->uart_port, 1);
  473. MODEM_CHECK(res == ESP_OK, "set rx timeout failed", err_uart_config);
  474. /* Set pattern interrupt, used to detect the end of a line. */
  475. res = uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  476. /* Set pattern queue size */
  477. esp_dte->pattern_queue_size = config->pattern_queue_size;
  478. res |= uart_pattern_queue_reset(esp_dte->uart_port, config->pattern_queue_size);
  479. /* Starting in command mode -> explicitly disable RX interrupt */
  480. uart_disable_rx_intr(esp_dte->uart_port);
  481. MODEM_CHECK(res == ESP_OK, "config uart pattern failed", err_uart_pattern);
  482. /* Create Event loop */
  483. esp_event_loop_args_t loop_args = {
  484. .queue_size = ESP_MODEM_EVENT_QUEUE_SIZE,
  485. .task_name = NULL
  486. };
  487. MODEM_CHECK(esp_event_loop_create(&loop_args, &esp_dte->event_loop_hdl) == ESP_OK, "create event loop failed", err_eloop);
  488. /* Create semaphore */
  489. esp_dte->process_sem = xSemaphoreCreateBinary();
  490. MODEM_CHECK(esp_dte->process_sem, "create process semaphore failed", err_sem1);
  491. esp_dte->exit_sem = xSemaphoreCreateBinary();
  492. MODEM_CHECK(esp_dte->exit_sem, "create exit semaphore failed", err_sem);
  493. /* Create UART Event task */
  494. BaseType_t ret = xTaskCreate(uart_event_task_entry, //Task Entry
  495. "uart_event", //Task Name
  496. config->event_task_stack_size, //Task Stack Size(Bytes)
  497. esp_dte, //Task Parameter
  498. config->event_task_priority, //Task Priority
  499. & (esp_dte->uart_event_task_hdl) //Task Handler
  500. );
  501. MODEM_CHECK(ret == pdTRUE, "create uart event task failed", err_tsk_create);
  502. return &(esp_dte->parent);
  503. /* Error handling */
  504. err_tsk_create:
  505. vSemaphoreDelete(esp_dte->exit_sem);
  506. err_sem:
  507. vSemaphoreDelete(esp_dte->process_sem);
  508. err_sem1:
  509. esp_event_loop_delete(esp_dte->event_loop_hdl);
  510. err_eloop:
  511. uart_disable_pattern_det_intr(esp_dte->uart_port);
  512. err_uart_pattern:
  513. uart_driver_delete(esp_dte->uart_port);
  514. err_uart_config:
  515. free(esp_dte->buffer);
  516. err_line_mem:
  517. free(esp_dte);
  518. err_dte_mem:
  519. return NULL;
  520. }
  521. esp_err_t esp_modem_set_event_handler(modem_dte_t *dte, esp_event_handler_t handler, int32_t event_id, void *handler_args)
  522. {
  523. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  524. return esp_event_handler_register_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, event_id, handler, handler_args);
  525. }
  526. esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t handler)
  527. {
  528. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  529. return esp_event_handler_unregister_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_EVENT_ANY_ID, handler);
  530. }
  531. esp_err_t esp_modem_start_ppp(modem_dte_t *dte)
  532. {
  533. modem_dce_t *dce = dte->dce;
  534. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  535. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  536. /* Set PDP Context */
  537. MODEM_CHECK(dce->define_pdp_context(dce, 1, "IP", CONFIG_EXAMPLE_COMPONENT_MODEM_APN) == ESP_OK, "set MODEM APN failed", err);
  538. /* Enter PPP mode */
  539. MODEM_CHECK(dte->change_mode(dte, MODEM_PPP_MODE) == ESP_OK, "enter ppp mode failed", err);
  540. /* post PPP mode started event */
  541. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_START, NULL, 0, 0);
  542. return ESP_OK;
  543. err:
  544. return ESP_FAIL;
  545. }
  546. esp_err_t esp_modem_stop_ppp(modem_dte_t *dte)
  547. {
  548. modem_dce_t *dce = dte->dce;
  549. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  550. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  551. /* Enter command mode */
  552. MODEM_CHECK(dte->change_mode(dte, MODEM_COMMAND_MODE) == ESP_OK, "enter command mode failed", err);
  553. /* post PPP mode stopped event */
  554. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_MODEM_EVENT_PPP_STOP, NULL, 0, 0);
  555. /* Hang up */
  556. MODEM_CHECK(dce->hang_up(dce) == ESP_OK, "hang up failed", err);
  557. /* wait for the PPP mode to exit gracefully */
  558. if (xSemaphoreTake(esp_dte->exit_sem, pdMS_TO_TICKS(20000)) != pdTRUE) {
  559. ESP_LOGW(MODEM_TAG, "Failed to exit the PPP mode gracefully");
  560. }
  561. return ESP_OK;
  562. err:
  563. return ESP_FAIL;
  564. }
  565. esp_err_t esp_modem_notify_ppp_netif_closed(modem_dte_t *dte)
  566. {
  567. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  568. return xSemaphoreGive(esp_dte->exit_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
  569. }