diff options
| author | Your Name <you@example.com> | 2026-05-20 06:50:27 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-20 06:50:27 +0530 |
| commit | 09c9a6425587e8f71a8089815aaae11e51bdfef9 (patch) | |
| tree | e362a61124b27bd8a1593672cd3c2e1f898754be | |
| parent | c44fa437bc7b25c072c1186912f6af7646b5354b (diff) | |
fix: start captive portal on AP_START, use esp_timer for service init
Root cause: xTaskCreate from within IP event handler never scheduled the
services_start_task on ESP32-S3. Replaced with esp_timer one-shot callback.
Also moved captive_portal_start() into start_ap_services() so the portal
starts immediately when the AP comes up, not waiting for STA GOT IP.
Added /debug endpoint for runtime diagnostics.
Added captive_portal diagnostic getters.
| -rw-r--r-- | main/captive_portal.c | 30 | ||||
| -rw-r--r-- | main/captive_portal.h | 2 | ||||
| -rw-r--r-- | main/tollgate_api.c | 29 | ||||
| -rw-r--r-- | main/tollgate_main.c | 44 |
4 files changed, 81 insertions, 24 deletions
diff --git a/main/captive_portal.c b/main/captive_portal.c index 6a8c716..9a0a5ff 100644 --- a/main/captive_portal.c +++ b/main/captive_portal.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <stdio.h> | 17 | #include <stdio.h> |
| 18 | 18 | ||
| 19 | static const char *TAG = "captive_portal"; | 19 | static const char *TAG = "captive_portal"; |
| 20 | static bool s_start_called = false; | ||
| 21 | static esp_err_t s_start_result = ESP_OK; | ||
| 20 | static httpd_handle_t s_server = NULL; | 22 | static httpd_handle_t s_server = NULL; |
| 21 | static char s_ap_ip_str[16] = "10.0.0.1"; | 23 | static char s_ap_ip_str[16] = "10.0.0.1"; |
| 22 | 24 | ||
| @@ -707,16 +709,18 @@ static const httpd_uri_t uri_wifi_status = { .uri = "/wifi/status", .method = HT | |||
| 707 | 709 | ||
| 708 | esp_err_t captive_portal_start(const char *ap_ip_str) | 710 | esp_err_t captive_portal_start(const char *ap_ip_str) |
| 709 | { | 711 | { |
| 712 | s_start_called = true; | ||
| 710 | if (s_server) return ESP_OK; | 713 | if (s_server) return ESP_OK; |
| 714 | if (!ap_ip_str) return ESP_ERR_INVALID_ARG; | ||
| 711 | strncpy(s_ap_ip_str, ap_ip_str, sizeof(s_ap_ip_str) - 1); | 715 | strncpy(s_ap_ip_str, ap_ip_str, sizeof(s_ap_ip_str) - 1); |
| 712 | 716 | ||
| 713 | httpd_config_t config = HTTPD_DEFAULT_CONFIG(); | 717 | httpd_config_t config = HTTPD_DEFAULT_CONFIG(); |
| 714 | config.max_uri_handlers = 20; | 718 | config.max_uri_handlers = 20; |
| 715 | 719 | ||
| 716 | esp_err_t ret = httpd_start(&s_server, &config); | 720 | s_start_result = httpd_start(&s_server, &config); |
| 717 | if (ret != ESP_OK) { | 721 | if (s_start_result != ESP_OK) { |
| 718 | ESP_LOGE(TAG, "Failed to start HTTP server: %s", esp_err_to_name(ret)); | 722 | ESP_LOGE(TAG, "Failed to start HTTP server on port %d: %s", config.server_port, esp_err_to_name(s_start_result)); |
| 719 | return ret; | 723 | return s_start_result; |
| 720 | } | 724 | } |
| 721 | 725 | ||
| 722 | httpd_register_uri_handler(s_server, &uri_portal); | 726 | httpd_register_uri_handler(s_server, &uri_portal); |
| @@ -733,19 +737,23 @@ esp_err_t captive_portal_start(const char *ap_ip_str) | |||
| 733 | httpd_register_uri_handler(s_server, &uri_connecttest); | 737 | httpd_register_uri_handler(s_server, &uri_connecttest); |
| 734 | httpd_register_uri_handler(s_server, &uri_wpad); | 738 | httpd_register_uri_handler(s_server, &uri_wpad); |
| 735 | httpd_register_uri_handler(s_server, &uri_setup); | 739 | httpd_register_uri_handler(s_server, &uri_setup); |
| 736 | ret = httpd_register_uri_handler(s_server, &uri_wifi_scan); | 740 | esp_err_t reg_ret; |
| 737 | ESP_LOGI(TAG, "Registered /wifi/scan: %s", esp_err_to_name(ret)); | 741 | reg_ret = httpd_register_uri_handler(s_server, &uri_wifi_scan); |
| 738 | ret = httpd_register_uri_handler(s_server, &uri_wifi_connect); | 742 | ESP_LOGI(TAG, "Registered /wifi/scan: %s", esp_err_to_name(reg_ret)); |
| 739 | ESP_LOGI(TAG, "Registered /wifi/connect: %s", esp_err_to_name(ret)); | 743 | reg_ret = httpd_register_uri_handler(s_server, &uri_wifi_connect); |
| 740 | ret = httpd_register_uri_handler(s_server, &uri_wifi_status); | 744 | ESP_LOGI(TAG, "Registered /wifi/connect: %s", esp_err_to_name(reg_ret)); |
| 741 | ESP_LOGI(TAG, "Registered /wifi/status: %s", esp_err_to_name(ret)); | 745 | reg_ret = httpd_register_uri_handler(s_server, &uri_wifi_status); |
| 746 | ESP_LOGI(TAG, "Registered /wifi/status: %s", esp_err_to_name(reg_ret)); | ||
| 742 | 747 | ||
| 743 | httpd_register_err_handler(s_server, HTTPD_404_NOT_FOUND, catchall_err_handler); | 748 | httpd_register_err_handler(s_server, HTTPD_404_NOT_FOUND, catchall_err_handler); |
| 744 | 749 | ||
| 745 | ESP_LOGI(TAG, "Captive portal started on port 80"); | 750 | ESP_LOGI(TAG, "Captive portal started on port 80"); |
| 746 | return ESP_OK; | 751 | return s_start_result; |
| 747 | } | 752 | } |
| 748 | 753 | ||
| 754 | bool captive_portal_was_start_called(void) { return s_start_called; } | ||
| 755 | esp_err_t captive_portal_get_start_result(void) { return s_start_result; } | ||
| 756 | |||
| 749 | void captive_portal_stop(void) | 757 | void captive_portal_stop(void) |
| 750 | { | 758 | { |
| 751 | if (s_server) { | 759 | if (s_server) { |
diff --git a/main/captive_portal.h b/main/captive_portal.h index e02a4ce..c3aa923 100644 --- a/main/captive_portal.h +++ b/main/captive_portal.h | |||
| @@ -8,5 +8,7 @@ esp_err_t captive_portal_start(const char *ap_ip_str); | |||
| 8 | void captive_portal_stop(void); | 8 | void captive_portal_stop(void); |
| 9 | httpd_handle_t captive_portal_get_server(void); | 9 | httpd_handle_t captive_portal_get_server(void); |
| 10 | bool captive_portal_is_setup_available(void); | 10 | bool captive_portal_is_setup_available(void); |
| 11 | bool captive_portal_was_start_called(void); | ||
| 12 | esp_err_t captive_portal_get_start_result(void); | ||
| 11 | 13 | ||
| 12 | #endif | 14 | #endif |
diff --git a/main/tollgate_api.c b/main/tollgate_api.c index 45cd02f..af91093 100644 --- a/main/tollgate_api.c +++ b/main/tollgate_api.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #include "config.h" | 3 | #include "config.h" |
| 4 | #include "identity.h" | 4 | #include "identity.h" |
| 5 | #include "session.h" | 5 | #include "session.h" |
| 6 | #include "captive_portal.h" | ||
| 6 | #include "firewall.h" | 7 | #include "firewall.h" |
| 7 | #include "nucula_wallet.h" | 8 | #include "nucula_wallet.h" |
| 8 | #include "mint_health.h" | 9 | #include "mint_health.h" |
| @@ -681,6 +682,32 @@ static esp_err_t api_get_mining_stats(httpd_req_t *req) | |||
| 681 | return ESP_OK; | 682 | return ESP_OK; |
| 682 | } | 683 | } |
| 683 | 684 | ||
| 685 | extern bool s_start_services_called; | ||
| 686 | extern bool s_start_ap_services_called; | ||
| 687 | extern bool s_sta_got_ip; | ||
| 688 | extern bool s_ap_started; | ||
| 689 | |||
| 690 | static esp_err_t api_get_debug(httpd_req_t *req) | ||
| 691 | { | ||
| 692 | httpd_handle_t portal = captive_portal_get_server(); | ||
| 693 | cJSON *root = cJSON_CreateObject(); | ||
| 694 | cJSON_AddBoolToObject(root, "portal_running", portal != NULL); | ||
| 695 | cJSON_AddBoolToObject(root, "portal_start_called", captive_portal_was_start_called()); | ||
| 696 | cJSON_AddNumberToObject(root, "portal_start_result", captive_portal_get_start_result()); | ||
| 697 | cJSON_AddBoolToObject(root, "start_services_called", s_start_services_called); | ||
| 698 | cJSON_AddBoolToObject(root, "start_ap_services_called", s_start_ap_services_called); | ||
| 699 | cJSON_AddBoolToObject(root, "sta_got_ip", s_sta_got_ip); | ||
| 700 | cJSON_AddBoolToObject(root, "ap_started", s_ap_started); | ||
| 701 | cJSON_AddNumberToObject(root, "free_heap", (double)esp_get_free_heap_size()); | ||
| 702 | cJSON_AddNumberToObject(root, "min_free_heap", (double)esp_get_minimum_free_heap_size()); | ||
| 703 | char *json = cJSON_PrintUnformatted(root); | ||
| 704 | httpd_resp_set_type(req, "application/json"); | ||
| 705 | httpd_resp_sendstr(req, json); | ||
| 706 | cJSON_free(json); | ||
| 707 | cJSON_Delete(root); | ||
| 708 | return ESP_OK; | ||
| 709 | } | ||
| 710 | |||
| 684 | static const httpd_uri_t uri_discovery = { .uri = "/", .method = HTTP_GET, .handler = api_get_discovery }; | 711 | static const httpd_uri_t uri_discovery = { .uri = "/", .method = HTTP_GET, .handler = api_get_discovery }; |
| 685 | static const httpd_uri_t uri_payment = { .uri = "/", .method = HTTP_POST, .handler = api_post_payment }; | 712 | static const httpd_uri_t uri_payment = { .uri = "/", .method = HTTP_POST, .handler = api_post_payment }; |
| 686 | static const httpd_uri_t uri_mints = { .uri = "/mints", .method = HTTP_GET, .handler = api_get_mints }; | 713 | static const httpd_uri_t uri_mints = { .uri = "/mints", .method = HTTP_GET, .handler = api_get_mints }; |
| @@ -731,6 +758,7 @@ static esp_err_t api_get_market(httpd_req_t *req) | |||
| 731 | } | 758 | } |
| 732 | 759 | ||
| 733 | static const httpd_uri_t uri_market = { .uri = "/market", .method = HTTP_GET, .handler = api_get_market }; | 760 | static const httpd_uri_t uri_market = { .uri = "/market", .method = HTTP_GET, .handler = api_get_market }; |
| 761 | static const httpd_uri_t uri_debug = { .uri = "/debug", .method = HTTP_GET, .handler = api_get_debug }; | ||
| 734 | 762 | ||
| 735 | esp_err_t tollgate_api_start(void) | 763 | esp_err_t tollgate_api_start(void) |
| 736 | { | 764 | { |
| @@ -750,6 +778,7 @@ esp_err_t tollgate_api_start(void) | |||
| 750 | } | 778 | } |
| 751 | 779 | ||
| 752 | httpd_register_uri_handler(s_api_server, &uri_discovery); | 780 | httpd_register_uri_handler(s_api_server, &uri_discovery); |
| 781 | httpd_register_uri_handler(s_api_server, &uri_debug); | ||
| 753 | httpd_register_uri_handler(s_api_server, &uri_payment); | 782 | httpd_register_uri_handler(s_api_server, &uri_payment); |
| 754 | httpd_register_uri_handler(s_api_server, &uri_mints); | 783 | httpd_register_uri_handler(s_api_server, &uri_mints); |
| 755 | httpd_register_uri_handler(s_api_server, &uri_usage); | 784 | httpd_register_uri_handler(s_api_server, &uri_usage); |
diff --git a/main/tollgate_main.c b/main/tollgate_main.c index 6c85b28..23b4a00 100644 --- a/main/tollgate_main.c +++ b/main/tollgate_main.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "esp_system.h" | 8 | #include "esp_system.h" |
| 9 | #include "nvs_flash.h" | 9 | #include "nvs_flash.h" |
| 10 | #include "esp_netif.h" | 10 | #include "esp_netif.h" |
| 11 | #include "esp_timer.h" | ||
| 11 | #include "lwip/netif.h" | 12 | #include "lwip/netif.h" |
| 12 | #include "lwip/dns.h" | 13 | #include "lwip/dns.h" |
| 13 | #include "esp_sntp.h" | 14 | #include "esp_sntp.h" |
| @@ -55,14 +56,22 @@ static char s_ap_ip_str[16] = "10.0.0.1"; | |||
| 55 | static relay_selector_t s_relay_selector; | 56 | static relay_selector_t s_relay_selector; |
| 56 | static sync_manager_t s_sync_manager; | 57 | static sync_manager_t s_sync_manager; |
| 57 | 58 | ||
| 59 | volatile bool s_start_services_called = false; | ||
| 60 | volatile bool s_start_ap_services_called = false; | ||
| 61 | volatile bool s_sta_got_ip = false; | ||
| 62 | volatile bool s_ap_started = false; | ||
| 63 | |||
| 58 | static void start_services(void); | 64 | static void start_services(void); |
| 59 | static void stop_services(void); | 65 | static void stop_services(void); |
| 60 | static void start_ap_services(void); | 66 | static void start_ap_services(void); |
| 61 | 67 | ||
| 62 | static void start_ap_services(void) | 68 | static void start_ap_services(void) |
| 63 | { | 69 | { |
| 70 | s_start_ap_services_called = true; | ||
| 64 | if (s_ap_services_running) return; | 71 | if (s_ap_services_running) return; |
| 65 | 72 | ||
| 73 | const tollgate_config_t *cfg = tollgate_config_get(); | ||
| 74 | captive_portal_start(cfg->ap_ip_str); | ||
| 66 | tollgate_api_start(); | 75 | tollgate_api_start(); |
| 67 | beacon_price_start(); | 76 | beacon_price_start(); |
| 68 | market_init(); | 77 | market_init(); |
| @@ -120,17 +129,18 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base, | |||
| 120 | event->mac[0], event->mac[1], event->mac[2], | 129 | event->mac[0], event->mac[1], event->mac[2], |
| 121 | event->mac[3], event->mac[4], event->mac[5]); | 130 | event->mac[3], event->mac[4], event->mac[5]); |
| 122 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_START) { | 131 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_START) { |
| 132 | s_ap_started = true; | ||
| 123 | start_ap_services(); | 133 | start_ap_services(); |
| 124 | } | 134 | } |
| 125 | } | 135 | } |
| 126 | 136 | ||
| 127 | static void services_start_task(void *pvParameters) | 137 | static void services_start_timer_cb(void *arg) |
| 128 | { | 138 | { |
| 129 | vTaskDelay(pdMS_TO_TICKS(3000)); | ||
| 130 | start_services(); | 139 | start_services(); |
| 131 | vTaskDelete(NULL); | ||
| 132 | } | 140 | } |
| 133 | 141 | ||
| 142 | static esp_timer_handle_t s_services_timer; | ||
| 143 | |||
| 134 | static void ip_event_handler(void *arg, esp_event_base_t event_base, | 144 | static void ip_event_handler(void *arg, esp_event_base_t event_base, |
| 135 | int32_t event_id, void *event_data) | 145 | int32_t event_id, void *event_data) |
| 136 | { | 146 | { |
| @@ -138,8 +148,17 @@ static void ip_event_handler(void *arg, esp_event_base_t event_base, | |||
| 138 | ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; | 148 | ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; |
| 139 | ESP_LOGI(TAG, "Got IP:" IPSTR ", GW:" IPSTR, IP2STR(&event->ip_info.ip), IP2STR(&event->ip_info.gw)); | 149 | ESP_LOGI(TAG, "Got IP:" IPSTR ", GW:" IPSTR, IP2STR(&event->ip_info.ip), IP2STR(&event->ip_info.gw)); |
| 140 | s_retry_count = 0; | 150 | s_retry_count = 0; |
| 151 | s_sta_got_ip = true; | ||
| 141 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); | 152 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); |
| 142 | 153 | ||
| 154 | const esp_timer_create_args_t timer_cfg = { | ||
| 155 | .callback = services_start_timer_cb, | ||
| 156 | .name = "svc_start", | ||
| 157 | }; | ||
| 158 | ESP_ERROR_CHECK(esp_timer_create(&timer_cfg, &s_services_timer)); | ||
| 159 | ESP_ERROR_CHECK(esp_timer_start_once(s_services_timer, 3000000)); | ||
| 160 | ESP_LOGI(TAG, "services_start_timer scheduled (3s)"); | ||
| 161 | |||
| 143 | esp_sntp_stop(); | 162 | esp_sntp_stop(); |
| 144 | esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); | 163 | esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); |
| 145 | esp_sntp_setservername(0, "pool.ntp.org"); | 164 | esp_sntp_setservername(0, "pool.ntp.org"); |
| @@ -150,8 +169,6 @@ static void ip_event_handler(void *arg, esp_event_base_t event_base, | |||
| 150 | char gw_ip_str[16]; | 169 | char gw_ip_str[16]; |
| 151 | snprintf(gw_ip_str, sizeof(gw_ip_str), IPSTR, IP2STR(&event->ip_info.gw)); | 170 | snprintf(gw_ip_str, sizeof(gw_ip_str), IPSTR, IP2STR(&event->ip_info.gw)); |
| 152 | tollgate_client_on_sta_connected(gw_ip_str); | 171 | tollgate_client_on_sta_connected(gw_ip_str); |
| 153 | |||
| 154 | xTaskCreate(services_start_task, "svc_start", 32768, NULL, 5, NULL); | ||
| 155 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) { | 172 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) { |
| 156 | ESP_LOGW(TAG, "Lost IP address"); | 173 | ESP_LOGW(TAG, "Lost IP address"); |
| 157 | xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT); | 174 | xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT); |
| @@ -159,13 +176,6 @@ static void ip_event_handler(void *arg, esp_event_base_t event_base, | |||
| 159 | } | 176 | } |
| 160 | } | 177 | } |
| 161 | 178 | ||
| 162 | static void wallet_init_task(void *pvParameters) | ||
| 163 | { | ||
| 164 | const tollgate_config_t *cfg = tollgate_config_get(); | ||
| 165 | nucula_wallet_init(cfg->mint_url); | ||
| 166 | vTaskDelete(NULL); | ||
| 167 | } | ||
| 168 | |||
| 169 | static void publish_wifistr_task(void *pvParameters) | 179 | static void publish_wifistr_task(void *pvParameters) |
| 170 | { | 180 | { |
| 171 | vTaskDelay(pdMS_TO_TICKS(5000)); | 181 | vTaskDelay(pdMS_TO_TICKS(5000)); |
| @@ -177,12 +187,15 @@ static void publish_wifistr_task(void *pvParameters) | |||
| 177 | 187 | ||
| 178 | static void start_services(void) | 188 | static void start_services(void) |
| 179 | { | 189 | { |
| 190 | ESP_LOGI(TAG, ">>> start_services() called"); | ||
| 180 | if (s_services_mutex) xSemaphoreTake(s_services_mutex, portMAX_DELAY); | 191 | if (s_services_mutex) xSemaphoreTake(s_services_mutex, portMAX_DELAY); |
| 181 | if (s_services_running) { | 192 | if (s_services_running) { |
| 182 | if (s_services_mutex) xSemaphoreGive(s_services_mutex); | 193 | if (s_services_mutex) xSemaphoreGive(s_services_mutex); |
| 183 | return; | 194 | return; |
| 184 | } | 195 | } |
| 185 | 196 | ||
| 197 | s_start_services_called = true; | ||
| 198 | |||
| 186 | esp_netif_get_ip_info(s_ap_netif, &(esp_netif_ip_info_t){0}); | 199 | esp_netif_get_ip_info(s_ap_netif, &(esp_netif_ip_info_t){0}); |
| 187 | esp_netif_ip_info_t ap_ip_info; | 200 | esp_netif_ip_info_t ap_ip_info; |
| 188 | esp_netif_get_ip_info(s_ap_netif, &ap_ip_info); | 201 | esp_netif_get_ip_info(s_ap_netif, &ap_ip_info); |
| @@ -412,7 +425,12 @@ void app_main(void) | |||
| 412 | 425 | ||
| 413 | if (tollgate_config_get_wifi(&(wifi_config_t){0}) != ESP_OK) { | 426 | if (tollgate_config_get_wifi(&(wifi_config_t){0}) != ESP_OK) { |
| 414 | ESP_LOGI(TAG, "No STA network configured, starting services immediately"); | 427 | ESP_LOGI(TAG, "No STA network configured, starting services immediately"); |
| 415 | xTaskCreate(services_start_task, "svc_start", 32768, NULL, 5, NULL); | 428 | const esp_timer_create_args_t timer_cfg = { |
| 429 | .callback = services_start_timer_cb, | ||
| 430 | .name = "svc_start_fallback", | ||
| 431 | }; | ||
| 432 | ESP_ERROR_CHECK(esp_timer_create(&timer_cfg, &s_services_timer)); | ||
| 433 | ESP_ERROR_CHECK(esp_timer_start_once(s_services_timer, 3000000)); | ||
| 416 | } | 434 | } |
| 417 | 435 | ||
| 418 | while (1) { | 436 | while (1) { |