#include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/uart.h" #include "driver/gpio.h" #include "netif/ppp/pppapi.h" #include "netif/ppp/pppos.h" #include "netif/ppp/ppp.h" #include "lwip/netif.h" #include "lwip/sockets.h" #include "lwip/inet.h" #include "esp_log.h" #include "esp_event.h" #include "esp_netif.h" // Set to 1 if you wire RTS/CTS and set modem IFC=2,2; otherwise keep 0 (TX/RX only). #define USE_HW_FLOWCTRL 0 #define MODEM_UART UART_NUM_1 #define UART_TX_PIN 37 // adjust to your wiring #define UART_RX_PIN 36 // adjust to your wiring #define UART_BAUDRATE 115200 #define MODEM_PWRKEY 1 // adjust if your PWRKEY is another GPIO #define APN "www" // Vi India APN is "www"; change if needed #define MODEM_PDP_TYPE "IP" // use "IP" or "IPV4V6" if needed static const char *TAG = "PPPOS_ONLY"; static ppp_pcb *ppp; static struct netif ppp_netif; static esp_netif_t *esp_netif_ppp; /* UART init */ static void uart_init(void) { uart_config_t cfg = { .baud_rate = UART_BAUDRATE, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, #if USE_HW_FLOWCTRL .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, .rx_flow_ctrl_thresh = 64, #else .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, #endif }; uart_driver_install(MODEM_UART, 4096, 4096, 0, NULL, 0); uart_param_config(MODEM_UART, &cfg); uart_set_pin(MODEM_UART, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); #if USE_HW_FLOWCTRL uart_set_hw_flow_ctrl(MODEM_UART, UART_HW_FLOWCTRL_CTS_RTS, 64); #endif } /* Modem power pulse */ static void modem_power_on(void) { gpio_set_direction(MODEM_PWRKEY, GPIO_MODE_OUTPUT); gpio_set_level(MODEM_PWRKEY, 1); vTaskDelay(pdMS_TO_TICKS(100)); gpio_set_level(MODEM_PWRKEY, 0); vTaskDelay(pdMS_TO_TICKS(1200)); gpio_set_level(MODEM_PWRKEY, 1); vTaskDelay(pdMS_TO_TICKS(6000)); } /* AT helpers */ static void at_cmd(const char *cmd, int delay_ms) { uart_write_bytes(MODEM_UART, cmd, strlen(cmd)); uart_write_bytes(MODEM_UART, "\r", 1); vTaskDelay(pdMS_TO_TICKS(delay_ms)); } static void at_cmd_log(const char *cmd, int collect_ms) { uint8_t buf[256]; uart_flush_input(MODEM_UART); uart_write_bytes(MODEM_UART, cmd, strlen(cmd)); uart_write_bytes(MODEM_UART, "\r", 1); TickType_t start = xTaskGetTickCount(); while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(collect_ms)) { int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS); if (len > 0) { buf[len] = 0; ESP_LOGI(TAG, "%s rsp: %s", cmd, buf); } } } /* Wait for CONNECT */ static bool wait_for_connect(int timeout_ms) { uint8_t buf[256]; TickType_t start = xTaskGetTickCount(); while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) { int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS); if (len > 0) { buf[len] = 0; ESP_LOGI(TAG, "MODEM: %s", buf); if (strstr((char*)buf, "CONNECT")) return true; if (strstr((char*)buf, "ERROR") || strstr((char*)buf, "NO CARRIER")) return false; } } ESP_LOGE(TAG, "Timed out waiting for CONNECT"); return false; } /* Wait for +CGATT: 1 */ static bool wait_for_attach(int max_checks, int interval_ms) { for (int i = 0; i < max_checks; ++i) { uint8_t buf[128]; uart_flush_input(MODEM_UART); uart_write_bytes(MODEM_UART, "AT+CGATT?\r", 10); int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, interval_ms / portTICK_PERIOD_MS); if (len > 0) { buf[len] = 0; ESP_LOGI(TAG, "AT+CGATT? rsp: %s", buf); if (strstr((char*)buf, "+CGATT: 1")) { return true; } } } return false; } /* PPP callbacks */ static u32_t ppp_output_cb(ppp_pcb *pcb, const void *data, u32_t len, void *ctx) { uart_write_bytes(MODEM_UART, (const char *)data, len); return len; } static void ppp_status_cb(ppp_pcb *pcb, int err, void *ctx) { if (err == PPPERR_NONE) ESP_LOGI(TAG, "PPP CONNECTED"); else ESP_LOGE(TAG, "PPP ERROR: %d", err); } /* PPP RX task */ static void ppp_rx_task(void *arg) { uint8_t buf[1520]; while (1) { int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf), portMAX_DELAY); if (len > 0 && ppp) { pppos_input_tcpip(ppp, buf, len); } } } /* IP events */ static void ip_event_handler(void* arg, esp_event_base_t base, int32_t id, void* data) { if (id == IP_EVENT_PPP_GOT_IP) { ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data; ESP_LOGI(TAG, "PPP GOT IPv4: " IPSTR, IP2STR(&ev->ip_info.ip)); } else if (id == IP_EVENT_GOT_IP6) { ip_event_got_ip6_t *ev6 = (ip_event_got_ip6_t *)data; ESP_LOGI(TAG, "PPP GOT IPv6: " IPV6STR, IPV62STR(ev6->ip6_info.ip)); } } /* PDP bring-up on CID1 */ static bool setup_pdp_and_connect(void) { ESP_LOGI(TAG, "Setting PDP CID1 as %s and activating", MODEM_PDP_TYPE); // Basic init and disable echo/CMUX/hwflow on modem side at_cmd("ATE0", 200); at_cmd("AT+QCFG=\"dataformat\",0,0", 300); // disable CMUX #if USE_HW_FLOWCTRL at_cmd("AT+IFC=2,2", 300); // enable RTS/CTS if wired #else at_cmd("AT+IFC=0,0", 300); // disable hw flow control to match UART cfg #endif at_cmd("AT+IPR=115200", 300); // lock baud at_cmd("AT+CFUN=1", 500); // Wait for attach if (!wait_for_attach(10, 1000)) { ESP_LOGE(TAG, "Modem not attached (+CGATT:0); aborting"); return false; } char cmd[96]; snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"%s\",\"%s\"", MODEM_PDP_TYPE, APN); at_cmd(cmd, 500); at_cmd("AT+CGACT=1,1", 800); // activate CID1 at_cmd_log("AT+CGACT?", 500); // expect +CGACT: 1,1 // Confirm IP address uart_flush_input(MODEM_UART); at_cmd_log("AT+CGPADDR=1", 500); // should show an IP; if not, fail // Dial PPP using CGDATA (preferred on Quectel) uart_flush_input(MODEM_UART); ESP_LOGI(TAG, "Dialing AT+CGDATA=\"PPP\",1 ..."); uart_write_bytes(MODEM_UART, "AT+CGDATA=\"PPP\",1\r", 18); bool got_connect = wait_for_connect(10000); if (!got_connect) { ESP_LOGE(TAG, "No CONNECT; aborting PPP start"); return false; } // Allow modem to settle into data mode and drop the CONNECT text vTaskDelay(pdMS_TO_TICKS(200)); uart_flush_input(MODEM_UART); return true; } /* Start PPP */ static void start_pppos(void) { at_cmd_log("AT+CPIN?", 1000); at_cmd_log("AT+CSQ", 1000); bool connected = setup_pdp_and_connect(); if (!connected) { ESP_LOGE(TAG, "PDP/CONNECT failed; not starting PPP"); return; } esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP(); esp_netif_ppp = esp_netif_new(&cfg); assert(esp_netif_ppp); esp_netif_attach(esp_netif_ppp, &ppp_netif); ppp = pppapi_pppos_create(&ppp_netif, ppp_output_cb, ppp_status_cb, NULL); if (!ppp) { ESP_LOGE(TAG, "pppos_create failed"); return; } pppapi_set_default(ppp); ppp_set_usepeerdns(ppp, 1); ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "", ""); // carrier-specific creds if required xTaskCreatePinnedToCore(ppp_rx_task, "ppp_rx", 6144, NULL, 6, NULL, 1); ESP_LOGI(TAG, "Calling pppapi_connect..."); pppapi_connect(ppp, 0); } /* MAIN */ void app_main(void) { ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL)); uart_init(); modem_power_on(); start_pppos(); for (;;) { vTaskDelay(pdMS_TO_TICKS(5000)); } }