upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-20 06:50:27 +0530
committerYour Name <you@example.com>2026-05-20 06:50:27 +0530
commit09c9a6425587e8f71a8089815aaae11e51bdfef9 (patch)
treee362a61124b27bd8a1593672cd3c2e1f898754be
parentc44fa437bc7b25c072c1186912f6af7646b5354b (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.c30
-rw-r--r--main/captive_portal.h2
-rw-r--r--main/tollgate_api.c29
-rw-r--r--main/tollgate_main.c44
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
19static const char *TAG = "captive_portal"; 19static const char *TAG = "captive_portal";
20static bool s_start_called = false;
21static esp_err_t s_start_result = ESP_OK;
20static httpd_handle_t s_server = NULL; 22static httpd_handle_t s_server = NULL;
21static char s_ap_ip_str[16] = "10.0.0.1"; 23static 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
708esp_err_t captive_portal_start(const char *ap_ip_str) 710esp_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
754bool captive_portal_was_start_called(void) { return s_start_called; }
755esp_err_t captive_portal_get_start_result(void) { return s_start_result; }
756
749void captive_portal_stop(void) 757void 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);
8void captive_portal_stop(void); 8void captive_portal_stop(void);
9httpd_handle_t captive_portal_get_server(void); 9httpd_handle_t captive_portal_get_server(void);
10bool captive_portal_is_setup_available(void); 10bool captive_portal_is_setup_available(void);
11bool captive_portal_was_start_called(void);
12esp_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
685extern bool s_start_services_called;
686extern bool s_start_ap_services_called;
687extern bool s_sta_got_ip;
688extern bool s_ap_started;
689
690static 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
684static const httpd_uri_t uri_discovery = { .uri = "/", .method = HTTP_GET, .handler = api_get_discovery }; 711static const httpd_uri_t uri_discovery = { .uri = "/", .method = HTTP_GET, .handler = api_get_discovery };
685static const httpd_uri_t uri_payment = { .uri = "/", .method = HTTP_POST, .handler = api_post_payment }; 712static const httpd_uri_t uri_payment = { .uri = "/", .method = HTTP_POST, .handler = api_post_payment };
686static const httpd_uri_t uri_mints = { .uri = "/mints", .method = HTTP_GET, .handler = api_get_mints }; 713static 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
733static const httpd_uri_t uri_market = { .uri = "/market", .method = HTTP_GET, .handler = api_get_market }; 760static const httpd_uri_t uri_market = { .uri = "/market", .method = HTTP_GET, .handler = api_get_market };
761static const httpd_uri_t uri_debug = { .uri = "/debug", .method = HTTP_GET, .handler = api_get_debug };
734 762
735esp_err_t tollgate_api_start(void) 763esp_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";
55static relay_selector_t s_relay_selector; 56static relay_selector_t s_relay_selector;
56static sync_manager_t s_sync_manager; 57static sync_manager_t s_sync_manager;
57 58
59volatile bool s_start_services_called = false;
60volatile bool s_start_ap_services_called = false;
61volatile bool s_sta_got_ip = false;
62volatile bool s_ap_started = false;
63
58static void start_services(void); 64static void start_services(void);
59static void stop_services(void); 65static void stop_services(void);
60static void start_ap_services(void); 66static void start_ap_services(void);
61 67
62static void start_ap_services(void) 68static 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
127static void services_start_task(void *pvParameters) 137static 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
142static esp_timer_handle_t s_services_timer;
143
134static void ip_event_handler(void *arg, esp_event_base_t event_base, 144static 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
162static 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
169static void publish_wifistr_task(void *pvParameters) 179static 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
178static void start_services(void) 188static 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) {