fix: Verbindungs-Timeout im WLAN-Zustandsautomaten

This commit is contained in:
Michael Sauer
2026-09-11 22:42:49 +02:00
parent 2bdeaed98d
commit 2f7cadaeee
3 changed files with 38 additions and 0 deletions
+15
View File
@@ -46,6 +46,8 @@ static void fail_test(nl_wifi_sm_t *sm, nl_wifi_error_t err, uint32_t now, nl_wi
sm->backoff = NL_WIFI_BACKOFF_MIN_MS; sm->backoff = NL_WIFI_BACKOFF_MIN_MS;
sm->retry_armed = false; sm->retry_armed = false;
a->connect = true; /* old credentials */ a->connect = true; /* old credentials */
sm->awaiting = true;
sm->connect_at = now;
} else { } else {
sm->state = NL_WIFI_ST_AP_ONBOARDING; sm->state = NL_WIFI_ST_AP_ONBOARDING;
} }
@@ -60,6 +62,8 @@ nl_wifi_actions_t nl_wifi_sm_start(nl_wifi_sm_t *sm, bool have_creds, uint32_t n
if (have_creds) { if (have_creds) {
begin_connecting(sm, now); begin_connecting(sm, now);
a.connect = true; a.connect = true;
sm->awaiting = true;
sm->connect_at = now;
} else { } else {
sm->state = NL_WIFI_ST_AP_ONBOARDING; sm->state = NL_WIFI_ST_AP_ONBOARDING;
sm->ap_up = true; sm->ap_up = true;
@@ -77,6 +81,7 @@ nl_wifi_actions_t nl_wifi_sm_event(nl_wifi_sm_t *sm, nl_wifi_event_t ev, nl_wifi
switch (sm->state) { switch (sm->state) {
case NL_WIFI_ST_STA_CONNECTING: case NL_WIFI_ST_STA_CONNECTING:
case NL_WIFI_ST_APSTA_FALLBACK: case NL_WIFI_ST_APSTA_FALLBACK:
sm->awaiting = false;
if (ev == NL_WIFI_EV_CONNECTED) { if (ev == NL_WIFI_EV_CONNECTED) {
sm->state = NL_WIFI_ST_STA_CONNECTED; sm->state = NL_WIFI_ST_STA_CONNECTED;
sm->retry_armed = false; sm->retry_armed = false;
@@ -131,10 +136,20 @@ nl_wifi_actions_t nl_wifi_sm_tick(nl_wifi_sm_t *sm, uint32_t now)
a.start_ap = true; a.start_ap = true;
} }
} }
if ((sm->state == NL_WIFI_ST_STA_CONNECTING || sm->state == NL_WIFI_ST_APSTA_FALLBACK) && sm->awaiting && !sm->retry_armed &&
due(now, sm->connect_at + NL_WIFI_CONNECT_TIMEOUT_MS)) {
sm->awaiting = false;
uint32_t timeout_at = sm->connect_at + NL_WIFI_CONNECT_TIMEOUT_MS;
sm->retry_armed = true;
sm->retry_at = timeout_at + sm->backoff;
sm->backoff = sm->backoff * 2u > NL_WIFI_BACKOFF_MAX_MS ? NL_WIFI_BACKOFF_MAX_MS : sm->backoff * 2u;
}
if ((sm->state == NL_WIFI_ST_STA_CONNECTING || sm->state == NL_WIFI_ST_APSTA_FALLBACK) && sm->retry_armed && if ((sm->state == NL_WIFI_ST_STA_CONNECTING || sm->state == NL_WIFI_ST_APSTA_FALLBACK) && sm->retry_armed &&
due(now, sm->retry_at)) { due(now, sm->retry_at)) {
sm->retry_armed = false; sm->retry_armed = false;
a.connect = true; a.connect = true;
sm->awaiting = true;
sm->connect_at = now;
} }
if (sm->state == NL_WIFI_ST_ONBOARD_TEST && due(now, sm->deadline)) if (sm->state == NL_WIFI_ST_ONBOARD_TEST && due(now, sm->deadline))
fail_test(sm, NL_WIFI_ERR_TIMEOUT, now, &a); fail_test(sm, NL_WIFI_ERR_TIMEOUT, now, &a);
+3
View File
@@ -10,6 +10,7 @@
#define NL_WIFI_AP_CLOSE_FALLBACK_MS 10000u #define NL_WIFI_AP_CLOSE_FALLBACK_MS 10000u
#define NL_WIFI_BACKOFF_MIN_MS 1000u #define NL_WIFI_BACKOFF_MIN_MS 1000u
#define NL_WIFI_BACKOFF_MAX_MS 60000u #define NL_WIFI_BACKOFF_MAX_MS 60000u
#define NL_WIFI_CONNECT_TIMEOUT_MS 30000u /* no event after a connect -> treat as failed */
typedef enum { typedef enum {
NL_WIFI_ST_AP_ONBOARDING = 0, NL_WIFI_ST_AP_ONBOARDING = 0,
@@ -41,11 +42,13 @@ typedef struct {
bool pulsing; bool pulsing;
bool retry_armed; bool retry_armed;
bool ap_stop_armed; bool ap_stop_armed;
bool awaiting; /* waiting for response to a connect */
uint32_t since; /* start of the current connecting phase */ uint32_t since; /* start of the current connecting phase */
uint32_t retry_at; uint32_t retry_at;
uint32_t backoff; uint32_t backoff;
uint32_t deadline; /* onboarding test */ uint32_t deadline; /* onboarding test */
uint32_t ap_stop_at; uint32_t ap_stop_at;
uint32_t connect_at; /* when the pending connect was issued */
} nl_wifi_sm_t; } nl_wifi_sm_t;
nl_wifi_actions_t nl_wifi_sm_start(nl_wifi_sm_t *sm, bool have_creds, uint32_t now); nl_wifi_actions_t nl_wifi_sm_start(nl_wifi_sm_t *sm, bool have_creds, uint32_t now);
+20
View File
@@ -155,6 +155,25 @@ static void test_error_names(void)
TEST_ASSERT_EQUAL_STRING("not_found", nl_wifi_error_name(NL_WIFI_ERR_NOT_FOUND)); TEST_ASSERT_EQUAL_STRING("not_found", nl_wifi_error_name(NL_WIFI_ERR_NOT_FOUND));
} }
static void test_connect_without_any_event_retries(void)
{
nl_wifi_sm_start(&sm, true, 0);
TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, 29999).connect);
TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, 30000).connect); /* retry scheduled at 31000 */
TEST_ASSERT_TRUE(nl_wifi_sm_tick(&sm, 31000).connect);
/* next timeout: 31000 + 30000 + 2000 backoff = 63000 */
TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, 62999).connect);
TEST_ASSERT_TRUE(nl_wifi_sm_tick(&sm, 63000).connect);
/* fallback after 300000 ms, and attempts continue */
a = nl_wifi_sm_tick(&sm, 300000);
TEST_ASSERT_TRUE(a.start_ap);
TEST_ASSERT_EQUAL(NL_WIFI_ST_APSTA_FALLBACK, sm.state);
TEST_ASSERT_EQUAL_STRING("apsta", nl_wifi_sm_mode(&sm));
/* another attempt fires later */
a = nl_wifi_sm_tick(&sm, 360000);
TEST_ASSERT_TRUE(a.connect);
}
int main(void) int main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
@@ -168,5 +187,6 @@ int main(void)
RUN_TEST(test_onboarding_timeout); RUN_TEST(test_onboarding_timeout);
RUN_TEST(test_onboarding_while_connected_falls_back_to_old_credentials); RUN_TEST(test_onboarding_while_connected_falls_back_to_old_credentials);
RUN_TEST(test_error_names); RUN_TEST(test_error_names);
RUN_TEST(test_connect_without_any_event_retries);
return UNITY_END(); return UNITY_END();
} }