esp_modem.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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 "netif/ppp/pppapi.h"
  21. #include "netif/ppp/pppos.h"
  22. #include "lwip/dns.h"
  23. #include "tcpip_adapter.h"
  24. #include "esp_modem.h"
  25. #include "esp_log.h"
  26. #include "sdkconfig.h"
  27. #define ESP_MODEM_LINE_BUFFER_SIZE (CONFIG_EXAMPLE_UART_RX_BUFFER_SIZE / 2)
  28. #define ESP_MODEM_EVENT_QUEUE_SIZE (16)
  29. #define MIN_PATTERN_INTERVAL (10000)
  30. #define MIN_POST_IDLE (10)
  31. #define MIN_PRE_IDLE (10)
  32. /**
  33. * @brief Macro defined for error checking
  34. *
  35. */
  36. static const char *MODEM_TAG = "esp-modem";
  37. #define MODEM_CHECK(a, str, goto_tag, ...) \
  38. do \
  39. { \
  40. if (!(a)) \
  41. { \
  42. ESP_LOGE(MODEM_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
  43. goto goto_tag; \
  44. } \
  45. } while (0)
  46. ESP_EVENT_DEFINE_BASE(ESP_MODEM_EVENT);
  47. /**
  48. * @brief ESP32 Modem DTE
  49. *
  50. */
  51. typedef struct {
  52. uart_port_t uart_port; /*!< UART port */
  53. uint8_t *buffer; /*!< Internal buffer to store response lines/data from DCE */
  54. QueueHandle_t event_queue; /*!< UART event queue handle */
  55. esp_event_loop_handle_t event_loop_hdl; /*!< Event loop handle */
  56. TaskHandle_t uart_event_task_hdl; /*!< UART event task handle */
  57. SemaphoreHandle_t process_sem; /*!< Semaphore used for indicating processing status */
  58. struct netif pppif; /*!< PPP network interface */
  59. ppp_pcb *ppp; /*!< PPP control block */
  60. modem_dte_t parent; /*!< DTE interface that should extend */
  61. } esp_modem_dte_t;
  62. /**
  63. * @brief Handle one line in DTE
  64. *
  65. * @param esp_dte ESP modem DTE object
  66. * @return esp_err_t
  67. * - ESP_OK on success
  68. * - ESP_FAIL on error
  69. */
  70. static esp_err_t esp_dte_handle_line(esp_modem_dte_t *esp_dte)
  71. {
  72. modem_dce_t *dce = esp_dte->parent.dce;
  73. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  74. const char *line = (const char *)(esp_dte->buffer);
  75. /* Skip pure "\r\n" lines */
  76. if (strlen(line) > 2) {
  77. MODEM_CHECK(dce->handle_line, "no handler for line", err_handle);
  78. MODEM_CHECK(dce->handle_line(dce, line) == ESP_OK, "handle line failed", err_handle);
  79. }
  80. return ESP_OK;
  81. err_handle:
  82. /* Send MODEM_EVENT_UNKNOWN signal to event loop */
  83. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, MODEM_EVENT_UNKNOWN,
  84. (void *)line, strlen(line) + 1, pdMS_TO_TICKS(100));
  85. err:
  86. return ESP_FAIL;
  87. }
  88. /**
  89. * @brief Handle when a pattern has been detected by UART
  90. *
  91. * @param esp_dte ESP32 Modem DTE object
  92. */
  93. static void esp_handle_uart_pattern(esp_modem_dte_t *esp_dte)
  94. {
  95. int pos = uart_pattern_pop_pos(esp_dte->uart_port);
  96. int read_len = 0;
  97. if (pos != -1) {
  98. if (pos < ESP_MODEM_LINE_BUFFER_SIZE - 1) {
  99. /* read one line(include '\n') */
  100. read_len = pos + 1;
  101. } else {
  102. ESP_LOGW(MODEM_TAG, "ESP Modem Line buffer too small");
  103. read_len = ESP_MODEM_LINE_BUFFER_SIZE - 1;
  104. }
  105. read_len = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, read_len, pdMS_TO_TICKS(100));
  106. if (read_len) {
  107. /* make sure the line is a standard string */
  108. esp_dte->buffer[read_len] = '\0';
  109. /* Send new line to handle */
  110. esp_dte_handle_line(esp_dte);
  111. } else {
  112. ESP_LOGE(MODEM_TAG, "uart read bytes failed");
  113. }
  114. } else {
  115. ESP_LOGW(MODEM_TAG, "Pattern Queue Size too small");
  116. uart_flush(esp_dte->uart_port);
  117. }
  118. }
  119. /**
  120. * @brief Handle when new data received by UART
  121. *
  122. * @param esp_dte ESP32 Modem DTE object
  123. */
  124. static void esp_handle_uart_data(esp_modem_dte_t *esp_dte)
  125. {
  126. size_t length = 0;
  127. uart_get_buffered_data_len(esp_dte->uart_port, &length);
  128. length = MIN(ESP_MODEM_LINE_BUFFER_SIZE, length);
  129. length = uart_read_bytes(esp_dte->uart_port, esp_dte->buffer, length, portMAX_DELAY);
  130. /* pass input data to the lwIP core thread */
  131. if (length) {
  132. pppos_input_tcpip(esp_dte->ppp, esp_dte->buffer, length);
  133. }
  134. }
  135. /**
  136. * @brief UART Event Task Entry
  137. *
  138. * @param param task parameter
  139. */
  140. static void uart_event_task_entry(void *param)
  141. {
  142. esp_modem_dte_t *esp_dte = (esp_modem_dte_t *)param;
  143. uart_event_t event;
  144. while (1) {
  145. if (xQueueReceive(esp_dte->event_queue, &event, pdMS_TO_TICKS(100))) {
  146. switch (event.type) {
  147. case UART_DATA:
  148. esp_handle_uart_data(esp_dte);
  149. break;
  150. case UART_FIFO_OVF:
  151. ESP_LOGW(MODEM_TAG, "HW FIFO Overflow");
  152. uart_flush_input(esp_dte->uart_port);
  153. xQueueReset(esp_dte->event_queue);
  154. break;
  155. case UART_BUFFER_FULL:
  156. ESP_LOGW(MODEM_TAG, "Ring Buffer Full");
  157. uart_flush_input(esp_dte->uart_port);
  158. xQueueReset(esp_dte->event_queue);
  159. break;
  160. case UART_BREAK:
  161. ESP_LOGW(MODEM_TAG, "Rx Break");
  162. break;
  163. case UART_PARITY_ERR:
  164. ESP_LOGE(MODEM_TAG, "Parity Error");
  165. break;
  166. case UART_FRAME_ERR:
  167. ESP_LOGE(MODEM_TAG, "Frame Error");
  168. break;
  169. case UART_PATTERN_DET:
  170. esp_handle_uart_pattern(esp_dte);
  171. break;
  172. default:
  173. ESP_LOGW(MODEM_TAG, "unknown uart event type: %d", event.type);
  174. break;
  175. }
  176. }
  177. /* Drive the event loop */
  178. esp_event_loop_run(esp_dte->event_loop_hdl, pdMS_TO_TICKS(50));
  179. }
  180. vTaskDelete(NULL);
  181. }
  182. /**
  183. * @brief Send command to DCE
  184. *
  185. * @param dte Modem DTE object
  186. * @param command command string
  187. * @param timeout timeout value, unit: ms
  188. * @return esp_err_t
  189. * - ESP_OK on success
  190. * - ESP_FAIL on error
  191. */
  192. static esp_err_t esp_modem_dte_send_cmd(modem_dte_t *dte, const char *command, uint32_t timeout)
  193. {
  194. esp_err_t ret = ESP_FAIL;
  195. modem_dce_t *dce = dte->dce;
  196. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  197. MODEM_CHECK(command, "command is NULL", err);
  198. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  199. /* Calculate timeout clock tick */
  200. /* Reset runtime information */
  201. dce->state = MODEM_STATE_PROCESSING;
  202. /* Send command via UART */
  203. uart_write_bytes(esp_dte->uart_port, command, strlen(command));
  204. /* Check timeout */
  205. MODEM_CHECK(xSemaphoreTake(esp_dte->process_sem, pdMS_TO_TICKS(timeout)) == pdTRUE, "process command timeout", err);
  206. ret = ESP_OK;
  207. err:
  208. dce->handle_line = NULL;
  209. return ret;
  210. }
  211. /**
  212. * @brief Send data to DCE
  213. *
  214. * @param dte Modem DTE object
  215. * @param data data buffer
  216. * @param length length of data to send
  217. * @return int actual length of data that has been send out
  218. */
  219. static int esp_modem_dte_send_data(modem_dte_t *dte, const char *data, uint32_t length)
  220. {
  221. MODEM_CHECK(data, "data is NULL", err);
  222. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  223. return uart_write_bytes(esp_dte->uart_port, data, length);
  224. err:
  225. return -1;
  226. }
  227. /**
  228. * @brief Send data and wait for prompt from DCE
  229. *
  230. * @param dte Modem DTE object
  231. * @param data data buffer
  232. * @param length length of data to send
  233. * @param prompt pointer of specific prompt
  234. * @param timeout timeout value (unit: ms)
  235. * @return esp_err_t
  236. * ESP_OK on success
  237. * ESP_FAIL on error
  238. */
  239. static esp_err_t esp_modem_dte_send_wait(modem_dte_t *dte, const char *data, uint32_t length,
  240. const char *prompt, uint32_t timeout)
  241. {
  242. MODEM_CHECK(data, "data is NULL", err_param);
  243. MODEM_CHECK(prompt, "prompt is NULL", err_param);
  244. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  245. // We'd better disable pattern detection here for a moment in case prompt string contains the pattern character
  246. uart_disable_pattern_det_intr(esp_dte->uart_port);
  247. // uart_disable_rx_intr(esp_dte->uart_port);
  248. MODEM_CHECK(uart_write_bytes(esp_dte->uart_port, data, length) >= 0, "uart write bytes failed", err_write);
  249. uint32_t len = strlen(prompt);
  250. uint8_t *buffer = calloc(len + 1, sizeof(uint8_t));
  251. int res = uart_read_bytes(esp_dte->uart_port, buffer, len, pdMS_TO_TICKS(timeout));
  252. MODEM_CHECK(res >= len, "wait prompt [%s] timeout", err, prompt);
  253. MODEM_CHECK(!strncmp(prompt, (const char *)buffer, len), "get wrong prompt: %s", err, buffer);
  254. free(buffer);
  255. uart_enable_pattern_det_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  256. return ESP_OK;
  257. err:
  258. free(buffer);
  259. err_write:
  260. uart_enable_pattern_det_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  261. err_param:
  262. return ESP_FAIL;
  263. }
  264. /**
  265. * @brief Change Modem's working mode
  266. *
  267. * @param dte Modem DTE object
  268. * @param new_mode new working mode
  269. * @return esp_err_t
  270. * - ESP_OK on success
  271. * - ESP_FAIL on error
  272. */
  273. static esp_err_t esp_modem_dte_change_mode(modem_dte_t *dte, modem_mode_t new_mode)
  274. {
  275. modem_dce_t *dce = dte->dce;
  276. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  277. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  278. MODEM_CHECK(dce->mode != new_mode, "already in mode: %d", err, new_mode);
  279. switch (new_mode) {
  280. case MODEM_PPP_MODE:
  281. MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err, new_mode);
  282. uart_disable_pattern_det_intr(esp_dte->uart_port);
  283. uart_enable_rx_intr(esp_dte->uart_port);
  284. break;
  285. case MODEM_COMMAND_MODE:
  286. uart_disable_rx_intr(esp_dte->uart_port);
  287. uart_flush(esp_dte->uart_port);
  288. uart_enable_pattern_det_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  289. uart_pattern_queue_reset(esp_dte->uart_port, CONFIG_EXAMPLE_UART_PATTERN_QUEUE_SIZE);
  290. MODEM_CHECK(dce->set_working_mode(dce, new_mode) == ESP_OK, "set new working mode:%d failed", err, new_mode);
  291. break;
  292. default:
  293. break;
  294. }
  295. return ESP_OK;
  296. err:
  297. return ESP_FAIL;
  298. }
  299. static esp_err_t esp_modem_dte_process_cmd_done(modem_dte_t *dte)
  300. {
  301. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  302. return xSemaphoreGive(esp_dte->process_sem) == pdTRUE ? ESP_OK : ESP_FAIL;
  303. }
  304. /**
  305. * @brief Deinitialize a Modem DTE object
  306. *
  307. * @param dte Modem DTE object
  308. * @return esp_err_t
  309. * - ESP_OK on success
  310. * - ESP_FAIL on error
  311. */
  312. static esp_err_t esp_modem_dte_deinit(modem_dte_t *dte)
  313. {
  314. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  315. /* Delete UART event task */
  316. vTaskDelete(esp_dte->uart_event_task_hdl);
  317. /* Delete semaphore */
  318. vSemaphoreDelete(esp_dte->process_sem);
  319. /* Delete event loop */
  320. esp_event_loop_delete(esp_dte->event_loop_hdl);
  321. /* Uninstall UART Driver */
  322. uart_driver_delete(esp_dte->uart_port);
  323. /* Free memory */
  324. free(esp_dte->buffer);
  325. if (dte->dce) {
  326. dte->dce->dte = NULL;
  327. }
  328. free(esp_dte);
  329. return ESP_OK;
  330. }
  331. modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config)
  332. {
  333. esp_err_t res;
  334. /* malloc memory for esp_dte object */
  335. esp_modem_dte_t *esp_dte = calloc(1, sizeof(esp_modem_dte_t));
  336. MODEM_CHECK(esp_dte, "calloc esp_dte failed", err_dte_mem);
  337. /* malloc memory to storing lines from modem dce */
  338. esp_dte->buffer = calloc(1, ESP_MODEM_LINE_BUFFER_SIZE);
  339. MODEM_CHECK(esp_dte->buffer, "calloc line memory failed", err_line_mem);
  340. /* Set attributes */
  341. esp_dte->uart_port = config->port_num;
  342. esp_dte->parent.flow_ctrl = config->flow_control;
  343. /* Bind methods */
  344. esp_dte->parent.send_cmd = esp_modem_dte_send_cmd;
  345. esp_dte->parent.send_data = esp_modem_dte_send_data;
  346. esp_dte->parent.send_wait = esp_modem_dte_send_wait;
  347. esp_dte->parent.change_mode = esp_modem_dte_change_mode;
  348. esp_dte->parent.process_cmd_done = esp_modem_dte_process_cmd_done;
  349. esp_dte->parent.deinit = esp_modem_dte_deinit;
  350. /* Config UART */
  351. uart_config_t uart_config = {
  352. .baud_rate = config->baud_rate,
  353. .data_bits = config->data_bits,
  354. .parity = config->parity,
  355. .stop_bits = config->stop_bits,
  356. .flow_ctrl = (config->flow_control == MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE
  357. };
  358. MODEM_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config);
  359. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  360. res = uart_set_pin(esp_dte->uart_port, CONFIG_EXAMPLE_UART_MODEM_TX_PIN, CONFIG_EXAMPLE_UART_MODEM_RX_PIN,
  361. CONFIG_EXAMPLE_UART_MODEM_RTS_PIN, CONFIG_EXAMPLE_UART_MODEM_CTS_PIN);
  362. } else {
  363. res = uart_set_pin(esp_dte->uart_port, CONFIG_EXAMPLE_UART_MODEM_TX_PIN, CONFIG_EXAMPLE_UART_MODEM_RX_PIN,
  364. UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  365. }
  366. MODEM_CHECK(res == ESP_OK, "config uart gpio failed", err_uart_config);
  367. /* Set flow control threshold */
  368. if (config->flow_control == MODEM_FLOW_CONTROL_HW) {
  369. res = uart_set_hw_flow_ctrl(esp_dte->uart_port, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
  370. } else if (config->flow_control == MODEM_FLOW_CONTROL_SW) {
  371. res = uart_set_sw_flow_ctrl(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8);
  372. }
  373. MODEM_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config);
  374. /* Install UART driver and get event queue used inside driver */
  375. res = uart_driver_install(esp_dte->uart_port, CONFIG_EXAMPLE_UART_RX_BUFFER_SIZE, CONFIG_EXAMPLE_UART_TX_BUFFER_SIZE,
  376. CONFIG_EXAMPLE_UART_EVENT_QUEUE_SIZE, &(esp_dte->event_queue), 0);
  377. MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config);
  378. /* Set pattern interrupt, used to detect the end of a line. */
  379. res = uart_enable_pattern_det_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE);
  380. /* Set pattern queue size */
  381. res |= uart_pattern_queue_reset(esp_dte->uart_port, CONFIG_EXAMPLE_UART_PATTERN_QUEUE_SIZE);
  382. MODEM_CHECK(res == ESP_OK, "config uart pattern failed", err_uart_pattern);
  383. /* Create Event loop */
  384. esp_event_loop_args_t loop_args = {
  385. .queue_size = ESP_MODEM_EVENT_QUEUE_SIZE,
  386. .task_name = NULL
  387. };
  388. MODEM_CHECK(esp_event_loop_create(&loop_args, &esp_dte->event_loop_hdl) == ESP_OK, "create event loop failed", err_eloop);
  389. /* Create semaphore */
  390. esp_dte->process_sem = xSemaphoreCreateBinary();
  391. MODEM_CHECK(esp_dte->process_sem, "create process semaphore failed", err_sem);
  392. /* Create UART Event task */
  393. BaseType_t ret = xTaskCreate(uart_event_task_entry, //Task Entry
  394. "uart_event", //Task Name
  395. CONFIG_EXAMPLE_UART_EVENT_TASK_STACK_SIZE, //Task Stack Size(Bytes)
  396. esp_dte, //Task Parameter
  397. CONFIG_EXAMPLE_UART_EVENT_TASK_PRIORITY, //Task Priority
  398. & (esp_dte->uart_event_task_hdl) //Task Handler
  399. );
  400. MODEM_CHECK(ret == pdTRUE, "create uart event task failed", err_tsk_create);
  401. return &(esp_dte->parent);
  402. /* Error handling */
  403. err_tsk_create:
  404. vSemaphoreDelete(esp_dte->process_sem);
  405. err_sem:
  406. esp_event_loop_delete(esp_dte->event_loop_hdl);
  407. err_eloop:
  408. uart_disable_pattern_det_intr(esp_dte->uart_port);
  409. err_uart_pattern:
  410. uart_driver_delete(esp_dte->uart_port);
  411. err_uart_config:
  412. free(esp_dte->buffer);
  413. err_line_mem:
  414. free(esp_dte);
  415. err_dte_mem:
  416. return NULL;
  417. }
  418. esp_err_t esp_modem_add_event_handler(modem_dte_t *dte, esp_event_handler_t handler, void *handler_args)
  419. {
  420. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  421. return esp_event_handler_register_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_EVENT_ANY_ID, handler, handler_args);
  422. }
  423. esp_err_t esp_modem_remove_event_handler(modem_dte_t *dte, esp_event_handler_t handler)
  424. {
  425. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  426. return esp_event_handler_unregister_with(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, ESP_EVENT_ANY_ID, handler);
  427. }
  428. /**
  429. * @brief PPP status callback which is called on PPP status change (up, down, …) by lwIP core thread
  430. *
  431. * @param pcb PPP control block
  432. * @param err_code Error code
  433. * @param ctx Context of callback
  434. */
  435. static void on_ppp_status_changed(ppp_pcb *pcb, int err_code, void *ctx)
  436. {
  437. struct netif *pppif = ppp_netif(pcb);
  438. modem_dte_t *dte = (modem_dte_t *)(ctx);
  439. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  440. ppp_client_ip_info_t ipinfo = {0};
  441. switch (err_code) {
  442. case PPPERR_NONE: /* Connected */
  443. ipinfo.ip = pppif->ip_addr.u_addr.ip4;
  444. ipinfo.gw = pppif->gw.u_addr.ip4;
  445. ipinfo.netmask = pppif->netmask.u_addr.ip4;
  446. ipinfo.ns1 = dns_getserver(0).u_addr.ip4;
  447. ipinfo.ns2 = dns_getserver(1).u_addr.ip4;
  448. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, MODEM_EVENT_PPP_CONNECT, &ipinfo, sizeof(ipinfo), 0);
  449. break;
  450. case PPPERR_PARAM:
  451. ESP_LOGE(MODEM_TAG, "Invalid parameter");
  452. break;
  453. case PPPERR_OPEN:
  454. ESP_LOGE(MODEM_TAG, "Unable to open PPP session");
  455. break;
  456. case PPPERR_DEVICE:
  457. ESP_LOGE(MODEM_TAG, "Invalid I/O device for PPP");
  458. break;
  459. case PPPERR_ALLOC:
  460. ESP_LOGE(MODEM_TAG, "Unable to allocate resources");
  461. break;
  462. case PPPERR_USER: /* User interrupt */
  463. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, MODEM_EVENT_PPP_STOP, NULL, 0, 0);
  464. /* Free the PPP control block */
  465. pppapi_free(esp_dte->ppp);
  466. break;
  467. case PPPERR_CONNECT: /* Connection lost */
  468. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, MODEM_EVENT_PPP_DISCONNECT, NULL, 0, 0);
  469. break;
  470. case PPPERR_AUTHFAIL:
  471. ESP_LOGE(MODEM_TAG, "Failed authentication challenge");
  472. break;
  473. case PPPERR_PROTOCOL:
  474. ESP_LOGE(MODEM_TAG, "Failed to meet protocol");
  475. break;
  476. case PPPERR_PEERDEAD:
  477. ESP_LOGE(MODEM_TAG, "Connection timeout");
  478. break;
  479. case PPPERR_IDLETIMEOUT:
  480. ESP_LOGE(MODEM_TAG, "Idle Timeout");
  481. break;
  482. case PPPERR_CONNECTTIME:
  483. ESP_LOGE(MODEM_TAG, "Max connect time reached");
  484. break;
  485. case PPPERR_LOOPBACK:
  486. ESP_LOGE(MODEM_TAG, "Loopback detected");
  487. break;
  488. default:
  489. ESP_LOGE(MODEM_TAG, "Unknown error code %d", err_code);
  490. break;
  491. }
  492. }
  493. #if PPP_NOTIFY_PHASE
  494. /**
  495. * @brief Notify phase callback which is called on each PPP internal state change
  496. *
  497. * @param pcb PPP control block
  498. * @param phase Phase ID
  499. * @param ctx Context of callback
  500. */
  501. static void on_ppp_notify_phase(ppp_pcb *pcb, u8_t phase, void *ctx)
  502. {
  503. switch (phase) {
  504. case PPP_PHASE_DEAD:
  505. ESP_LOGD(MODEM_TAG, "Phase Dead");
  506. break;
  507. case PPP_PHASE_INITIALIZE:
  508. ESP_LOGD(MODEM_TAG, "Phase Start");
  509. break;
  510. case PPP_PHASE_ESTABLISH:
  511. ESP_LOGD(MODEM_TAG, "Phase Establish");
  512. break;
  513. case PPP_PHASE_AUTHENTICATE:
  514. ESP_LOGD(MODEM_TAG, "Phase Authenticate");
  515. break;
  516. case PPP_PHASE_NETWORK:
  517. ESP_LOGD(MODEM_TAG, "Phase Network");
  518. break;
  519. case PPP_PHASE_RUNNING:
  520. ESP_LOGD(MODEM_TAG, "Phase Running");
  521. break;
  522. case PPP_PHASE_TERMINATE:
  523. ESP_LOGD(MODEM_TAG, "Phase Terminate");
  524. break;
  525. case PPP_PHASE_DISCONNECT:
  526. ESP_LOGD(MODEM_TAG, "Phase Disconnect");
  527. break;
  528. default:
  529. ESP_LOGW(MODEM_TAG, "Phase Unknown: %d", phase);
  530. break;
  531. }
  532. }
  533. #endif
  534. /**
  535. * @brief PPPoS serial output callback
  536. *
  537. * @param pcb PPP control block
  538. * @param data Buffer to write to serial port
  539. * @param len Length of the data buffer
  540. * @param ctx Context of callback
  541. * @return uint32_t Length of data successfully sent
  542. */
  543. static uint32_t pppos_low_level_output(ppp_pcb *pcb, uint8_t *data, uint32_t len, void *ctx)
  544. {
  545. modem_dte_t *dte = (modem_dte_t *)ctx;
  546. return dte->send_data(dte, (const char *)data, len);
  547. }
  548. esp_err_t esp_modem_setup_ppp(modem_dte_t *dte)
  549. {
  550. modem_dce_t *dce = dte->dce;
  551. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  552. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  553. /* Set PDP Context */
  554. MODEM_CHECK(dce->define_pdp_context(dce, 1, "IP", CONFIG_EXAMPLE_MODEM_APN) == ESP_OK, "set MODEM APN failed", err);
  555. /* Enter PPP mode */
  556. MODEM_CHECK(dte->change_mode(dte, MODEM_PPP_MODE) == ESP_OK, "enter ppp mode failed", err);
  557. /* Create PPPoS interface */
  558. esp_dte->ppp = pppapi_pppos_create(&(esp_dte->pppif), pppos_low_level_output, on_ppp_status_changed, dte);
  559. MODEM_CHECK(esp_dte->ppp, "create pppos interface failed", err);
  560. #if PPP_NOTIFY_PHASE
  561. ppp_set_notify_phase_callback(esp_dte->ppp, on_ppp_notify_phase);
  562. #endif
  563. /* Initiate PPP client connection */
  564. /* Set default route */
  565. MODEM_CHECK(pppapi_set_default(esp_dte->ppp) == ERR_OK, "set default route failed", err);
  566. /* Ask the peer for up to 2 DNS server addresses */
  567. ppp_set_usepeerdns(esp_dte->ppp, 1);
  568. /* Auth configuration */
  569. #if PAP_SUPPORT
  570. pppapi_set_auth(esp_dte->ppp, PPPAUTHTYPE_PAP, CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME, CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD);
  571. #elif CHAP_SUPPORT
  572. pppapi_set_auth(esp_dte->ppp, PPPAUTHTYPE_CHAP, CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME, CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD);
  573. #else
  574. #error "Unsupported AUTH Negotiation"
  575. #endif
  576. /* Initiate PPP negotiation, without waiting */
  577. MODEM_CHECK(pppapi_connect(esp_dte->ppp, 0) == ERR_OK, "initiate ppp negotiation failed", err);
  578. esp_event_post_to(esp_dte->event_loop_hdl, ESP_MODEM_EVENT, MODEM_EVENT_PPP_START, NULL, 0, 0);
  579. return ESP_OK;
  580. err:
  581. return ESP_FAIL;
  582. }
  583. esp_err_t esp_modem_exit_ppp(modem_dte_t *dte)
  584. {
  585. modem_dce_t *dce = dte->dce;
  586. MODEM_CHECK(dce, "DTE has not yet bind with DCE", err);
  587. esp_modem_dte_t *esp_dte = __containerof(dte, esp_modem_dte_t, parent);
  588. /* Shutdown of PPP protocols */
  589. MODEM_CHECK(pppapi_close(esp_dte->ppp, 0) == ERR_OK, "close ppp connection failed", err);
  590. /* Enter command mode */
  591. MODEM_CHECK(dte->change_mode(dte, MODEM_COMMAND_MODE) == ESP_OK, "enter command mode failed", err);
  592. /* Hang up */
  593. MODEM_CHECK(dce->hang_up(dce) == ESP_OK, "hang up failed", err);
  594. return ESP_OK;
  595. err:
  596. return ESP_FAIL;
  597. }