diff --git a/src/net/nl_wifi_sm.c b/src/net/nl_wifi_sm.c index e606d49..ff653be 100644 --- a/src/net/nl_wifi_sm.c +++ b/src/net/nl_wifi_sm.c @@ -240,6 +240,12 @@ nl_wifi_actions_t nl_wifi_sm_standalone(nl_wifi_sm_t *sm, bool pulse, uint32_t n sm->pulse_armed = true; sm->pulse_stop_at = now + NL_WIFI_STANDALONE_PULSE_MS; a.pulse_on = true; + } else if (sm->pulsing) { + /* Ein laufender unbefristeter Puls (aus dem Onboarding-AP) hat im eigenen AP keinen + * Timer mehr, der ihn beendet; er uebermalte dauerhaft die normale Ausgabe. */ + sm->pulsing = false; + sm->pulse_armed = false; + a.pulse_off = true; } return a; } diff --git a/test/test_wifi_sm.c b/test/test_wifi_sm.c index c75a1be..009f675 100644 --- a/test/test_wifi_sm.c +++ b/test/test_wifi_sm.c @@ -307,6 +307,9 @@ static void test_failed_onboarding_returns_to_standalone(void) TEST_ASSERT_TRUE(sm.standalone); TEST_ASSERT_FALSE(nl_wifi_sm_open_access(&sm)); TEST_ASSERT_FALSE(a.clear_standalone); + TEST_ASSERT_FALSE(a.connect); + TEST_ASSERT_TRUE(a.disconnect); + TEST_ASSERT_TRUE(a.start_ap); TEST_ASSERT_EQUAL(NL_WIFI_ERR_AUTH, sm.error); } @@ -315,9 +318,13 @@ static void test_onboarding_timeout_returns_to_standalone(void) { nl_wifi_sm_start(&sm, false, true, false, 0); nl_wifi_sm_onboard(&sm, 1000); - nl_wifi_sm_tick(&sm, 1000 + NL_WIFI_ONBOARD_TIMEOUT_MS); + a = nl_wifi_sm_tick(&sm, 1000 + NL_WIFI_ONBOARD_TIMEOUT_MS); TEST_ASSERT_EQUAL(NL_WIFI_ST_STANDALONE, sm.state); TEST_ASSERT_EQUAL(NL_WIFI_ERR_TIMEOUT, sm.error); + TEST_ASSERT_FALSE(a.connect); + TEST_ASSERT_TRUE(a.disconnect); + TEST_ASSERT_TRUE(a.start_ap); + TEST_ASSERT_FALSE(nl_wifi_sm_open_access(&sm)); } /* Der bisherige Weg bleibt unberuehrt: ohne Standalone und ohne gespeicherte Daten @@ -351,6 +358,8 @@ static void test_leaving_standalone_with_credentials_connects(void) nl_wifi_sm_start(&sm, true, true, false, 0); a = nl_wifi_sm_leave_standalone(&sm, true, 1000); TEST_ASSERT_TRUE(a.connect); + TEST_ASSERT_FALSE(a.start_ap); + TEST_ASSERT_FALSE(nl_wifi_sm_open_access(&sm)); TEST_ASSERT_FALSE(sm.standalone); TEST_ASSERT_EQUAL(NL_WIFI_ST_STA_CONNECTING, sm.state); } @@ -382,6 +391,68 @@ static void test_onboard_cancels_running_start_pulse(void) TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, 20000).pulse_off); } +/* Der eigentliche Spec-Fall: gespeicherte Zugangsdaten UND Standalone, der Test scheitert. + * Die Lampe darf nicht in den Rueckfall (APSTA_FALLBACK) mit den alten Daten gehen und + * damit ihren eigenen AP verlassen, sondern bleibt im Standalone-AP. */ +static void test_failed_onboarding_with_credentials_stays_standalone(void) +{ + nl_wifi_sm_start(&sm, true, true, false, 0); + nl_wifi_sm_onboard(&sm, 1000); + a = nl_wifi_sm_event(&sm, NL_WIFI_EV_JOIN_FAILED, NL_WIFI_ERR_AUTH, 2000); + TEST_ASSERT_EQUAL(NL_WIFI_ST_STANDALONE, sm.state); + TEST_ASSERT_FALSE(a.connect); + TEST_ASSERT_TRUE(a.disconnect); + TEST_ASSERT_TRUE(a.start_ap); + TEST_ASSERT_FALSE(nl_wifi_sm_open_access(&sm)); +} + +static void test_onboarding_timeout_with_credentials_stays_standalone(void) +{ + nl_wifi_sm_start(&sm, true, true, false, 0); + nl_wifi_sm_onboard(&sm, 1000); + a = nl_wifi_sm_tick(&sm, 1000 + NL_WIFI_ONBOARD_TIMEOUT_MS); + TEST_ASSERT_EQUAL(NL_WIFI_ST_STANDALONE, sm.state); + TEST_ASSERT_FALSE(a.connect); + TEST_ASSERT_TRUE(a.disconnect); + TEST_ASSERT_FALSE(nl_wifi_sm_open_access(&sm)); +} + +/* Nach gelungenem Onboarding laeuft noch der AP-Stopptimer. Schaltet man jetzt auf + * Standalone, muss er weg sein, sonst schaltet tick() den AP ab und die Lampe ist + * ueber nichts mehr erreichbar. */ +static void test_standalone_cancels_pending_ap_stop(void) +{ + nl_wifi_sm_start(&sm, false, false, false, 0); + nl_wifi_sm_onboard(&sm, 1000); + nl_wifi_sm_event(&sm, NL_WIFI_EV_CONNECTED, NL_WIFI_ERR_NONE, 2000); + nl_wifi_sm_standalone(&sm, false, 3000); + a = nl_wifi_sm_tick(&sm, 2000 + NL_WIFI_AP_CLOSE_ONBOARD_MS); + TEST_ASSERT_FALSE(a.stop_ap); + TEST_ASSERT_TRUE(sm.ap_up); +} + +/* Ein unbefristeter Puls aus dem Onboarding-AP muss beim Wechsel ohne Puls enden, denn + * im Standalone-Modus gibt es keinen Timer mehr, der ihn beendete. */ +static void test_standalone_without_pulse_ends_running_pulse(void) +{ + nl_wifi_sm_start(&sm, false, false, false, 0); + TEST_ASSERT_TRUE(sm.pulsing); + a = nl_wifi_sm_standalone(&sm, false, 1000); + TEST_ASSERT_TRUE(a.pulse_off); + TEST_ASSERT_FALSE(a.pulse_on); + TEST_ASSERT_FALSE(sm.pulsing); + TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, 1000 + NL_WIFI_STANDALONE_PULSE_MS).pulse_off); +} + +/* onboard() aus dem Onboarding-AP laesst den unbefristeten Puls in Ruhe. */ +static void test_onboard_from_ap_onboarding_keeps_pulse(void) +{ + nl_wifi_sm_start(&sm, false, false, false, 0); + a = nl_wifi_sm_onboard(&sm, 1000); + TEST_ASSERT_FALSE(a.pulse_off); + TEST_ASSERT_TRUE(sm.pulsing); +} + int main(void) { UNITY_BEGIN(); @@ -414,5 +485,10 @@ int main(void) RUN_TEST(test_leaving_standalone_with_credentials_connects); RUN_TEST(test_leaving_standalone_without_credentials_opens_onboarding); RUN_TEST(test_onboard_cancels_running_start_pulse); + RUN_TEST(test_failed_onboarding_with_credentials_stays_standalone); + RUN_TEST(test_onboarding_timeout_with_credentials_stays_standalone); + RUN_TEST(test_standalone_cancels_pending_ap_stop); + RUN_TEST(test_standalone_without_pulse_ends_running_pulse); + RUN_TEST(test_onboard_from_ap_onboarding_keeps_pulse); return UNITY_END(); }