feat(wifi): Wechsel in und aus dem Standalone-Modus
This commit is contained in:
+72
-1
@@ -40,7 +40,15 @@ static void arm_ap_stop(nl_wifi_sm_t *sm, uint32_t at)
|
|||||||
static void fail_test(nl_wifi_sm_t *sm, nl_wifi_error_t err, uint32_t now, nl_wifi_actions_t *a)
|
static void fail_test(nl_wifi_sm_t *sm, nl_wifi_error_t err, uint32_t now, nl_wifi_actions_t *a)
|
||||||
{
|
{
|
||||||
sm->error = err;
|
sm->error = err;
|
||||||
if (sm->have_creds) {
|
if (sm->standalone) {
|
||||||
|
/* Zurueck in den EIGENEN AP. Der offene Onboarding-AP waere hier doppelt falsch:
|
||||||
|
* er verloere Name und Passwort des Nutzers, und open_access() machte die Lampe
|
||||||
|
* ohne Token flashbar. Ein Tippfehler im WLAN-Passwort darf sie nicht entsichern. */
|
||||||
|
sm->state = NL_WIFI_ST_STANDALONE;
|
||||||
|
sm->ap_up = true;
|
||||||
|
a->disconnect = true;
|
||||||
|
a->start_ap = true;
|
||||||
|
} else if (sm->have_creds) {
|
||||||
sm->state = NL_WIFI_ST_APSTA_FALLBACK;
|
sm->state = NL_WIFI_ST_APSTA_FALLBACK;
|
||||||
sm->since = now;
|
sm->since = now;
|
||||||
sm->backoff = NL_WIFI_BACKOFF_MIN_MS;
|
sm->backoff = NL_WIFI_BACKOFF_MIN_MS;
|
||||||
@@ -114,6 +122,10 @@ nl_wifi_actions_t nl_wifi_sm_event(nl_wifi_sm_t *sm, nl_wifi_event_t ev, nl_wifi
|
|||||||
case NL_WIFI_ST_ONBOARD_TEST:
|
case NL_WIFI_ST_ONBOARD_TEST:
|
||||||
if (ev == NL_WIFI_EV_CONNECTED) {
|
if (ev == NL_WIFI_EV_CONNECTED) {
|
||||||
a.save_test_creds = true;
|
a.save_test_creds = true;
|
||||||
|
if (sm->standalone) {
|
||||||
|
sm->standalone = false;
|
||||||
|
a.clear_standalone = true;
|
||||||
|
}
|
||||||
sm->have_creds = true;
|
sm->have_creds = true;
|
||||||
sm->error = NL_WIFI_ERR_NONE;
|
sm->error = NL_WIFI_ERR_NONE;
|
||||||
sm->state = NL_WIFI_ST_STA_CONNECTED;
|
sm->state = NL_WIFI_ST_STA_CONNECTED;
|
||||||
@@ -195,12 +207,71 @@ nl_wifi_actions_t nl_wifi_sm_onboard(nl_wifi_sm_t *sm, uint32_t now)
|
|||||||
sm->deadline = now + NL_WIFI_ONBOARD_TIMEOUT_MS;
|
sm->deadline = now + NL_WIFI_ONBOARD_TIMEOUT_MS;
|
||||||
sm->retry_armed = false;
|
sm->retry_armed = false;
|
||||||
sm->ap_stop_armed = false;
|
sm->ap_stop_armed = false;
|
||||||
|
if (sm->pulse_armed) {
|
||||||
|
/* Der Startpuls gehoert nicht in den Test: sonst feuerte spaeter ein pulse_off, das zu
|
||||||
|
* keinem Puls mehr gehoert. Hier abraeumen; pulsing auch, damit er nicht haengen bleibt. */
|
||||||
|
sm->pulse_armed = false;
|
||||||
|
sm->pulsing = false;
|
||||||
|
a.pulse_off = true;
|
||||||
|
}
|
||||||
a.disconnect = true; /* M1: drop any stale station attempt so its events don't count */
|
a.disconnect = true; /* M1: drop any stale station attempt so its events don't count */
|
||||||
a.connect = true;
|
a.connect = true;
|
||||||
a.use_test_creds = true;
|
a.use_test_creds = true;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nl_wifi_actions_t nl_wifi_sm_standalone(nl_wifi_sm_t *sm, bool pulse, uint32_t now)
|
||||||
|
{
|
||||||
|
nl_wifi_actions_t a = none();
|
||||||
|
|
||||||
|
sm->standalone = true;
|
||||||
|
sm->state = NL_WIFI_ST_STANDALONE;
|
||||||
|
sm->error = NL_WIFI_ERR_NONE;
|
||||||
|
sm->retry_armed = false;
|
||||||
|
sm->ap_stop_armed = false;
|
||||||
|
sm->awaiting = false;
|
||||||
|
a.disconnect = true; /* eine laufende Stationsverbindung aufgeben */
|
||||||
|
if (!sm->ap_up) {
|
||||||
|
sm->ap_up = true;
|
||||||
|
a.start_ap = true;
|
||||||
|
}
|
||||||
|
if (pulse) {
|
||||||
|
sm->pulsing = true;
|
||||||
|
sm->pulse_armed = true;
|
||||||
|
sm->pulse_stop_at = now + NL_WIFI_STANDALONE_PULSE_MS;
|
||||||
|
a.pulse_on = true;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_wifi_actions_t nl_wifi_sm_leave_standalone(nl_wifi_sm_t *sm, bool have_creds, uint32_t now)
|
||||||
|
{
|
||||||
|
nl_wifi_actions_t a = none();
|
||||||
|
|
||||||
|
sm->standalone = false;
|
||||||
|
sm->have_creds = have_creds;
|
||||||
|
sm->pulse_armed = false;
|
||||||
|
if (have_creds) {
|
||||||
|
begin_connecting(sm, now);
|
||||||
|
a.connect = true;
|
||||||
|
sm->awaiting = true;
|
||||||
|
sm->connect_at = now;
|
||||||
|
if (sm->pulsing) {
|
||||||
|
sm->pulsing = false;
|
||||||
|
a.pulse_off = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Ohne Zugangsdaten bliebe die Lampe sonst unerreichbar: der offene
|
||||||
|
* Onboarding-AP ist hier der gewollte Ausweg. */
|
||||||
|
sm->state = NL_WIFI_ST_AP_ONBOARDING;
|
||||||
|
sm->ap_up = true;
|
||||||
|
sm->pulsing = true;
|
||||||
|
a.start_ap = true;
|
||||||
|
a.pulse_on = true;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
bool nl_wifi_sm_open_access(const nl_wifi_sm_t *sm)
|
bool nl_wifi_sm_open_access(const nl_wifi_sm_t *sm)
|
||||||
{
|
{
|
||||||
/* !standalone is NOT redundant: during an onboarding test started from standalone mode
|
/* !standalone is NOT redundant: during an onboarding test started from standalone mode
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ typedef struct {
|
|||||||
bool disconnect; /* drop a stray/failed station attempt (before any connect in the same set) */
|
bool disconnect; /* drop a stray/failed station attempt (before any connect in the same set) */
|
||||||
bool pulse_on;
|
bool pulse_on;
|
||||||
bool pulse_off;
|
bool pulse_off;
|
||||||
|
bool clear_standalone; /* Onboarding gelungen: den Standalone-Modus dauerhaft loeschen */
|
||||||
} nl_wifi_actions_t;
|
} nl_wifi_actions_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -61,6 +62,11 @@ nl_wifi_actions_t nl_wifi_sm_start(nl_wifi_sm_t *sm, bool have_creds, bool stand
|
|||||||
nl_wifi_actions_t nl_wifi_sm_event(nl_wifi_sm_t *sm, nl_wifi_event_t ev, nl_wifi_error_t err, uint32_t now);
|
nl_wifi_actions_t nl_wifi_sm_event(nl_wifi_sm_t *sm, nl_wifi_event_t ev, nl_wifi_error_t err, uint32_t now);
|
||||||
nl_wifi_actions_t nl_wifi_sm_tick(nl_wifi_sm_t *sm, uint32_t now);
|
nl_wifi_actions_t nl_wifi_sm_tick(nl_wifi_sm_t *sm, uint32_t now);
|
||||||
nl_wifi_actions_t nl_wifi_sm_onboard(nl_wifi_sm_t *sm, uint32_t now);
|
nl_wifi_actions_t nl_wifi_sm_onboard(nl_wifi_sm_t *sm, uint32_t now);
|
||||||
|
/* Schaltet zur Laufzeit in den Standalone-Modus (aus der API). */
|
||||||
|
nl_wifi_actions_t nl_wifi_sm_standalone(nl_wifi_sm_t *sm, bool pulse, uint32_t now);
|
||||||
|
/* Nimmt ihn zurueck: mit gespeicherten Zugangsdaten ins WLAN, sonst in den
|
||||||
|
offenen Onboarding-AP. */
|
||||||
|
nl_wifi_actions_t nl_wifi_sm_leave_standalone(nl_wifi_sm_t *sm, bool have_creds, uint32_t now);
|
||||||
bool nl_wifi_sm_open_access(const nl_wifi_sm_t *sm);
|
bool nl_wifi_sm_open_access(const nl_wifi_sm_t *sm);
|
||||||
const char *nl_wifi_sm_mode(const nl_wifi_sm_t *sm);
|
const char *nl_wifi_sm_mode(const nl_wifi_sm_t *sm);
|
||||||
const char *nl_wifi_error_name(nl_wifi_error_t e);
|
const char *nl_wifi_error_name(nl_wifi_error_t e);
|
||||||
|
|||||||
@@ -282,6 +282,106 @@ static void test_standalone_without_pulse_stays_dark(void)
|
|||||||
TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, NL_WIFI_STANDALONE_PULSE_MS).pulse_off);
|
TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, NL_WIFI_STANDALONE_PULSE_MS).pulse_off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Erfolg: die Lampe wechselt ins WLAN UND verlaesst den Standalone-Modus dauerhaft.
|
||||||
|
* Ohne clear_standalone staende sie nach dem naechsten Neustart wieder im eigenen AP. */
|
||||||
|
static void test_onboarding_from_standalone_clears_the_mode(void)
|
||||||
|
{
|
||||||
|
nl_wifi_sm_start(&sm, false, true, false, 0);
|
||||||
|
nl_wifi_sm_onboard(&sm, 1000);
|
||||||
|
a = nl_wifi_sm_event(&sm, NL_WIFI_EV_CONNECTED, NL_WIFI_ERR_NONE, 2000);
|
||||||
|
TEST_ASSERT_TRUE(a.save_test_creds);
|
||||||
|
TEST_ASSERT_TRUE(a.clear_standalone);
|
||||||
|
TEST_ASSERT_FALSE(sm.standalone);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ST_STA_CONNECTED, sm.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fehlschlag: zurueck in den EIGENEN AP, nicht in den offenen Onboarding-AP. Sonst
|
||||||
|
* verloere ein Tippfehler im WLAN-Passwort den vom Nutzer gesetzten AP-Namen samt
|
||||||
|
* Passwort und entsicherte die Lampe, weil open_access() dann wieder true waere. */
|
||||||
|
static void test_failed_onboarding_returns_to_standalone(void)
|
||||||
|
{
|
||||||
|
nl_wifi_sm_start(&sm, false, 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_TRUE(sm.standalone);
|
||||||
|
TEST_ASSERT_FALSE(nl_wifi_sm_open_access(&sm));
|
||||||
|
TEST_ASSERT_FALSE(a.clear_standalone);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ERR_AUTH, sm.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auch der Zeitablauf des Tests fuehrt zurueck in den eigenen AP. */
|
||||||
|
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);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ST_STANDALONE, sm.state);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ERR_TIMEOUT, sm.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Der bisherige Weg bleibt unberuehrt: ohne Standalone und ohne gespeicherte Daten
|
||||||
|
* landet ein gescheiterter Test weiterhin im offenen Onboarding-AP. */
|
||||||
|
static void test_failed_onboarding_without_standalone_opens_ap(void)
|
||||||
|
{
|
||||||
|
nl_wifi_sm_start(&sm, false, false, false, 0);
|
||||||
|
nl_wifi_sm_onboard(&sm, 1000);
|
||||||
|
nl_wifi_sm_event(&sm, NL_WIFI_EV_JOIN_FAILED, NL_WIFI_ERR_AUTH, 2000);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ST_AP_ONBOARDING, sm.state);
|
||||||
|
TEST_ASSERT_TRUE(nl_wifi_sm_open_access(&sm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Aus dem laufenden Stationsbetrieb in den eigenen AP. */
|
||||||
|
static void test_switching_to_standalone_at_runtime(void)
|
||||||
|
{
|
||||||
|
nl_wifi_sm_start(&sm, true, false, false, 0);
|
||||||
|
nl_wifi_sm_event(&sm, NL_WIFI_EV_CONNECTED, NL_WIFI_ERR_NONE, 1000);
|
||||||
|
a = nl_wifi_sm_standalone(&sm, true, 2000);
|
||||||
|
TEST_ASSERT_TRUE(a.disconnect);
|
||||||
|
TEST_ASSERT_TRUE(a.start_ap);
|
||||||
|
TEST_ASSERT_TRUE(a.pulse_on);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ST_STANDALONE, sm.state);
|
||||||
|
TEST_ASSERT_TRUE(sm.standalone);
|
||||||
|
TEST_ASSERT_TRUE(nl_wifi_sm_tick(&sm, 2000 + NL_WIFI_STANDALONE_PULSE_MS).pulse_off);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zuruecknehmen MIT gespeicherten Zugangsdaten: ab ins WLAN, nicht in den offenen AP. */
|
||||||
|
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(sm.standalone);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ST_STA_CONNECTING, sm.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zuruecknehmen OHNE Zugangsdaten: offener Onboarding-AP, damit man wieder herankommt. */
|
||||||
|
static void test_leaving_standalone_without_credentials_opens_onboarding(void)
|
||||||
|
{
|
||||||
|
nl_wifi_sm_start(&sm, false, true, false, 0);
|
||||||
|
a = nl_wifi_sm_leave_standalone(&sm, false, 1000);
|
||||||
|
TEST_ASSERT_TRUE(a.start_ap);
|
||||||
|
TEST_ASSERT_TRUE(a.pulse_on);
|
||||||
|
TEST_ASSERT_EQUAL(NL_WIFI_ST_AP_ONBOARDING, sm.state);
|
||||||
|
TEST_ASSERT_TRUE(nl_wifi_sm_open_access(&sm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Laeuft beim Start eines Onboarding-Tests noch der Startpuls, raeumt onboard() ihn ab:
|
||||||
|
* pulse_off sofort, danach kein verwaister pulse_off mehr -- weder nach einem
|
||||||
|
* gescheiterten noch nach einem gelungenen Test. */
|
||||||
|
static void test_onboard_cancels_running_start_pulse(void)
|
||||||
|
{
|
||||||
|
nl_wifi_sm_start(&sm, false, true, true, 0);
|
||||||
|
a = nl_wifi_sm_onboard(&sm, 1000);
|
||||||
|
TEST_ASSERT_TRUE(a.pulse_off);
|
||||||
|
TEST_ASSERT_FALSE(sm.pulse_armed);
|
||||||
|
TEST_ASSERT_FALSE(sm.pulsing);
|
||||||
|
TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, NL_WIFI_STANDALONE_PULSE_MS).pulse_off);
|
||||||
|
a = nl_wifi_sm_event(&sm, NL_WIFI_EV_CONNECTED, NL_WIFI_ERR_NONE, 6000);
|
||||||
|
TEST_ASSERT_FALSE(a.pulse_off);
|
||||||
|
TEST_ASSERT_FALSE(nl_wifi_sm_tick(&sm, 20000).pulse_off);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
@@ -306,5 +406,13 @@ int main(void)
|
|||||||
RUN_TEST(test_standalone_drops_a_stray_connect);
|
RUN_TEST(test_standalone_drops_a_stray_connect);
|
||||||
RUN_TEST(test_standalone_pulse_stops_by_itself);
|
RUN_TEST(test_standalone_pulse_stops_by_itself);
|
||||||
RUN_TEST(test_standalone_without_pulse_stays_dark);
|
RUN_TEST(test_standalone_without_pulse_stays_dark);
|
||||||
|
RUN_TEST(test_onboarding_from_standalone_clears_the_mode);
|
||||||
|
RUN_TEST(test_failed_onboarding_returns_to_standalone);
|
||||||
|
RUN_TEST(test_onboarding_timeout_returns_to_standalone);
|
||||||
|
RUN_TEST(test_failed_onboarding_without_standalone_opens_ap);
|
||||||
|
RUN_TEST(test_switching_to_standalone_at_runtime);
|
||||||
|
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);
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user