5.35 WLAN 设备
5.35 WLAN 设备
📚 本节导读
学习时长: 约 60 分钟
难度级别: ⭐⭐⭐⭐☆
前置知识: C 语言基础、无线网络基础、5.1 设备驱动框架、5.20 Net 网络设备
WLAN(Wireless Local Area Network,无线局域网)设备是嵌入式设备联网的核心之一,广泛用于智能家居、网关、物联网节点。OneOS 将 WLAN 抽象为 OS_DEVICE_TYPE_WLAN 类型设备,通过 os_wlan_device 内嵌 os_net_device 实现与网络协议栈的无缝对接,提供 STA(工作站)/AP(热点) 模式、扫描、加入/离开网络、事件回调等能力。WLAN 设备框架位于 drivers/net/ 目录,核心文件为 wlan_dev.h 与 wlan_dev.c。
本节会带你:
- 看懂 WLAN 设备如何内嵌 Net 设备、对接网络协议栈;
- 掌握
os_wlan_device、os_wlan_device_ops、os_wlan_info、os_wlan_scan_info等核心结构体的每个字段; - 掌握安全类型(
os_wlan_security_t)与 WLAN 事件类型; - 逐个拆解
os_wlan_join、os_wlan_scan、os_wlan_leave、os_wlan_start/stop、os_wlan_net_register、os_wlan_event_callback的完整源码; - 通过多个可运行示例掌握联网、扫描、加入网络、事件处理的实际开发。
说明:本节所有源码均取自项目
drivers/net/wlan_dev.h与drivers/net/wlan_dev.c,与项目源码逐字一致(含原始英文注释)。
🎯 学习目标
- 理解 OneOS 中 WLAN 设备内嵌 Net 设备、对接网络协议栈的设计
- 掌握
os_wlan_device、os_wlan_device_ops、os_wlan_info、os_wlan_scan_info、os_wlan_ssid各字段含义与来源 - 掌握安全类型(
os_wlan_security_t)与 WLAN 事件类型 - 掌握扫描、加入/离开网络、STA/AP 启停等核心 API 的使用
- 理解 WLAN 事件回调(
os_wlan_event_callback)如何联动网络状态 - 理解更换 WLAN 模组/芯片时如何移植 BSP 层 WLAN 驱动
- 能够编写完整的 WLAN 联网程序
一、概述
WLAN(Wireless Local Area Network,无线局域网)设备是嵌入式设备联网的核心之一,广泛用于智能家居、网关、物联网节点。OneOS 将 WLAN 抽象为 OS_DEVICE_TYPE_WLAN 类型设备,通过 os_wlan_device 内嵌 os_net_device 实现与网络协议栈的无缝对接,提供 STA/AP 模式、扫描、加入/离开网络、事件回调等能力。WLAN 设备框架位于 drivers/net/ 目录下,核心头文件为 wlan_dev.h。
WLAN 设备框架的特点:
- 网络协议栈对接:
os_wlan_device内嵌os_net_device,天然接入 OneOS 网络协议栈(lwIP 等) - STA/AP 双模式:支持工作站(连接路由器)与热点(被连接)两种模式
- 扫描功能:主动扫描周边无线网络,返回扫描结果
- 事件回调:AP 启动/停止、STA 加入/离开、扫描完成等事件驱动
- 多种安全类型:开放、WEP、WPA/WPA2(PSK/ENT)等
1.1 WLAN 设备的分层架构
WLAN 设备基于 5.1 设备框架和 5.20 Net 网络设备,通过 os_wlan_device_ops 与具体无线芯片/模组驱动解耦:
┌────────────────────────────────────────────────────────────┐
│ 应用层(Application) │
│ os_wlan_join / os_wlan_scan / os_wlan_leave │
│ os_wlan_start / os_wlan_stop / os_wlan_event_callback │
│ os_device_open_s / os_net_*(网络收发) │
└──────────────────────────────┬─────────────────────────────┘
│ os_wlan_* → ops->xxx
▼
┌────────────────────────────────────────────────────────────┐
│ WLAN 框架层(drivers/net/wlan_dev.c) │
│ os_wlan_join/scan/leave/start/stop │
│ os_wlan_event_callback(事件→网络状态联动) │
│ wlan_net_dev_ops(init/send/get_mac/set_filter) │
│ os_wlan_net_register(注册为 Net 设备) │
└──────────────────────────────┬─────────────────────────────┘
│ 调用 wlan_dev->ops->join/scan/start/send
▼
┌────────────────────────────────────────────────────────────┐
│ BSP 无线芯片/模组驱动(如 beken 的 drv_wlan.c) │
│ 实现 struct os_wlan_device_ops 的接口 │
│ 通过 SDIO/USB/SPI 操作无线芯片固件与协议栈 │
└──────────────────────────────┬─────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 硬件(无线芯片/模组 + 天线) │
└────────────────────────────────────────────────────────────┘关键理解:WLAN 框架层不直接操作无线芯片。它负责"参数装配 + 事件转发 + 网络设备适配",真正驱动无线芯片(扫描、连接、收发)的是 BSP 无线驱动实现的 struct os_wlan_device_ops。这让上层应用与具体无线芯片(博通、乐鑫、Realtek 等)解耦。
1.2 WLAN 设备使用场景
一句话核心
WLAN 设备适用于需要让嵌入式设备通过无线网络联网的场景,如接入路由器上网(STA)或开启热点供他设备连接(AP)。
与有线网络/其他联网方式的机制对比
| 维度 | WLAN | 有线以太网(ETH) | 蜂窝(4G/5G) | NB-IoT |
|---|---|---|---|---|
| 布线 | 无线 | 网线 | 无线 | 无线 |
| 速率 | 中(几十~几百 Mbps) | 高(千兆) | 高(4G/5G) | 低(~100kbps) |
| 功耗 | 中 | 高 | 高 | 低 |
| 场景 | 智能家居、网关 | 工业、固定终端 | 移动联网 | 低功耗物联 |
| 拓扑 | STA/AP | 点对点/交换 | 蜂窝网 | 蜂窝网 |
为什么用 WLAN 而不是有线/蜂窝:需要免布线、无线接入局域网时 WLAN 最合适(家庭/办公室场景);有线需布线、蜂窝需 SIM 卡和资费、NB-IoT 速率极低只适合低频上报。WLAN 在"覆盖广、速率够、免布线"三者间最均衡。
典型应用场景
场景 1:设备接入路由器上网(STA 模式)
┌────────────┐ WLAN(无线) ┌─────────────┐
│ 智能设备 │ ◀─────────────▶│ 无线路由器 │
│ os_wlan_join│ │ (AP) │
└────────────┘ └─────────────┘为什么用 WLAN:设备需要连上家庭/办公室 WiFi 才能上报数据、接收控制命令。os_wlan_join 提供 SSID + 密码连接。
实际工作:任务调 os_wlan_join(&wlan, "MyWiFi", "password", OS_WLAN_SECURITY_WPA2_AES_PSK) → 无线驱动连接路由器 → 成功后 os_wlan_event_callback 收到 OS_WLAN_EVET_JOIN → 调 os_net_linkchange(OS_TRUE) 通知网络协议栈链路就绪 → 设备获得 IP,可收发数据。
场景 2:设备开启热点(AP 模式)
为什么用 WLAN:设备要作为热点供手机/其他设备连接(如配网、点对点控制)。
实际工作:调 os_wlan_start 启动无线,os_wlan_event_callback 收到 OS_WLAN_EVET_AP_START → 链路就绪;手机连接后收到 OS_WLAN_EVET_AP_ASSOCIATED。
场景 3:扫描周边 WiFi(选网/配网)
为什么用 WLAN:设备需要列出周边可用 WiFi 让用户选择,或自动选信号强的网络。
实际工作:调 os_wlan_scan(&wlan, 1000, 20) 扫描 1 秒、最多 20 个结果 → 遍历 scan_result->scan_info[] 读 SSID、信号强度、加密方式。
选型边界表(何时不该用 WLAN)
| 场景 | 该用什么 | 为什么 |
|---|---|---|
| 需极高带宽/稳定(工业实时控制) | 有线以太网 | WLAN 易受干扰、延迟抖动 |
| 超低功耗、低频上报 | NB-IoT/LoRa | WLAN 连接功耗高 |
| 移动蜂窝联网 | 4G/5G 模组 | WLAN 依赖 AP 热点 |
| 极短距离点对点 | BLE/蓝牙 | WLAN 功耗和复杂度高 |
结合源码的使用注意点
- WLAN 是 Net 设备的子类:
os_wlan_device内嵌os_net_device,通过os_wlan_net_register注册为网络设备,上层用os_net_*收发数据(见 4.7)。 - 加入网络是异步的:
os_wlan_join只是下发连接请求(ops->join),真正连接成功由事件OS_WLAN_EVET_JOIN通知,需注册事件回调处理(见 4.6)。 - 扫描会分配内存:
os_wlan_scan内部os_calloc分配结果缓冲,用后需os_wlan_scan_clean_result释放(见 4.3)。 - 安全类型枚举校验:
os_wlan_join会校验security < OS_WLAN_SECURITY_MAX,非法值返回OS_EIO(见 4.2)。
二、核心数据结构(字段详解)
本节对照 drivers/net/wlan_dev.h 讲解 WLAN 设备的核心结构体。来源:drivers/net/wlan_dev.h。
2.1 WLAN 设备结构体 os_wlan_device
struct os_wlan_device
{
struct os_net_device net_dev;
const struct os_wlan_device_ops *ops;
void *drv_dev;
uint32_t flags;
struct os_wlan_info info;
struct os_wlan_scan_result *scan_result;
};| 字段 | 类型 | 含义 |
|---|---|---|
net_dev | struct os_net_device | 内嵌的网络设备,使 WLAN 接入网络协议栈 |
ops | const struct os_wlan_device_ops * | WLAN 操作函数表(BSP 无线驱动填充) |
drv_dev | void * | 无线驱动私有数据指针 |
flags | uint32_t | 标志位(OS_WLAN_FLAG_STA_ONLY/AP_ONLY) |
info | struct os_wlan_info | 连接信息(SSID/密码/安全类型/国家/信道) |
scan_result | struct os_wlan_scan_result * | 扫描结果指针(os_wlan_scan 分配) |
关键理解:net_dev 内嵌 os_net_device,是 WLAN 设备与网络协议栈的桥。os_wlan_net_register 用它把 WLAN 注册为网络设备,wlan_net_dev_ops(send/get_mac/init 等)让协议栈能通过 WLAN 收发数据(见 4.7)。
2.2 WLAN 设备信息 os_wlan_info
struct os_wlan_info
{
const char *ssid;
const char *password;
os_wlan_security_t security;
os_wlan_country_code_t country;
uint8_t channel;
};| 字段 | 类型 | 含义 |
|---|---|---|
ssid | const char * | 无线网络名称(os_wlan_join 传入) |
password | const char * | 连接密码(os_wlan_join 传入) |
security | os_wlan_security_t | 安全类型(见 3.1) |
country | os_wlan_country_code_t | 国家码(CHINA/UNITED_STATES) |
channel | uint8_t | 信道 |
os_wlan_join 会把 ssid/password/security 填入 wlan_dev->info(见 4.2)。
2.3 WLAN 扫描信息 os_wlan_scan_info 与 os_wlan_scan_result
struct os_wlan_scan_info
{
os_wlan_ssid_t ssid;
uint8_t bssid[6];
int16_t signal_strength;
uint32_t max_data_rate;
os_wlan_bss_type_t bss_type;
os_wlan_security_t security;
uint8_t channel;
os_wlan_802_11_band_t band;
os_bool_t on_channel;
};| 字段 | 类型 | 含义 |
|---|---|---|
ssid | os_wlan_ssid_t | 网络名称(含长度) |
bssid[6] | uint8_t[6] | 接入点 MAC 地址 |
signal_strength | int16_t | 信号强度(dBm,负值) |
max_data_rate | uint32_t | 最大数据速率 |
bss_type | os_wlan_bss_type_t | BSS 类型(基础设施/Adhoc/任意) |
security | os_wlan_security_t | 安全类型 |
channel | uint8_t | 信道 |
band | os_wlan_802_11_band_t | 频段(2.4GHz/5GHz) |
on_channel | os_bool_t | 是否在指定信道 |
struct os_wlan_scan_result
{
struct os_wlan_scan_info *scan_info;
uint32_t max_num;
uint32_t count;
};| 字段 | 类型 | 含义 |
|---|---|---|
scan_info | struct os_wlan_scan_info * | 扫描结果数组指针 |
max_num | uint32_t | 最大可存结果数 |
count | uint32_t | 实际扫描到的结果数 |
关键理解:os_wlan_scan 内部分配"scan_result 结构体 + max_num 个 scan_info"的连续内存,scan_info 指向紧随 scan_result 之后的位置(见 4.3)。遍历 count 个结果即可。
2.4 SSID 结构体 os_wlan_ssid
typedef struct os_wlan_ssid
{
uint8_t len;
char val[OS_WLAN_SSID_MAX_LENGTH + 1];
} os_wlan_ssid_t;| 字段 | 类型 | 含义 |
|---|---|---|
len | uint8_t | SSID 长度 |
val | char[OS_WLAN_SSID_MAX_LENGTH + 1] | SSID 字符串(含结尾 \0) |
2.5 WLAN 操作函数表 os_wlan_device_ops
struct os_wlan_device_ops
{
os_err_t (*join)(struct os_wlan_device *wlan_dev);
os_err_t (*check_join_status)(struct os_wlan_device *wlan_dev);
os_err_t (*leave)(struct os_wlan_device *wlan_dev);
os_err_t (*wlan_scan)(struct os_wlan_device *wlan, uint32_t msec, struct os_wlan_scan_result *scan_result);
os_err_t (*wlan_scan_stop)(struct os_wlan_device *wlan);
os_err_t (*start)(struct os_wlan_device *wlan_dev);
os_err_t (*stop)(struct os_wlan_device *wlan_dev);
void (*irq_handler)(void *param);
os_err_t (*init)(struct os_wlan_device *wlan_dev);
os_err_t (*deinit)(struct os_wlan_device *wlan_dev);
os_err_t (*send)(struct os_wlan_device *wlan_dev, uint8_t *buff, uint32_t size);
os_err_t (*get_mac)(struct os_wlan_device *wlan_dev, uint8_t *addr);
os_err_t (*set_filter)(struct os_wlan_device *wlan_dev, uint8_t *addr, os_bool_t enable);
};| 函数指针 | 说明 |
|---|---|
join | 加入网络(连接 AP,STA 模式) |
check_join_status | 检查连接状态 |
leave | 离开网络(断开连接) |
wlan_scan | 扫描周边网络 |
wlan_scan_stop | 停止扫描 |
start | 启动无线(AP/STA 模式) |
stop | 停止无线 |
irq_handler | 无线芯片中断回调 |
init/deinit | 初始化/反初始化无线 |
send | 发送网络数据包(供协议栈调用) |
get_mac | 获取 MAC 地址 |
set_filter | 设置过滤 |
关键理解:这些 ops 是 BSP 无线驱动的"契约"。其中 send/get_mac/init/deinit/set_filter 通过 wlan_net_dev_ops 暴露给网络协议栈(见 4.7);join/scan/start/stop 等是 WLAN 专有接口。
三、安全类型与事件类型
本节对照 drivers/net/wlan_dev.h 讲解安全类型、事件类型等枚举。来源:drivers/net/wlan_dev.h。
3.1 安全类型 os_wlan_security_t
typedef enum
{
OS_WLAN_SECURITY_OPEN = 0,
OS_WLAN_SECURITY_WEP_PSK,
OS_WLAN_SECURITY_WEP_SHARED,
OS_WLAN_SECURITY_WPA_TKIP_PSK,
OS_WLAN_SECURITY_WPA_AES_PSK,
OS_WLAN_SECURITY_WPA_MIXED_PSK,
OS_WLAN_SECURITY_WPA2_AES_PSK,
OS_WLAN_SECURITY_WPA2_TKIP_PSK,
OS_WLAN_SECURITY_WPA2_MIXED_PSK,
OS_WLAN_SECURITY_WPA_TKIP_ENT,
OS_WLAN_SECURITY_WPA_AES_ENT,
OS_WLAN_SECURITY_WPA_MIXED_ENT,
OS_WLAN_SECURITY_WPA2_TKIP_ENT,
OS_WLAN_SECURITY_WPA2_AES_ENT,
OS_WLAN_SECURITY_WPA2_MIXED_ENT,
OS_WLAN_SECURITY_IBSS_OPEN,
OS_WLAN_SECURITY_WPS_OPEN,
OS_WLAN_SECURITY_WPS_SECURE,
OS_WLAN_SECURITY_UNKNOWN,
OS_WLAN_SECURITY_FORCE_32_BIT,
OS_WLAN_SECURITY_MAX,
} os_wlan_security_t;| 安全类型 | 值 | 说明 |
|---|---|---|
OS_WLAN_SECURITY_OPEN | 0 | 开放(无密码) |
OS_WLAN_SECURITY_WEP_PSK | 1 | WEP 预共享密钥 |
OS_WLAN_SECURITY_WPA_AES_PSK | 4 | WPA-AES 预共享密钥 |
OS_WLAN_SECURITY_WPA_MIXED_PSK | 5 | WPA 混合模式 |
OS_WLAN_SECURITY_WPA2_AES_PSK | 6 | WPA2-AES(家庭路由器常用) |
OS_WLAN_SECURITY_WPA2_TKIP_PSK | 7 | WPA2-TKIP |
OS_WLAN_SECURITY_WPA2_MIXED_PSK | 8 | WPA2 混合模式 |
OS_WLAN_SECURITY_IBSS_OPEN | 15 | IBSS(Adhoc)开放 |
OS_WLAN_SECURITY_WPS_SECURE | 17 | WPS 安全 |
OS_WLAN_SECURITY_UNKNOWN | 18 | 未知 |
OS_WLAN_SECURITY_FORCE_32_BIT | 19 | 强制 32 位(对齐占位) |
OS_WLAN_SECURITY_MAX | 20 | 上限哨兵(os_wlan_join 校验用) |
关键理解:
OS_WLAN_SECURITY_FORCE_32_BIT用于让枚举强制占 4 字节(防止编译器压缩成 1 字节,保证 ABI 稳定);OS_WLAN_SECURITY_MAX是上限哨兵,os_wlan_join用它校验非法安全类型(见 4.2)。
3.2 事件类型
#define OS_WLAN_EVET_AP_START 0x01
#define OS_WLAN_EVET_AP_STOP 0x02
#define OS_WLAN_EVET_STA_START 0x03
#define OS_WLAN_EVET_STA_STOP 0x04
#define OS_WLAN_EVET_AP_ASSOCIATED 0x05
#define OS_WLAN_EVET_AP_DISASSOCIATED 0x06
#define OS_WLAN_EVET_JOIN 0x07
#define OS_WLAN_EVET_LEAVE 0x08
#define OS_WLAN_EVET_SCAN 0x09
#define OS_WLAN_EVET_NONE 0x00| 事件 | 值 | 说明 |
|---|---|---|
OS_WLAN_EVET_AP_START | 0x01 | AP 模式启动 |
OS_WLAN_EVET_AP_STOP | 0x02 | AP 模式停止 |
OS_WLAN_EVET_STA_START | 0x03 | STA 模式启动 |
OS_WLAN_EVET_STA_STOP | 0x04 | STA 模式停止 |
OS_WLAN_EVET_AP_ASSOCIATED | 0x05 | 有设备接入 AP |
OS_WLAN_EVET_AP_DISASSOCIATED | 0x06 | 有设备离开 AP |
OS_WLAN_EVET_JOIN | 0x07 | 已加入网络(连接成功) |
OS_WLAN_EVET_LEAVE | 0x08 | 已离开网络 |
OS_WLAN_EVET_SCAN | 0x09 | 扫描完成 |
OS_WLAN_EVET_NONE | 0x00 | 无事件 |
关键理解:os_wlan_event_callback 把 JOIN/AP_START 映射为链路就绪(os_net_linkchange(OS_TRUE)),把 LEAVE/AP_STOP 映射为链路断开(os_net_linkchange(OS_FALSE)),AP_ASSOCIATED/AP_DISASSOCIATED 仅记录不改变链路(见 4.6)。
3.3 其他枚举
typedef enum
{
OS_WLAN_COUNTRY_CHINA = 0,
OS_WLAN_COUNTRY_UNITED_STATES,
OS_WLAN_COUNTRY_UNKNOW
} os_wlan_country_code_t;
typedef enum
{
OS_802_11_BAND_5GHZ = 0, /* Denotes 5GHz radio band */
OS_802_11_BAND_2_4GHZ = 1, /* Denotes 2.4GHz radio band */
OS_802_11_BAND_UNKNOWN = 0x7fffffff, /* unknown */
} os_wlan_802_11_band_t;
typedef enum
{
OS_BSS_TYPE_INFRASTRUCTURE = 0,
OS_BSS_TYPE_ADHOC = 1,
OS_BSS_TYPE_ANY = 2,
OS_BSS_TYPE_UNKNOWN = -1
} os_wlan_bss_type_t;| 枚举 | 取值 | 说明 |
|---|---|---|
os_wlan_country_code_t | CHINA=0/UNITED_STATES=1/UNKNOW=2 | 国家码 |
os_wlan_802_11_band_t | 5GHZ=0/2_4GHZ=1/UNKNOWN=0x7fffffff | 频段(0x7fffffff 表示未知) |
os_wlan_bss_type_t | INFRASTRUCTURE=0/ADHOC=1/ANY=2/UNKNOWN=-1 | BSS 类型 |
3.4 标志与编译配置
#define OS_WLAN_FLAG_STA_ONLY (0x1 << 0)
#define OS_WLAN_FLAG_AP_ONLY (0x1 << 1)| 标志 | 值 | 说明 |
|---|---|---|
OS_WLAN_FLAG_STA_ONLY | 0x01 | 仅 STA 模式(bit0) |
OS_WLAN_FLAG_AP_ONLY | 0x02 | 仅 AP 模式(bit1) |
编译配置:drivers/net/weave.yaml 中 wlan_dev.c ? {is_define('OS_USING_WLAN')}——只有定义了 OS_USING_WLAN 才编译 WLAN 框架。
四、核心 API 详解
本节逐个拆解 drivers/net/wlan_dev.c 中的核心函数。来源:drivers/net/wlan_dev.c。
4.1 os_wlan_start / os_wlan_stop —— 启动/停止无线
函数签名
os_err_t os_wlan_start(struct os_wlan_device *wlan_dev)
os_err_t os_wlan_stop(struct os_wlan_device *wlan_dev)参数 / 返回值说明
| 参数 | 类型 | 说明 |
|---|---|---|
wlan_dev | struct os_wlan_device * | WLAN 设备指针 |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 成功 |
OS_EIO | wlan_dev 为空 |
OS_FAILURE | ops->start 未实现(os_wlan_start) |
完整源码
os_err_t os_wlan_start(struct os_wlan_device *wlan_dev)
{
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}
if (wlan_dev->ops->start)
{
return wlan_dev->ops->start(wlan_dev);
}
return OS_FAILURE;
}
os_err_t os_wlan_stop(struct os_wlan_device *wlan_dev)
{
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}
if (wlan_dev->ops->stop)
{
return wlan_dev->ops->stop(wlan_dev);
}
return OS_SUCCESS;
}分步详解
第一步:校验设备非空(条件 wlan_dev == OS_NULL)
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}wlan_dev 为空返回 OS_EIO(非法参数)。
第二步:调用底层接口(条件 ops->start/ops->stop 非空)
if (wlan_dev->ops->start)
{
return wlan_dev->ops->start(wlan_dev);
}
return OS_FAILURE;os_wlan_start:若 ops->start 实现则调用(启动无线),否则返回 OS_FAILURE(未实现)。os_wlan_stop 同理,但未实现时返回 OS_SUCCESS(停止未实现的无线视为已停止)。
条件走向总结(os_wlan_start)
os_wlan_start() 条件走向总结:
├── wlan_dev == OS_NULL → 返回 OS_EIO
├── ops->start 非空 → 返回 ops->start(wlan_dev)
└── ops->start 为空 → 返回 OS_FAILURE4.2 os_wlan_join —— 加入网络(STA 连接)
函数签名
os_err_t os_wlan_join(struct os_wlan_device *wlan_dev, const char *ssid, const char *password, os_wlan_security_t security)参数 / 返回值说明
| 参数 | 类型 | 说明 |
|---|---|---|
wlan_dev | struct os_wlan_device * | WLAN 设备指针 |
ssid | const char * | 网络名称 |
password | const char * | 连接密码 |
security | os_wlan_security_t | 安全类型 |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 加入请求已下发(连接成功由事件 OS_WLAN_EVET_JOIN 通知) |
OS_EIO | wlan_dev 为空或 security 非法 |
OS_FAILURE | ops->join 未实现 |
完整源码
os_err_t os_wlan_join(struct os_wlan_device *wlan_dev, const char *ssid, const char *password, os_wlan_security_t security)
{
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}
if (security >= OS_WLAN_SECURITY_MAX)
{
return OS_EIO;
}
wlan_dev->info.ssid = ssid;
wlan_dev->info.password = password;
wlan_dev->info.security = security;
if (wlan_dev->ops->join)
{
return wlan_dev->ops->join(wlan_dev);
}
return OS_SUCCESS;
}分步详解
第一步:校验设备非空(条件 wlan_dev == OS_NULL)
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}第二步:校验安全类型合法(条件 security >= OS_WLAN_SECURITY_MAX)
if (security >= OS_WLAN_SECURITY_MAX)
{
return OS_EIO;
}为什么校验 security < OS_WLAN_SECURITY_MAX:OS_WLAN_SECURITY_MAX(20)是枚举上限哨兵。若 security 传入非法大值(如负数转成无符号后超过 20),底层驱动按未知安全类型处理可能出错。此校验防止非法参数传入。
第三步:填充连接信息(无条件执行)
wlan_dev->info.ssid = ssid;
wlan_dev->info.password = password;
wlan_dev->info.security = security;把 ssid/password/security 填入 wlan_dev->info,供底层驱动读取。
第四步:调用底层接口(条件 ops->join 非空)
if (wlan_dev->ops->join)
{
return wlan_dev->ops->join(wlan_dev);
}
return OS_SUCCESS;若 ops->join 实现则调用(下发连接请求),否则返回 OS_SUCCESS(默认视为成功)。
关键理解——加入是异步的:
os_wlan_join返回OS_SUCCESS仅表示"连接请求已下发",真正的连接结果由os_wlan_event_callback收到OS_WLAN_EVET_JOIN事件通知(见 4.6)。应用应在收到 JOIN 事件后才认为联网成功。
条件走向总结(os_wlan_join)
os_wlan_join() 条件走向总结:
├── wlan_dev == OS_NULL → 返回 OS_EIO
├── security >= OS_WLAN_SECURITY_MAX → 返回 OS_EIO
├── 填充 info.ssid/password/security
├── ops->join 非空 → 返回 ops->join(wlan_dev)
└── ops->join 为空 → 返回 OS_SUCCESS4.3 os_wlan_scan —— 扫描周边网络
函数签名
struct os_wlan_scan_result *os_wlan_scan(struct os_wlan_device *wlan_dev, uint32_t msec, uint32_t max_num)参数 / 返回值说明
| 参数 | 类型 | 说明 |
|---|---|---|
wlan_dev | struct os_wlan_device * | WLAN 设备指针 |
msec | uint32_t | 扫描超时(毫秒) |
max_num | uint32_t | 最大结果数 |
| 返回值 | 说明 |
|---|---|
| 非空指针 | 扫描结果(os_wlan_scan_result *) |
OS_NULL | 参数非法、内存分配失败或扫描失败 |
完整源码
struct os_wlan_scan_result *os_wlan_scan(struct os_wlan_device *wlan_dev, uint32_t msec, uint32_t max_num)
{
if ((wlan_dev == OS_NULL) || (wlan_dev->ops->wlan_scan == OS_NULL))
{
return OS_NULL;
}
wlan_dev->scan_result = os_calloc(1, sizeof(struct os_wlan_scan_result) + max_num * sizeof(struct os_wlan_scan_info));
if (wlan_dev->scan_result == OS_NULL)
{
return OS_NULL;
}
wlan_dev->scan_result->count = 0;
wlan_dev->scan_result->max_num = max_num;
wlan_dev->scan_result->scan_info = (struct os_wlan_scan_info *)((os_ubase_t)wlan_dev->scan_result + sizeof(struct os_wlan_scan_result));
if (wlan_dev->ops->wlan_scan(wlan_dev, msec, wlan_dev->scan_result) != OS_SUCCESS)
{
os_free(wlan_dev->scan_result);
wlan_dev->scan_result = OS_NULL;
}
return wlan_dev->scan_result;
}分步详解
第一步:参数校验(条件 wlan_dev 或 ops->wlan_scan 为空)
if ((wlan_dev == OS_NULL) || (wlan_dev->ops->wlan_scan == OS_NULL))
{
return OS_NULL;
}设备为空或底层扫描未实现,返回 OS_NULL。
第二步:分配扫描结果内存(条件分配失败)
wlan_dev->scan_result = os_calloc(1, sizeof(struct os_wlan_scan_result) + max_num * sizeof(struct os_wlan_scan_info));
if (wlan_dev->scan_result == OS_NULL)
{
return OS_NULL;
}关键点:一次性分配"scan_result 结构体 + max_num 个 scan_info"的连续内存。分配失败返回 OS_NULL。
数值演算(内存大小):以 32 位平台、4 字节对齐、
OS_WLAN_SSID_MAX_LENGTH = 32(Kconfig默认值)、max_num = 20为例,先推演sizeof(os_wlan_scan_info):
字段 大小/对齐后 说明 ssid(os_wlan_ssid_t)len(1)+对齐(3)+val[33]=40val[32+1]=33,整块对齐到 4bssid[6]6累计 40+6=46signal_strength(int16)2累计 48max_data_rate(uint32)4累计 52bss_type(enum=int)4累计 56security(enum=int)4累计 60channel(uint8)1累计 61band(enum=int)4(需 4 字节对齐)61补 3 字节 →64,再+4=68on_channel(bool)1累计 69,整结构对齐到 4 →72故
sizeof(os_wlan_scan_info) = 72字节,sizeof(os_wlan_scan_result) = 12字节(32 位下 3 个 4 字节成员)。max_num = 20时:
计算项 代入计算 结果 scan_result结构体sizeof(scan_result)12字节结果数组 20 * 721440字节总分配 12 + 14401452字节这
1452字节由os_calloc一次申请为连续内存,scan_info指针指向scan_result之后(偏移 12 字节)的位置。
第三步:初始化结果并调用底层扫描(条件 ops->wlan_scan 失败)
wlan_dev->scan_result->count = 0;
wlan_dev->scan_result->max_num = max_num;
wlan_dev->scan_result->scan_info = (struct os_wlan_scan_info *)((os_ubase_t)wlan_dev->scan_result + sizeof(struct os_wlan_scan_result));
if (wlan_dev->ops->wlan_scan(wlan_dev, msec, wlan_dev->scan_result) != OS_SUCCESS)
{
os_free(wlan_dev->scan_result);
wlan_dev->scan_result = OS_NULL;
}
return wlan_dev->scan_result;count清零、max_num记录上限、scan_info指向scan_result之后的位置(连续内存偏移);- 调用
ops->wlan_scan执行扫描,失败则释放内存并置空; - 返回
scan_result(调用者遍历scan_info[0..count-1])。
条件走向总结(os_wlan_scan)
os_wlan_scan() 条件走向总结:
├── wlan_dev 或 ops->wlan_scan 为空 → 返回 OS_NULL
├── os_calloc 分配连续内存
│ ├── 分配失败 → 返回 OS_NULL
│ └── 分配成功 → 继续
├── 初始化 count=0、max_num、scan_info 指针
├── ops->wlan_scan 失败
│ └── os_free + scan_result = OS_NULL
└── 返回 scan_result4.4 扫描结果释放/停止(os_wlan_scan_clean_result / os_wlan_scan_stop)
函数签名
os_err_t os_wlan_scan_clean_result(struct os_wlan_device *wlan_dev)
os_err_t os_wlan_scan_stop(struct os_wlan_device *wlan_dev)参数 / 返回值说明
| 参数 | 类型 | 说明 |
|---|---|---|
wlan_dev | struct os_wlan_device * | WLAN 设备指针 |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 成功 |
OS_EIO | wlan_dev 为空 |
完整源码
os_err_t os_wlan_scan_clean_result(struct os_wlan_device *wlan_dev)
{
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}
if (wlan_dev->scan_result)
{
os_free(wlan_dev->scan_result);
wlan_dev->scan_result = OS_NULL;
}
return OS_SUCCESS;
}
os_err_t os_wlan_scan_stop(struct os_wlan_device *wlan_dev)
{
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}
if (wlan_dev->ops->wlan_scan_stop)
{
return wlan_dev->ops->wlan_scan_stop(wlan_dev);
}
return OS_SUCCESS;
}分步详解(os_wlan_scan_clean_result)
第一步:校验设备非空(条件 wlan_dev == OS_NULL)
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}wlan_dev 为空返回 OS_EIO(非法参数)。
第二步:释放扫描结果内存(条件 scan_result 非空)
if (wlan_dev->scan_result)
{
os_free(wlan_dev->scan_result);
wlan_dev->scan_result = OS_NULL;
}
return OS_SUCCESS;若 scan_result 非空(os_wlan_scan 曾分配过内存),则 os_free 释放并把指针置空,避免悬挂指针;若为空则跳过。最后返回 OS_SUCCESS。用后必须调用,防止内存泄漏(os_wlan_scan 内部 os_calloc 分配的内存不会自动释放)。
条件走向总结(os_wlan_scan_clean_result)
os_wlan_scan_clean_result() 条件走向总结:
├── wlan_dev == OS_NULL → 返回 OS_EIO
├── scan_result 非空
│ └── os_free(scan_result);scan_result = OS_NULL
└── 返回 OS_SUCCESS分步详解(os_wlan_scan_stop)
第一步:校验设备非空(条件 wlan_dev == OS_NULL)
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}第二步:调用底层停止扫描接口(条件 ops->wlan_scan_stop 非空)
if (wlan_dev->ops->wlan_scan_stop)
{
return wlan_dev->ops->wlan_scan_stop(wlan_dev);
}
return OS_SUCCESS;若底层实现了 wlan_scan_stop 则调用以停止正在进行的扫描并返回其结果;未实现则视为已停止,返回 OS_SUCCESS(空实现不算失败)。
条件走向总结(os_wlan_scan_stop)
os_wlan_scan_stop() 条件走向总结:
├── wlan_dev == OS_NULL → 返回 OS_EIO
├── ops->wlan_scan_stop 非空 → 返回 ops->wlan_scan_stop(wlan_dev)
└── ops->wlan_scan_stop 为空 → 返回 OS_SUCCESS4.5 os_wlan_leave / os_wlan_check_join_status —— 离开网络/检查连接状态
函数签名
os_err_t os_wlan_leave(struct os_wlan_device *wlan_dev)
os_err_t os_wlan_check_join_status(struct os_wlan_device *wlan_dev)参数 / 返回值说明
| 参数 | 类型 | 说明 |
|---|---|---|
wlan_dev | struct os_wlan_device * | WLAN 设备指针 |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 成功 |
OS_EIO | wlan_dev 为空 |
| 其他 | 底层接口返回值 |
完整源码
os_err_t os_wlan_leave(struct os_wlan_device *wlan_dev)
{
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}
if (wlan_dev->ops->leave)
{
return wlan_dev->ops->leave(wlan_dev);
}
return OS_SUCCESS;
}
os_err_t os_wlan_check_join_status(struct os_wlan_device *wlan_dev)
{
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}
if (wlan_dev->ops->check_join_status)
{
return wlan_dev->ops->check_join_status(wlan_dev);
}
return OS_SUCCESS;
}分步详解(os_wlan_leave)
第一步:校验设备非空(条件 wlan_dev == OS_NULL)
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}第二步:调用底层断开接口(条件 ops->leave 非空)
if (wlan_dev->ops->leave)
{
return wlan_dev->ops->leave(wlan_dev);
}
return OS_SUCCESS;若底层实现了 leave 则调用(断开当前连接)并返回其结果;未实现则视为已离开,返回 OS_SUCCESS。
条件走向总结(os_wlan_leave)
os_wlan_leave() 条件走向总结:
├── wlan_dev == OS_NULL → 返回 OS_EIO
├── ops->leave 非空 → 返回 ops->leave(wlan_dev)
└── ops->leave 为空 → 返回 OS_SUCCESS分步详解(os_wlan_check_join_status)
第一步:校验设备非空(条件 wlan_dev == OS_NULL)
if (wlan_dev == OS_NULL)
{
return OS_EIO;
}第二步:调用底层查询接口(条件 ops->check_join_status 非空)
if (wlan_dev->ops->check_join_status)
{
return wlan_dev->ops->check_join_status(wlan_dev);
}
return OS_SUCCESS;若底层实现了 check_join_status 则调用以查询当前连接状态(返回是否已连接);未实现则返回 OS_SUCCESS(默认视为已就绪)。
条件走向总结(os_wlan_check_join_status)
os_wlan_check_join_status() 条件走向总结:
├── wlan_dev == OS_NULL → 返回 OS_EIO
├── ops->check_join_status 非空 → 返回 ops->check_join_status(wlan_dev)
└── ops->check_join_status 为空 → 返回 OS_SUCCESS关键理解:
os_wlan_leave断开连接后,底层驱动应回调os_wlan_event_callback(收到OS_WLAN_EVET_LEAVE)通知框架链路断开(见 4.6);os_wlan_check_join_status用于主动查询当前连接状态。
4.6 os_wlan_event_callback —— 事件回调(网络状态联动)
函数签名
os_err_t os_wlan_event_callback(struct os_wlan_device *wlan_dev, os_ubase_t event, void *args)参数 / 返回值说明
| 参数 | 类型 | 说明 |
|---|---|---|
wlan_dev | struct os_wlan_device * | WLAN 设备指针 |
event | os_ubase_t | 事件类型(OS_WLAN_EVET_*,见 3.2) |
args | void * | 事件参数(未使用) |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 事件处理成功 |
完整源码
os_err_t os_wlan_event_callback(struct os_wlan_device *wlan_dev, os_ubase_t event, void *args)
{
switch (event)
{
case OS_WLAN_EVET_JOIN:
case OS_WLAN_EVET_AP_START:
os_net_linkchange(&wlan_dev->net_dev, OS_TRUE);
break;
case OS_WLAN_EVET_LEAVE:
case OS_WLAN_EVET_AP_STOP:
os_net_linkchange(&wlan_dev->net_dev, OS_FALSE);
break;
case OS_WLAN_EVET_AP_ASSOCIATED:
case OS_WLAN_EVET_AP_DISASSOCIATED:
break;
default:
LOG_D(DRV_EXT_TAG, "event: UNKNOWN");
break;
}
return OS_SUCCESS;
}分步详解
第一步:链路就绪事件(条件 JOIN/AP_START)
case OS_WLAN_EVET_JOIN:
case OS_WLAN_EVET_AP_START:
os_net_linkchange(&wlan_dev->net_dev, OS_TRUE);
break;已加入网络(JOIN)或 AP 启动(AP_START)时,调 os_net_linkchange(OS_TRUE) 通知网络协议栈链路就绪(此后可分配 IP、收发数据)。
第二步:链路断开事件(条件 LEAVE/AP_STOP)
case OS_WLAN_EVET_LEAVE:
case OS_WLAN_EVET_AP_STOP:
os_net_linkchange(&wlan_dev->net_dev, OS_FALSE);
break;离开网络(LEAVE)或 AP 停止(AP_STOP)时,os_net_linkchange(OS_FALSE) 通知协议栈链路断开。
第三步:其他事件(条件 AP_ASSOCIATED/AP_DISASSOCIATED/默认)
case OS_WLAN_EVET_AP_ASSOCIATED:
case OS_WLAN_EVET_AP_DISASSOCIATED:
break;
default:
LOG_D(DRV_EXT_TAG, "event: UNKNOWN");
break;AP_ASSOCIATED/AP_DISASSOCIATED(设备接入/离开 AP)仅记录不改变链路状态;未知事件打印调试日志。
关键理解——事件如何驱动联网:底层无线驱动在检测到连接成功/断开时,调用
os_wlan_event_callback。它把 WLAN 事件翻译成网络协议栈的链路状态(os_net_linkchange)。因此应用只需关注"是否收到 JOIN 事件",协议栈会自动感知链路就绪并配置 IP。
条件走向总结(os_wlan_event_callback)
os_wlan_event_callback() 条件走向总结:
├── JOIN / AP_START → os_net_linkchange(OS_TRUE)(链路就绪)
├── LEAVE / AP_STOP → os_net_linkchange(OS_FALSE)(链路断开)
├── AP_ASSOCIATED / AP_DISASSOCIATED → 不改变链路
└── 其他 → LOG_D("event: UNKNOWN")
└── 返回 OS_SUCCESS4.7 网络设备注册与 ops(os_wlan_net_register / wlan_net_dev_ops)
函数签名
os_err_t os_wlan_net_register(struct os_wlan_device *wlan_dev, const char *name)参数 / 返回值说明
| 参数 | 类型 | 说明 |
|---|---|---|
wlan_dev | struct os_wlan_device * | WLAN 设备指针 |
name | const char * | 网络设备名称,如 "wlan0" |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 注册成功 |
OS_FAILURE | wlan_dev/ops 为空或注册失败 |
完整源码(os_wlan_net_register)
os_err_t os_wlan_net_register(struct os_wlan_device *wlan_dev, const char *name)
{
if ((wlan_dev == OS_NULL) || (wlan_dev->ops == OS_NULL))
{
return OS_FAILURE;
}
wlan_dev->net_dev.ops = &wlan_net_dev_ops;
if (os_net_device_register(&wlan_dev->net_dev, name) != OS_SUCCESS)
{
return OS_FAILURE;
}
return OS_SUCCESS;
}网络设备操作表 wlan_net_dev_ops:
const static struct os_net_device_ops wlan_net_dev_ops = {
.init = os_wlan_init,
.deinit = os_wlan_deinit,
.send = os_wlan_send,
.get_mac = os_wlan_get_mac,
.set_filter = os_wlan_set_filter,
};分步详解(os_wlan_net_register)
第一步:参数校验(条件 wlan_dev 或 ops 为空)
if ((wlan_dev == OS_NULL) || (wlan_dev->ops == OS_NULL))
{
return OS_FAILURE;
}第二步:绑定网络 ops 并注册(条件 os_net_device_register 成功)
wlan_dev->net_dev.ops = &wlan_net_dev_ops;
if (os_net_device_register(&wlan_dev->net_dev, name) != OS_SUCCESS)
{
return OS_FAILURE;
}
return OS_SUCCESS;把 wlan_net_dev_ops 挂到内嵌的 net_dev,注册为网络设备。此后协议栈通过 wlan_net_dev_ops 的 send/get_mac 等操作 WLAN 收发数据。
网络收发函数示例(os_wlan_send):
static os_err_t os_wlan_send(struct os_net_device *net_dev, uint8_t *buff, int size)
{
struct os_wlan_device *wlan_dev = (struct os_wlan_device *)net_dev;
return wlan_dev->ops->send(wlan_dev, buff, size);
}协议栈发送数据包时,os_wlan_send 把 net_dev 转回 wlan_dev,调用底层 ops->send 把数据交给无线芯片。
条件走向总结(os_wlan_net_register)
os_wlan_net_register() 条件走向总结:
├── wlan_dev 或 ops 为空 → 返回 OS_FAILURE
├── net_dev.ops = &wlan_net_dev_ops
├── os_net_device_register 失败 → 返回 OS_FAILURE
└── 成功 → 返回 OS_SUCCESS4.8 中断处理(os_wlan_irq_handler)
函数签名
void os_wlan_irq_handler(void *device)完整源码
void os_wlan_irq_handler(void *device)
{
struct os_wlan_device *wlan_dev = (struct os_wlan_device *)device;
if (device == OS_NULL)
{
return;
}
if (wlan_dev->ops->irq_handler)
{
wlan_dev->ops->irq_handler(wlan_dev);
}
}分步详解
第一步:设备指针转换(无条件执行)
struct os_wlan_device *wlan_dev = (struct os_wlan_device *)device;把 void *device 强转为 struct os_wlan_device *。此函数由中断上下文调用(无线芯片产生中断时),device 是注册中断时传入的 WLAN 设备指针。
第二步:设备非空校验(条件 device == OS_NULL)
if (device == OS_NULL)
{
return;
}device 为空则直接返回(中断函数不能轻易进入死循环或访问空指针)。
第三步:转发底层中断处理(条件 ops->irq_handler 非空)
if (wlan_dev->ops->irq_handler)
{
wlan_dev->ops->irq_handler(wlan_dev);
}若底层实现了 irq_handler 则调用,由其读取无线芯片中断状态、处理事件(如连接成功/断开、扫描完成,通常最终会回调 os_wlan_event_callback)。
条件走向总结(os_wlan_irq_handler)
os_wlan_irq_handler() 条件走向总结:
├── 强转 device 为 wlan_dev
├── device == OS_NULL → 直接返回
└── device 非空
├── ops->irq_handler 非空 → 调用 ops->irq_handler(wlan_dev)
└── ops->irq_handler 为空 → 不做处理(返回)五、使用示例
以下示例基于项目头文件
drivers/net/wlan_dev.h的接口,均含返回值检查。
示例 1:WLAN 联网(STA 模式)
#include <net/wlan_dev.h>
#include <os_task.h>
#include <string.h>
/* WLAN 事件回调:处理联网结果 */
os_err_t my_wlan_event_cb(struct os_wlan_device *wlan, os_ubase_t event, void *args)
{
switch (event)
{
case OS_WLAN_EVET_JOIN:
os_kprintf("WLAN joined network!\r\n");
break;
case OS_WLAN_EVET_LEAVE:
os_kprintf("WLAN left network!\r\n");
break;
default:
break;
}
return OS_SUCCESS;
}
void wlan_connect_demo(struct os_wlan_device *wlan)
{
/* 1. 注册事件回调(处理 JOIN/LEAVE 等) */
os_err_t ret = os_wlan_event_callback(wlan, OS_WLAN_EVET_JOIN, OS_NULL);
if (ret != OS_SUCCESS)
{
os_kprintf("Event callback failed\r\n");
return;
}
/* 2. 加入网络(异步,结果由 JOIN 事件通知) */
ret = os_wlan_join(wlan, "MyWiFi", "password123", OS_WLAN_SECURITY_WPA2_AES_PSK);
if (ret != OS_SUCCESS)
{
os_kprintf("WLAN join failed: %d\r\n", ret);
return;
}
os_kprintf("Join request sent, waiting for JOIN event\r\n");
}实际效果:调用 os_wlan_join 下发连接请求(ssid="MyWiFi"、密码、WPA2-AES)。os_wlan_event_callback 返回成功表示事件框架正常;真正的连接结果由底层驱动回调 os_wlan_event_callback(收到 OS_WLAN_EVET_JOIN)驱动。
注意:
os_wlan_event_callback是框架内部(底层驱动调用它翻译链路状态),应用若要感知事件,需由 BSP 驱动把事件转发给应用注册的回调(具体机制见 6.4)。本示例演示了os_wlan_join的正确调用方式。
示例 2:扫描周边 WiFi
#include <net/wlan_dev.h>
#include <os_memory.h>
void wlan_scan_demo(struct os_wlan_device *wlan)
{
/* 1. 扫描 1 秒,最多 20 个结果 */
struct os_wlan_scan_result *result = os_wlan_scan(wlan, 1000, 20);
if (result == OS_NULL)
{
os_kprintf("WLAN scan failed\r\n");
return;
}
/* 2. 遍历扫描结果 */
os_kprintf("Found %d networks:\r\n", result->count);
for (uint32_t i = 0; i < result->count; i++)
{
struct os_wlan_scan_info *info = &result->scan_info[i];
os_kprintf(" [%d] SSID=%s signal=%d dBm ch=%d\r\n",
i, info->ssid.val, info->signal_strength, info->channel);
}
/* 3. 释放扫描结果内存(防泄漏) */
os_wlan_scan_clean_result(wlan);
}实际效果:os_wlan_scan 扫描 1 秒、最多 20 个结果,遍历 scan_info[0..count-1] 打印 SSID、信号强度、信道。用后必须 os_wlan_scan_clean_result 释放内存(见 4.4)。
示例 3:AP 热点模式
#include <net/wlan_dev.h>
void wlan_ap_demo(struct os_wlan_device *wlan)
{
/* 1. 启动无线(AP 模式由底层驱动配置) */
os_err_t ret = os_wlan_start(wlan);
if (ret != OS_SUCCESS)
{
os_kprintf("WLAN start failed: %d\r\n", ret);
return;
}
/* 2. 设置 AP 参数(SSID/密码/安全类型,通过 info) */
wlan->info.ssid = "OneOS_AP";
wlan->info.password = "12345678";
wlan->info.security = OS_WLAN_SECURITY_WPA2_AES_PSK;
/* 3. 启动 AP(底层 ops->start 内部使用 info 配置热点) */
ret = os_wlan_start(wlan);
if (ret != OS_SUCCESS)
{
os_kprintf("WLAN AP start failed: %d\r\n", ret);
return;
}
os_kprintf("AP '%s' started\r\n", wlan->info.ssid);
}实际效果:启动无线并配置 AP 参数(SSID、密码、安全类型)。底层 ops->start 根据 wlan->info 开启热点。AP 启动成功后,底层驱动回调 os_wlan_event_callback 收到 OS_WLAN_EVET_AP_START → 链路就绪,其他设备可接入。
示例 4:离开网络
#include <net/wlan_dev.h>
void wlan_leave_demo(struct os_wlan_device *wlan)
{
os_err_t ret = os_wlan_leave(wlan);
if (ret != OS_SUCCESS)
{
os_kprintf("WLAN leave failed: %d\r\n", ret);
return;
}
os_kprintf("WLAN left network\r\n");
}实际效果:os_wlan_leave 断开当前连接。断开后底层驱动回调 os_wlan_event_callback 收到 OS_WLAN_EVET_LEAVE → os_net_linkchange(OS_FALSE) 通知协议栈链路断开。
六、更换无线芯片/模组(WLAN 驱动移植)—— 全局视角
本节从全局视角讲解:当你要换一款无线芯片/模组(或换 MCU 导致无线驱动失效)时,OneOS 的 WLAN 驱动要做什么才能在新芯片上跑起来。核心结论与 5.2~5.34 一致:应用层与框架层完全不用动,只需要新写/移植 BSP 无线驱动。
6.1 认识 BSP 层驱动:drv_wlan.c 等
BSP 无线驱动通常位于厂商 HAL 目录(如 beken 的 drivers/hal/beken/drivers/wlan/drv_wlan.c),实现 struct os_wlan_device_ops + 网络对接 + 注册。它需要:
(1)实现 struct os_wlan_device_ops 的关键函数
static const struct os_wlan_device_ops my_wlan_ops = {
.join = my_wlan_join,
.check_join_status = my_wlan_check_join_status,
.leave = my_wlan_leave,
.wlan_scan = my_wlan_scan,
.wlan_scan_stop = my_wlan_scan_stop,
.start = my_wlan_start,
.stop = my_wlan_stop,
.irq_handler = my_wlan_irq_handler,
.init = my_wlan_init,
.deinit = my_wlan_deinit,
.send = my_wlan_send,
.get_mac = my_wlan_get_mac,
.set_filter = my_wlan_set_filter,
};(2)注册 WLAN 设备
static struct os_wlan_device my_wlan;
void my_wlan_drv_init(void)
{
my_wlan.ops = &my_wlan_ops;
my_wlan.flags = OS_WLAN_FLAG_STA_ONLY;
os_wlan_net_register(&my_wlan, "wlan0");
}用 os_wlan_net_register 注册为网络设备 "wlan0"(见 4.7)。
(3)事件上报:无线芯片检测到连接成功/断开时,调用 os_wlan_event_callback(&my_wlan, OS_WLAN_EVET_JOIN, OS_NULL) 通知框架(见 4.6)。
(4)"根据所选芯片决定"是怎么决定的?:WLAN 芯片驱动通常随芯片厂商目录编译(如 beken 系列),通过厂商 Kconfig/weave.yaml 选择,机制与 5.34 的 LCD 屏选择类似。
6.2 移植前的全局视角:分层全景图
回顾 WLAN 设备的完整分层(本书 1.1 节已详解):应用层 → WLAN 框架层(wlan_dev.c)→ BSP 无线驱动 → 硬件层。
移植的关键洞察:
- 只有 BSP 无线驱动和具体芯片强相关(依赖芯片固件、SDIO/USB/SPI 接口、无线协议栈)。
- 框架层和应用层与具体芯片无关(只依赖
wlan_dev.h定义的抽象接口)。 - 所以"换无线芯片"本质上 = 新写/移植 BSP 无线驱动(实现
struct os_wlan_device_ops13 个函数 + 注册 + 事件上报)。
6.3 移植需要提供的"接口契约"
要移植,必须先满足 BSP 层与框架层之间的契约——也就是 struct os_wlan_device_ops(见 2.5 节)的关键函数:
| ops 函数 | 需实现的能力 |
|---|---|
init/deinit | 初始化/反初始化无线芯片(固件下载、SDIO/USB/SPI 接口初始化) |
start/stop | 启动/停止无线(配置 STA/AP 模式) |
join/leave/check_join_status | 连接/断开/查询 AP |
wlan_scan/wlan_scan_stop | 扫描周边网络 |
send/get_mac/set_filter | 收发数据包、取 MAC、设过滤(供协议栈) |
irq_handler | 无线芯片中断处理 |
此外还需要:
- 网络对接:通过
os_wlan_net_register注册(见 4.7),实现wlan_net_dev_ops调用的底层收发。 - 事件上报:连接/断开/扫描完成时调用
os_wlan_event_callback(见 4.6)。 - 无线协议栈:多数无线芯片自带固件/协议栈(如博通),BSP 需集成其 SDK。
6.4 移植的标准流程(5 步)
以"为一块无线芯片写 WLAN 驱动"为例:
第 1 步:定义 WLAN 设备实例并绑定 ops
struct my_wlan_dev
{
struct os_wlan_device wlan;
/* 芯片私有数据(固件句柄、接口等) */
void *chip;
};
static struct my_wlan_dev g_wlan;
static const struct os_wlan_device_ops my_wlan_ops = {
.join = my_wlan_join,
.leave = my_wlan_leave,
.start = my_wlan_start,
.stop = my_wlan_stop,
/* 其余函数(check_join_status/wlan_scan/send/get_mac 等)同样绑定 */
};第 2 步:实现核心 ops 函数
static os_err_t my_wlan_join(struct os_wlan_device *wlan_dev)
{
struct my_wlan_dev *dev = (struct my_wlan_dev *)wlan_dev;
/* 用 wlan_dev->info.ssid/password/security 连接 AP */
int ret = my_chip_connect(dev->chip, wlan_dev->info.ssid,
wlan_dev->info.password, wlan_dev->info.security);
return (ret == 0) ? OS_SUCCESS : OS_EIO;
}
static os_err_t my_wlan_scan(struct os_wlan_device *wlan, uint32_t msec, struct os_wlan_scan_result *result)
{
/* 扫描并把结果填入 result->scan_info[0..count-1] */
return OS_SUCCESS;
}第 3 步:注册 WLAN 设备并集成网络
void my_wlan_drv_init(void)
{
g_wlan.wlan.ops = &my_wlan_ops;
g_wlan.wlan.flags = OS_WLAN_FLAG_STA_ONLY;
os_wlan_net_register(&g_wlan.wlan, "wlan0");
}第 4 步:事件上报
在无线驱动检测到连接成功/断开/扫描完成时调用:
void my_chip_event_handler(int event)
{
switch (event)
{
case MY_CHIP_JOINED:
os_wlan_event_callback(&g_wlan.wlan, OS_WLAN_EVET_JOIN, OS_NULL);
break;
case MY_CHIP_LEFT:
os_wlan_event_callback(&g_wlan.wlan, OS_WLAN_EVET_LEAVE, OS_NULL);
break;
}
}第 5 步:验证
用本节"示例 1(联网)"验证能连上路由器;"示例 2(扫描)"验证能扫到网络;"示例 3(AP)"验证能开热点。
6.5 移植检查清单(快速自查)
| 检查项 | 是否满足 |
|---|---|
struct os_wlan_device_ops 关键函数已实现并绑定 | ☐ |
os_wlan_net_register 已注册为网络设备 | ☐ |
连接/断开事件已回调 os_wlan_event_callback | ☐ |
扫描结果正确填入 scan_result->scan_info | ☐ |
send/get_mac 已实现供协议栈收发 | ☐ |
| 无线芯片固件/SDK 已集成 | ☐ |
6.6 移植的价值与注意事项
价值:一旦 BSP 无线驱动移植完成,应用层代码一行不改即可在不同无线芯片间复用。
注意事项:
- 事件上报是关键:连接成功/断开必须回调
os_wlan_event_callback,否则协议栈感知不到链路状态,无法获取 IP。 send与协议栈对接:os_wlan_send把协议栈数据包交给ops->send,必须能正确处理 lwIP 等协议栈发出的包。- 内存管理:
os_wlan_scan分配的结果内存由应用os_wlan_scan_clean_result释放,BSP 的wlan_scan只负责填充结果,不重复分配。
📝 本节小结
核心要点回顾
- 内嵌 Net 设备:
os_wlan_device内嵌os_net_device,通过os_wlan_net_register注册为网络设备,与协议栈无缝对接。 - STA/AP 双模式:
start/stop启动/停止无线,join/leave连接/断开 AP,flags标记仅 STA/仅 AP。 - 扫描功能:
os_wlan_scan分配连续内存存结果,os_wlan_scan_clean_result释放,用后必须清理防泄漏。 - 安全类型:
os_wlan_security_t覆盖 OPEN/WEP/WPA/WPA2(PSK/ENT),OS_WLAN_SECURITY_MAX是校验哨兵。 - 事件联动:
os_wlan_event_callback把 JOIN/AP_START 映射为链路就绪(os_net_linkchange(TRUE)),LEAVE/AP_STOP 映射为断开。 - 加入是异步的:
os_wlan_join只下发请求,连接成功由事件OS_WLAN_EVET_JOIN通知。 - 更换无线芯片移植(见第六章):移植核心 = 实现
struct os_wlan_device_ops+ 注册 + 事件上报;应用层与框架层不用改。
关键易错点速查
| 易错点 | 正确做法 |
|---|---|
以为 os_wlan_join 返回成功就是联网完成 | 返回成功仅表示请求已下发 → 连接成功由 OS_WLAN_EVET_JOIN 事件通知 |
| 扫描后不释放结果内存 | os_wlan_scan 内部 os_calloc 分配 → 用后 os_wlan_scan_clean_result 释放 |
security 传入非法值 | 会触发 security >= MAX 校验返回 OS_EIO → 用枚举定义的安全类型 |
| 移植时漏掉事件上报 | 协议栈感知不到链路状态、拿不到 IP → 必须回调 os_wlan_event_callback |
移植时 send 未对接协议栈 | 数据包发不出去 → 必须实现 ops->send 并正确转发 |
| 混淆 STA 和 AP 模式 | start 后需设置 info(SSID/密码/安全)并配置模式 → 按场景选 STA 或 AP |
| 遍历扫描结果越界 | 用 result->count 限定循环次数 → 别用 max_num 当实际数量 |
下一步
- 本小节是设备驱动详解的最后一节。至此,第 5 章设备驱动详解已全部完成,你可以回顾 5.1 设备驱动框架 巩固整体框架,或进入其他章节继续学习。