|
| 1 | +/* |
| 2 | + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | +#include <stdio.h> |
| 7 | +#include <string.h> |
| 8 | +#include <stdbool.h> |
| 9 | +#include "esp_at.h" |
| 10 | +#include "driver/gpio.h" |
| 11 | +#include "driver/uart.h" |
| 12 | +#include "freertos/FreeRTOS.h" |
| 13 | +#include "freertos/event_groups.h" |
| 14 | +#include "freertos/semphr.h" |
| 15 | +#include "freertos/queue.h" |
| 16 | +#include "esp_netif.h" |
| 17 | +#include "esp_netif_ppp.h" |
| 18 | +#include "esp_check.h" |
| 19 | + |
| 20 | +extern uint8_t g_at_cmd_port; |
| 21 | + |
| 22 | +static uint8_t at_test_cmd_test(uint8_t *cmd_name) |
| 23 | +{ |
| 24 | + uint8_t buffer[64] = {0}; |
| 25 | + snprintf((char *)buffer, 64, "test command: <AT%s=?> is executed\r\n", cmd_name); |
| 26 | + esp_at_port_write_data(buffer, strlen((char *)buffer)); |
| 27 | + |
| 28 | + return ESP_AT_RESULT_CODE_OK; |
| 29 | +} |
| 30 | + |
| 31 | +static uint8_t at_query_cmd_test(uint8_t *cmd_name) |
| 32 | +{ |
| 33 | + uint8_t buffer[64] = {0}; |
| 34 | + snprintf((char *)buffer, 64, "query command: <AT%s?> is executed\r\n", cmd_name); |
| 35 | + esp_at_port_write_data(buffer, strlen((char *)buffer)); |
| 36 | + |
| 37 | + return ESP_AT_RESULT_CODE_OK; |
| 38 | +} |
| 39 | + |
| 40 | +static uint8_t at_setup_cmd_test(uint8_t para_num) |
| 41 | +{ |
| 42 | + uint8_t index = 0; |
| 43 | + printf("setup command: <AT%s=%d> is executed\r\n", esp_at_get_current_cmd_name(), para_num); |
| 44 | + |
| 45 | + // get first parameter, and parse it into a digit |
| 46 | + int32_t digit = 0; |
| 47 | + if (esp_at_get_para_as_digit(index++, &digit) != ESP_AT_PARA_PARSE_RESULT_OK) { |
| 48 | + return ESP_AT_RESULT_CODE_ERROR; |
| 49 | + } |
| 50 | + printf("digit: %d\r\n", digit); |
| 51 | + |
| 52 | + // get second parameter, and parse it into a string |
| 53 | + uint8_t *str = NULL; |
| 54 | + if (esp_at_get_para_as_str(index++, &str) != ESP_AT_PARA_PARSE_RESULT_OK) { |
| 55 | + return ESP_AT_RESULT_CODE_ERROR; |
| 56 | + } |
| 57 | + printf("string: %s\r\n", str); |
| 58 | + |
| 59 | + // allocate a buffer and construct the data, then send the data to mcu via interface (uart/spi/sdio/socket) |
| 60 | + uint8_t *buffer = (uint8_t *)malloc(512); |
| 61 | + if (!buffer) { |
| 62 | + return ESP_AT_RESULT_CODE_ERROR; |
| 63 | + } |
| 64 | + int len = snprintf((char *)buffer, 512, "setup command: <AT%s=%d,\"%s\"> is executed\r\n", |
| 65 | + esp_at_get_current_cmd_name(), digit, str); |
| 66 | + esp_at_port_write_data(buffer, len); |
| 67 | + |
| 68 | + // remember to free the buffer |
| 69 | + free(buffer); |
| 70 | + |
| 71 | + return ESP_AT_RESULT_CODE_OK; |
| 72 | +} |
| 73 | + |
| 74 | +#define TAG "at_custom_cmd" |
| 75 | +static esp_netif_t *s_netif = NULL; |
| 76 | + |
| 77 | +static void on_ppp_event(void *arg, esp_event_base_t base, int32_t event_id, void *data) |
| 78 | +{ |
| 79 | + esp_netif_t **netif = data; |
| 80 | + if (base == NETIF_PPP_STATUS && event_id == NETIF_PPP_ERRORUSER) { |
| 81 | + printf("Disconnected!"); |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +static void on_ip_event(void *arg, esp_event_base_t base, int32_t event_id, void *data) |
| 86 | +{ |
| 87 | + ip_event_got_ip_t *event = (ip_event_got_ip_t *)data; |
| 88 | + esp_netif_t *netif = event->esp_netif; |
| 89 | + if (event_id == IP_EVENT_PPP_GOT_IP) { |
| 90 | + printf("Got IPv4 event: Interface \"%s(%s)\" address: " IPSTR, esp_netif_get_desc(netif), |
| 91 | + esp_netif_get_ifkey(netif), IP2STR(&event->ip_info.ip)); |
| 92 | + ESP_ERROR_CHECK(esp_netif_napt_enable(s_netif)); |
| 93 | + |
| 94 | + } else if (event_id == IP_EVENT_PPP_LOST_IP) { |
| 95 | + ESP_LOGI(TAG, "Disconnected"); |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +static SemaphoreHandle_t at_sync_sema = NULL; |
| 100 | +static void wait_data_callback(void) |
| 101 | +{ |
| 102 | + static uint8_t buffer[1024] = {0}; |
| 103 | + // xSemaphoreGive(at_sync_sema); |
| 104 | + int len = esp_at_port_read_data(buffer, sizeof(buffer) - 1); |
| 105 | + ESP_LOG_BUFFER_HEXDUMP("ppp_uart_recv", buffer, len, ESP_LOG_VERBOSE); |
| 106 | + esp_netif_receive(s_netif, buffer, len, NULL); |
| 107 | +} |
| 108 | + |
| 109 | +static esp_err_t transmit(void *h, void *buffer, size_t len) |
| 110 | +{ |
| 111 | + // struct eppp_handle *handle = h; |
| 112 | + printf("transmit: %d bytes\n", len); |
| 113 | + // ESP_LOG_BUFFER_HEXDUMP("ppp_uart_send", buffer, len, ESP_LOG_INFO); |
| 114 | + esp_at_port_write_data(buffer, len); |
| 115 | + return ESP_OK; |
| 116 | +} |
| 117 | + |
| 118 | +static uint8_t at_exe_cmd_test(uint8_t *cmd_name) |
| 119 | +{ |
| 120 | + uint8_t buffer[64] = {0}; |
| 121 | + snprintf((char *)buffer, 64, "execute command: <AT%s> is executed\r\n", cmd_name); |
| 122 | + esp_at_port_write_data(buffer, strlen((char *)buffer)); |
| 123 | + printf("YYYEEES Command <AT%s> executed successfully\r\n", cmd_name); |
| 124 | + if (!at_sync_sema) { |
| 125 | + at_sync_sema = xSemaphoreCreateBinary(); |
| 126 | + assert(at_sync_sema != NULL); |
| 127 | + esp_netif_driver_ifconfig_t driver_cfg = { |
| 128 | + .handle = (void *)1, |
| 129 | + .transmit = transmit, |
| 130 | + }; |
| 131 | + const esp_netif_driver_ifconfig_t *ppp_driver_cfg = &driver_cfg; |
| 132 | + |
| 133 | + esp_netif_inherent_config_t base_netif_cfg = ESP_NETIF_INHERENT_DEFAULT_PPP(); |
| 134 | + esp_netif_config_t netif_ppp_config = { .base = &base_netif_cfg, |
| 135 | + .driver = ppp_driver_cfg, |
| 136 | + .stack = ESP_NETIF_NETSTACK_DEFAULT_PPP |
| 137 | + }; |
| 138 | + |
| 139 | + s_netif = esp_netif_new(&netif_ppp_config); |
| 140 | + esp_netif_ppp_config_t netif_params; |
| 141 | + ESP_ERROR_CHECK(esp_netif_ppp_get_params(s_netif, &netif_params)); |
| 142 | + netif_params.ppp_our_ip4_addr.addr = ESP_IP4TOADDR(192, 168, 11, 1); |
| 143 | + netif_params.ppp_their_ip4_addr.addr = ESP_IP4TOADDR(192, 168, 11, 2); |
| 144 | + netif_params.ppp_error_event_enabled = true; |
| 145 | + ESP_ERROR_CHECK(esp_netif_ppp_set_params(s_netif, &netif_params)); |
| 146 | + if (esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event, NULL) != ESP_OK) { |
| 147 | + printf("Failed to register IP event handler"); |
| 148 | + } |
| 149 | + if (esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, on_ppp_event, NULL) != ESP_OK) { |
| 150 | + printf("Failed to register NETIF_PPP_STATUS event handler"); |
| 151 | + } |
| 152 | + |
| 153 | + |
| 154 | + } |
| 155 | + esp_at_port_write_data((uint8_t *)"CONNECT\r\n", strlen("CONNECT\r\n")); |
| 156 | + |
| 157 | + // set the callback function which will be called by AT port after receiving the input data |
| 158 | + esp_at_port_enter_specific(wait_data_callback); |
| 159 | + esp_netif_action_start(s_netif, 0, 0, 0); |
| 160 | + esp_netif_action_connected(s_netif, 0, 0, 0); |
| 161 | + |
| 162 | + // receive input data |
| 163 | + // while(xSemaphoreTake(at_sync_sema, portMAX_DELAY)) { |
| 164 | + // int len = esp_at_port_read_data(buffer, sizeof(buffer) - 1); |
| 165 | + // if (len > 0) { |
| 166 | + // buffer[len] = '\0'; // null-terminate the string |
| 167 | + // printf("Received data: %s\n", buffer); |
| 168 | + // } else { |
| 169 | + // printf("No data received or error occurred.\n"); |
| 170 | + // continue; |
| 171 | + // } |
| 172 | + // } |
| 173 | + |
| 174 | + // uart_write_bytes(g_at_cmd_port, "CONNECT\r\n", strlen("CONNECT\r\n")); |
| 175 | + while (1) { |
| 176 | + vTaskDelay(pdMS_TO_TICKS(1000)); |
| 177 | + printf("-"); |
| 178 | + } |
| 179 | + return ESP_AT_RESULT_CODE_OK; |
| 180 | +} |
| 181 | + |
| 182 | +static uint8_t at_test_cereg(uint8_t *cmd_name) |
| 183 | +{ |
| 184 | + printf("%s: AT command <AT%s> is executed\r\n", __func__, cmd_name); |
| 185 | + return ESP_AT_RESULT_CODE_OK; |
| 186 | +} |
| 187 | + |
| 188 | +static uint8_t at_query_cereg(uint8_t *cmd_name) |
| 189 | +{ |
| 190 | + printf("%s: AT command <AT%s> is executed\r\n", __func__, cmd_name); |
| 191 | + // static uint8_t buffer[] = "+CEREG: 0,1,2,3,4,5\r\n"; |
| 192 | + static uint8_t buffer[] = "+CEREG: 7,8\r\n"; |
| 193 | + esp_at_port_write_data(buffer, sizeof(buffer)); |
| 194 | + return ESP_AT_RESULT_CODE_OK; |
| 195 | +} |
| 196 | + |
| 197 | +static uint8_t at_setup_cereg(uint8_t num) |
| 198 | +{ |
| 199 | + printf("%s: AT command <AT%d> is executed\r\n", __func__, num); |
| 200 | + return ESP_AT_RESULT_CODE_OK; |
| 201 | +} |
| 202 | + |
| 203 | +static uint8_t at_exe_cereg(uint8_t *cmd_name) |
| 204 | +{ |
| 205 | + printf("%s: AT command <AT%s> is executed\r\n", __func__, cmd_name); |
| 206 | + return ESP_AT_RESULT_CODE_OK; |
| 207 | +} |
| 208 | + |
| 209 | + |
| 210 | +static const esp_at_cmd_struct at_custom_cmd[] = { |
| 211 | + {"+PPPD", at_test_cmd_test, at_query_cmd_test, at_setup_cmd_test, at_exe_cmd_test}, |
| 212 | + {"+CEREG", at_test_cereg, at_query_cereg, at_setup_cereg, at_exe_cereg}, |
| 213 | + /** |
| 214 | + * @brief You can define your own AT commands here. |
| 215 | + */ |
| 216 | +}; |
| 217 | + |
| 218 | +bool esp_at_custom_cmd_register(void) |
| 219 | +{ |
| 220 | + return esp_at_custom_cmd_array_regist(at_custom_cmd, sizeof(at_custom_cmd) / sizeof(esp_at_cmd_struct)); |
| 221 | +} |
| 222 | + |
| 223 | +ESP_AT_CMD_SET_INIT_FN(esp_at_custom_cmd_register, 1); |
0 commit comments