4. WiFi无线状态机设计

任务说明

实现一个WiFi接口状态机,管理无线开启、关闭、扫描、连接、认证失败等核心状态,并处理用户配置变更(如修改SSID/密码)时的状态迁移。状态机作为独立模块,可被上层网络管理逻辑调用。

状态定义与迁移规则

状态触发事件动作下一状态
OFFENABLE启动无线硬件IDLE
IDLESCAN发起扫描SCANNING
IDLECONNECT(ssid, pwd)发起连接CONNECTING
IDLEDISABLE关闭无线OFF
SCANNINGSCAN_DONE上报扫描结果IDLE
SCANNINGDISABLE中止扫描并关闭OFF
CONNECTINGCONNECTED上报连接成功CONNECTED
CONNECTINGAUTH_FAIL上报认证失败IDLE
CONNECTINGDISABLE中止连接并关闭OFF
CONNECTEDDISCONNECTED上报断连IDLE
CONNECTEDDISABLE断开并关闭OFF
CONNECTEDCONFIG_CHANGE(ssid, pwd)保存新配置并重连CONNECTING

完整实现(wifi_state_machine.c)

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

typedef enum {
    WIFI_OFF,
    WIFI_IDLE,
    WIFI_SCANNING,
    WIFI_CONNECTING,
    WIFI_CONNECTED
} wifi_state_t;

typedef enum {
    EV_ENABLE,
    EV_DISABLE,
    EV_SCAN,
    EV_SCAN_DONE,
    EV_CONNECT,
    EV_CONNECTED,
    EV_AUTH_FAIL,
    EV_DISCONNECTED,
    EV_CONFIG_CHANGE
} wifi_event_t;

typedef struct {
    char ssid[32];
    char password[64];
} wifi_config_t;

typedef struct {
    wifi_state_t state;
    wifi_config_t config;
    bool pending_config_change;
} wifi_machine_t;

static const char* state_name(wifi_state_t s) {
    switch (s) {
        case WIFI_OFF: return "OFF";
        case WIFI_IDLE: return "IDLE";
        case WIFI_SCANNING: return "SCANNING";
        case WIFI_CONNECTING: return "CONNECTING";
        case WIFI_CONNECTED: return "CONNECTED";
        default: return "UNKNOWN";
    }
}

void wifi_machine_init(wifi_machine_t *m) {
    m->state = WIFI_OFF;
    m->pending_config_change = false;
    memset(&m->config, 0, sizeof(m->config));
}

void wifi_machine_handle_event(wifi_machine_t *m, wifi_event_t ev,
                               const wifi_config_t *new_cfg) {
    switch (m->state) {
    case WIFI_OFF:
        if (ev == EV_ENABLE) {
            m->state = WIFI_IDLE;
            printf("[WiFi] 无线已开启\n");
        }
        break;

    case WIFI_IDLE:
        if (ev == EV_DISABLE) {
            m->state = WIFI_OFF;
            printf("[WiFi] 无线已关闭\n");
        } else if (ev == EV_SCAN) {
            m->state = WIFI_SCANNING;
            printf("[WiFi] 开始扫描...\n");
        } else if (ev == EV_CONNECT && new_cfg) {
            m->config = *new_cfg;
            m->state = WIFI_CONNECTING;
            printf("[WiFi] 正在连接 %s...\n", new_cfg->ssid);
        }
        break;

    case WIFI_SCANNING:
        if (ev == EV_SCAN_DONE) {
            m->state = WIFI_IDLE;
            printf("[WiFi] 扫描完成,返回IDLE\n");
        } else if (ev == EV_DISABLE) {
            m->state = WIFI_OFF;
            printf("[WiFi] 扫描中止,无线关闭\n");
        }
        break;

    case WIFI_CONNECTING:
        if (ev == EV_CONNECTED) {
            m->state = WIFI_CONNECTED;
            printf("[WiFi] 连接成功\n");
        } else if (ev == EV_AUTH_FAIL) {
            m->state = WIFI_IDLE;
            printf("[WiFi] 认证失败,返回IDLE\n");
        } else if (ev == EV_DISABLE) {
            m->state = WIFI_OFF;
            printf("[WiFi] 连接中止,无线关闭\n");
        }
        break;

    case WIFI_CONNECTED:
        if (ev == EV_DISCONNECTED) {
            m->state = WIFI_IDLE;
            printf("[WiFi] 连接断开,返回IDLE\n");
        } else if (ev == EV_DISABLE) {
            m->state = WIFI_OFF;
            printf("[WiFi] 无线关闭\n");
        } else if (ev == EV_CONFIG_CHANGE && new_cfg) {
            m->config = *new_cfg;
            m->state = WIFI_CONNECTING;
            printf("[WiFi] 配置变更,重连 %s...\n", new_cfg->ssid);
        }
        break;
    }
}

/* ---- 最小验证入口 ---- */
int main(void) {
    wifi_machine_t m;
    wifi_machine_init(&m);

    wifi_config_t cfg1 = {"HomeNet", "pass1234"};
    wifi_config_t cfg2 = {"OfficeWiFi", "secure5678"};

    wifi_machine_handle_event(&m, EV_ENABLE, NULL);
    wifi_machine_handle_event(&m, EV_SCAN, NULL);
    wifi_machine_handle_event(&m, EV_SCAN_DONE, NULL);
    wifi_machine_handle_event(&m, EV_CONNECT, &cfg1);
    wifi_machine_handle_event(&m, EV_AUTH_FAIL, NULL);
    wifi_machine_handle_event(&m, EV_CONNECT, &cfg1);
    wifi_machine_handle_event(&m, EV_CONNECTED, NULL);
    wifi_machine_handle_event(&m, EV_CONFIG_CHANGE, &cfg2);
    wifi_machine_handle_event(&m, EV_CONNECTED, NULL);
    wifi_machine_handle_event(&m, EV_DISABLE, NULL);

    printf("最终状态: %s\n", state_name(m.state));
    return 0;
}

编译与运行

gcc -o wifi_sm wifi_state_machine.c && ./wifi_sm

验证方法

程序输出应依次显示:无线开启 → 开始扫描 → 扫描完成 → 正在连接HomeNet → 认证失败 → 正在连接HomeNet → 连接成功 → 配置变更重连OfficeWiFi → 连接成功 → 无线关闭。最终状态打印为OFF。若输出顺序与上述一致,则状态机迁移逻辑正确。

关键设计说明

  • 状态机采用事件驱动模型,所有状态迁移集中在wifi_machine_handle_event中,便于追踪和调试。
  • 配置变更仅在CONNECTED状态被接受,触发重连流程;在IDLE状态下用户可直接发起新连接,无需额外处理。
  • 实际硬件操作(如开关射频、扫描信道)通过打印日志模拟,接入真实驱动时替换对应打印语句即可。