4. WiFi无线状态机设计
任务说明
实现一个WiFi接口状态机,管理无线开启、关闭、扫描、连接、认证失败等核心状态,并处理用户配置变更(如修改SSID/密码)时的状态迁移。状态机作为独立模块,可被上层网络管理逻辑调用。
状态定义与迁移规则
| 状态 | 触发事件 | 动作 | 下一状态 |
|---|---|---|---|
| OFF | ENABLE | 启动无线硬件 | IDLE |
| IDLE | SCAN | 发起扫描 | SCANNING |
| IDLE | CONNECT(ssid, pwd) | 发起连接 | CONNECTING |
| IDLE | DISABLE | 关闭无线 | OFF |
| SCANNING | SCAN_DONE | 上报扫描结果 | IDLE |
| SCANNING | DISABLE | 中止扫描并关闭 | OFF |
| CONNECTING | CONNECTED | 上报连接成功 | CONNECTED |
| CONNECTING | AUTH_FAIL | 上报认证失败 | IDLE |
| CONNECTING | DISABLE | 中止连接并关闭 | OFF |
| CONNECTED | DISCONNECTED | 上报断连 | IDLE |
| CONNECTED | DISABLE | 断开并关闭 | OFF |
| CONNECTED | CONFIG_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状态下用户可直接发起新连接,无需额外处理。 - 实际硬件操作(如开关射频、扫描信道)通过打印日志模拟,接入真实驱动时替换对应打印语句即可。