sockert组成部分_IOT-OS之RT-Thread(十六)--- WLAN管理框架 + AP6181(BCM43362) WiFi模块

1、WLAN管理框架简介

随着物联网快速发展,愈来愈多的嵌入式设备上搭载了 WIFI 无线网络设备,为了可以管理 WIFI 网络设备,RT-Thread 引入了 WLAN 设备管理框架。这套框架是 RT-Thread 开发的一套用于管理 WIFI 的中间件:对下链接具体的 WIFI 驱动,控制 WIFI 的链接、断开、扫描等操做;对上承载不一样的应用,为应用提供 WIFI 控制、事件、数据导流等操做,为上层应用提供统一的 WIFI 控制接口。html

WLAN 框架主要由四个部分组成:Device 驱动接口层,为 WLAN 框架提供统一的调用接口;Manage 管理层为用户提供 WIFI 扫描、链接、断线重连等具体功能;Protocol 协议负责处理 WIFI 上产生的网络数据流,可根据不一样的使用场景挂载不一样网络协议栈(好比 LWIP );Config配置层能够保存 WIFI 配置参数,为用户提供自动链接服务(可从Flash读取曾经链接过的热点配置信息)。WIFI 框架层次图示以下:

WLAN管理框架各层功能简介以下:git

APP应用层:是基于 WLAN 框架的具体应用,如 WiFi 相关的 Shell 命令;

Airkiss / Voice 配网层:提供无线配网和声波配网等功能;

WLAN Manager 管理层:可以对 WLAN 设备进行控制和管理,具有设置模式、链接热点、断开热点、启动热点、扫描热点等 WLAN 控制相关的功能,还提供断线重连、自动切换热点等管理功能;

WLAN Protocol 协议层:将数据流递交给具体网络协议进行解析,用户能够指定使用不一样的协议进行通讯(本文使用LwIP协议);

WLAN Config 参数管理层:管理链接成功的热点信息及密码,并写入非易失的存储介质中,能够为用户提供自动链接曾连热点的服务;

WLAN Device 驱动接口层:对接具体 WLAN 硬件(本文使用AP6181 WIFI 模块),为管理层提供统一的调用接口。

在WLAN Protocol 与 APP 层之间还应包含网络协议层(好比LwIP),甚至是套接字抽象层SAL(包括网络设备无关层netdev),这些并无表如今上面的WLAN 框架图中,下文介绍LwIP协议栈移植时再详说。github

2、WLAN Device实现与AP6181 WLAN驱动移植

2.1 WLAN Device驱动接口层

WLAN设备数据结构

// rt-thread-4.0.1\components\drivers\wlan\wlan_dev.h

struct rt_wlan_device

{

struct rt_device device;

rt_wlan_mode_t mode;

struct rt_mutex lock;

struct rt_wlan_dev_event_desc handler_table[RT_WLAN_DEV_EVT_MAX][RT_WLAN_DEV_EVENT_NUM];

rt_wlan_pormisc_callback_t pormisc_callback;

const struct rt_wlan_dev_ops *ops;

rt_uint32_t flags;

void *prot;

void *user_data;

};

typedef enum

{

RT_WLAN_NONE,

RT_WLAN_STATION,

RT_WLAN_AP,

RT_WLAN_MODE_MAX

} rt_wlan_mode_t;

struct rt_wlan_dev_event_desc

{

rt_wlan_dev_event_handler handler;

void *parameter;

};

typedef void (*rt_wlan_dev_event_handler)(struct rt_wlan_device *device, rt_wlan_dev_event_t event, struct rt_wlan_buff *buff, void *parameter);

typedef void (*rt_wlan_pormisc_callback_t)(struct rt_wlan_device *device, void *data, int len);

struct rt_wlan_dev_ops

{

rt_err_t (*wlan_init)(struct rt_wlan_device *wlan);

rt_err_t (*wlan_mode)(struct rt_wlan_device *wlan, rt_wlan_mode_t mode);

rt_err_t (*wlan_scan)(struct rt_wlan_device *wlan, struct rt_scan_info *scan_info);

rt_err_t (*wlan_join)(struct rt_wlan_device *wlan, struct rt_sta_info *sta_info);

rt_err_t (*wlan_softap)(struct rt_wlan_device *wlan, struct rt_ap_info *ap_info);

rt_err_t (*wlan_disconnect)(struct rt_wlan_device *wlan);

rt_err_t (*wlan_ap_stop)(struct rt_wlan_device *wlan);

rt_err_t (*wlan_ap_deauth)(struct rt_wlan_device *wlan, rt_uint8_t mac[]);

rt_err_t (*wlan_scan_stop)(struct rt_wlan_device *wlan);

int (*wlan_get_rssi)(struct rt_wlan_device *wlan);

rt_err_t (*wlan_set_powersave)(struct rt_wlan_device *wlan, int level);

int (*wlan_get_powersave)(struct rt_wlan_device *wlan);

rt_err_t (*wlan_cfg_promisc)(struct rt_wlan_device *wlan, rt_bool_t start);

rt_err_t (*wlan_cfg_filter)(struct rt_wlan_device *wlan, struct rt_wlan_filter *filter);

rt_err_t (*wlan_set_channel)(struct rt_wlan_device *wlan, int channel);

int (*wlan_get_channel)(struct rt_wlan_device *wlan);

rt_err_t (*wlan_set_country)(struct rt_wlan_device *wlan, rt_country_code_t country_code);

rt_country_code_t (*wlan_get_country)(struct rt_wlan_device *wlan);

rt_err_t (*wlan_set_mac)(struct rt_wlan_device *wlan, rt_uint8_t mac[]);

rt_err_t (*wlan_get_mac)(struct rt_wlan_device *wlan, rt_uint8_t mac[]);

int (*wlan_recv)(struct rt_wlan_device *wlan, void *buff, int len);

int (*wlan_send)(struct rt_wlan_device *wlan, void *buff, int len);

};

结构体 rt_wlan_device 继承自设备基类 rt_device,天然须要将其注册到 I/O 设备管理层。rt_wlan_device 成员还包括WLAN设备工做模式(Access Point模式仍是Station模式)、WLAN设备访问互斥锁、WLAN事件回调函数组、WLAN混杂模式回调函数、须要底层驱动实现并注册的WLAN接口函数集合rt_wlan_dev_ops、WLAN标识位(用于标识工做模式或自动链接状态等)、WLAN设备使用的网络协议栈信息、私有数据等。web

WLAN接口函数及设备注册过程

WLAN设备驱动(这里指的是AP6181 WLAN驱动)须要向WLAN管理框架注册接口函数集合rt_wlan_dev_ops,以便WLAN管理框架对外提供的接口能正常工做,这个函数集合rt_wlan_dev_ops是如何注册到WLAN管理框架的呢?算法

// rt-thread-4.0.1\components\drivers\wlan\wlan_dev.c

rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data)

{

rt_err_t err = RT_EOK;

if ((wlan == RT_NULL) || (name == RT_NULL) || (ops == RT_NULL))

......

rt_memset(wlan, 0, sizeof(struct rt_wlan_device));

#ifdef RT_USING_DEVICE_OPS

wlan->device.ops = &wlan_ops;

#else

......

#endif

wlan->device.user_data = RT_NULL;

wlan->device.type = RT_Device_Class_NetIf;

wlan->ops = ops;

wlan->user_data = user_data;

wlan->flags = flag;

err = rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR);

return err;

}

#ifdef RT_USING_DEVICE_OPS

const static struct rt_device_ops wlan_ops =

{

_rt_wlan_dev_init,

RT_NULL,

RT_NULL,

RT_NULL,

RT_NULL,

_rt_wlan_dev_control

};

#endif

从函数rt_wlan_dev_register 的代码能够看出,该函数不只完成了将函数集合rt_wlan_dev_ops注册到WLAN管理框架的工做(经过参数传递),还完成了将函数集合wlan_ops(经过调用rt_wlan_dev_ops接口实现的rt_device_ops接口)注册到 I/O 设备管理框架的工做,注册的WLAN设备类型为网络接口设备RT_Device_Class_NetIf。编程

完成WLAN设备向WLAN管理框架和 I/O 设备管理框架的注册后,就可使用 I/O 设备管理层接口或WLAN Device层提供的接口访问WLAN设备了,咱们先看下WLAN设备向 I/O 设备管理层注册的函数集合 wlan_ops 的实现代码:api

// rt-thread-4.0.1\components\drivers\wlan\wlan_dev.c

static rt_err_t _rt_wlan_dev_init(rt_device_t dev)

{

struct rt_wlan_device *wlan = (struct rt_wlan_device *)dev;

rt_err_t result = RT_EOK;

rt_mutex_init(&wlan->lock, "wlan_dev", RT_IPC_FLAG_FIFO);

if (wlan->ops->wlan_init)

result = wlan->ops->wlan_init(wlan);

......

return result;

}

static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)

{

struct rt_wlan_device *wlan = (struct rt_wlan_device *)dev;

rt_err_t err = RT_EOK;

WLAN_DEV_LOCK(wlan);

switch (cmd)

{

case RT_WLAN_CMD_MODE:

{

rt_wlan_mode_t mode = *((rt_wlan_mode_t *)args);

if (wlan->ops->wlan_mode)

err = wlan->ops->wlan_mode(wlan, mode);

break;

}

case RT_WLAN_CMD_SCAN:

{

struct rt_scan_info *scan_info = args;

if (wlan->ops->wlan_scan)

err = wlan->ops->wlan_scan(wlan, scan_info);

break;

}

case RT_WLAN_CMD_JOIN:

{

struct rt_sta_info *sta_info = args;

if (wlan->ops->wlan_join)

err = wlan->ops->wlan_join(wlan, sta_info);

break;

}

case RT_WLAN_CMD_SOFTAP:

{

struct rt_ap_info *ap_info = args;

if (wlan->ops->wlan_softap)

err = wlan->ops->wlan_softap(wlan, ap_info);

break;

}

case RT_WLAN_CMD_DISCONNECT:

{

if (wlan->ops->wlan_disconnect)

err = wlan->ops->wlan_disconnect(wlan);

break;

}

case RT_WLAN_CMD_AP_STOP:

{

if (wlan->ops->wlan_ap_stop)

err = wlan->ops->wlan_ap_stop(wlan);

break;

}

case RT_WLAN_CMD_AP_DEAUTH:

{

if (wlan->ops->wlan_ap_deauth)

err = wlan->ops->wlan_ap_deauth(wlan, args);

break;

}

case RT_WLAN_CMD_SCAN_STOP:

{

if (wlan->ops->wlan_scan_stop)

err = wlan->ops->wlan_scan_stop(wlan);

break;

}

case RT_WLAN_CMD_GET_RSSI:

{

int *rssi = args;

if (wlan->ops->wlan_get_rssi)

*rssi = wlan->ops->wlan_get_rssi(wlan);

break;

}

case RT_WLAN_CMD_SET_POWERSAVE:

{

int level = *((int *)args);

if (wlan->ops->wlan_set_powersave)

err = wlan->ops->wlan_set_powersave(wlan, level);

break;

}

case RT_WLAN_CMD_GET_POWERSAVE:

{

int *level = args;

if (wlan->ops->wlan_get_powersave)

*level = wlan->ops->wlan_get_powersave(wlan);

break;

}

case RT_WLAN_CMD_CFG_PROMISC:

{

rt_bool_t start = *((rt_bool_t *)args);

if (wlan->ops->wlan_cfg_promisc)

err = wlan->ops->wlan_cfg_promisc(wlan, start);

break;

}

case RT_WLAN_CMD_CFG_FILTER:

{

struct rt_wlan_filter *filter = args;

if (wlan->ops->wlan_cfg_filter)

err = wlan->ops->wlan_cfg_filter(wlan, filter);

break;

}

case RT_WLAN_CMD_SET_CHANNEL:

{

int channel = *(int *)args;

if (wlan->ops->wlan_set_channel)

err = wlan->ops->wlan_set_channel(wlan, channel);

break;

}

case RT_WLAN_CMD_GET_CHANNEL:

{

int *channel = args;

if (wlan->ops->wlan_get_channel)

*channel = wlan->ops->wlan_get_channel(wlan);

break;

}

case RT_WLAN_CMD_SET_COUNTRY:

{

rt_country_code_t country = *(rt_country_code_t *)args;

if (wlan->ops->wlan_set_country)

err = wlan->ops->wlan_set_country(wlan, country);

break;

}

case RT_WLAN_CMD_GET_COUNTRY:

{

rt_country_code_t *country = args;

if (wlan->ops->wlan_get_country)

*country = wlan->ops->wlan_get_country(wlan);

break;

}

case RT_WLAN_CMD_SET_MAC:

{

rt_uint8_t *mac = args;

if (wlan->ops->wlan_set_mac)

err = wlan->ops->wlan_set_mac(wlan, mac);

break;

}

case RT_WLAN_CMD_GET_MAC:

{

rt_uint8_t *mac = args;

if (wlan->ops->wlan_get_mac)

err = wlan->ops->wlan_get_mac(wlan, mac);

break;

}

default:

break;

}

WLAN_DEV_UNLOCK(wlan);

return err;

}

函数集合 wlan_ops 的实现最终都是靠调用WLAN设备驱动提供的函数集合rt_wlan_dev_ops,并且WLAN设备的管理配置主要靠函数rt_device_control 经过发送不一样的命令码和参数实现。WLAN Device层提供的接口函数又是经过调用函数集合 wlan_ops 实现的,下面给出WLAN Device层对外提供的接口函数声明:数组

// rt-thread-4.0.1\components\drivers\wlan\wlan_dev.h

/* wlan device init */

rt_err_t rt_wlan_dev_init(struct rt_wlan_device *device, rt_wlan_mode_t mode);

/* wlan device station interface */

rt_err_t rt_wlan_dev_connect(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len);

rt_err_t rt_wlan_dev_disconnect(struct rt_wlan_device *device);

int rt_wlan_dev_get_rssi(struct rt_wlan_device *device);

/* wlan device ap interface */

rt_err_t rt_wlan_dev_ap_start(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len);

rt_err_t rt_wlan_dev_ap_stop(struct rt_wlan_device *device);

rt_err_t rt_wlan_dev_ap_deauth(struct rt_wlan_device *device, rt_uint8_t mac[6]);

/* wlan device scan interface */

rt_err_t rt_wlan_dev_scan(struct rt_wlan_device *device, struct rt_wlan_info *info);

rt_err_t rt_wlan_dev_scan_stop(struct rt_wlan_device *device);

/* wlan device mac interface */

rt_err_t rt_wlan_dev_get_mac(struct rt_wlan_device *device, rt_uint8_t mac[6]);

rt_err_t rt_wlan_dev_set_mac(struct rt_wlan_device *device, rt_uint8_t mac[6]);

/* wlan device powersave interface */

rt_err_t rt_wlan_dev_set_powersave(struct rt_wlan_device *device, int level);

int rt_wlan_dev_get_powersave(struct rt_wlan_device *device);

/* wlan device event interface */

rt_err_t rt_wlan_dev_register_event_handler(struct rt_wlan_device *device, rt_wlan_dev_event_t event, rt_wlan_dev_event_handler handler, void *parameter);

rt_err_t rt_wlan_dev_unregister_event_handler(struct rt_wlan_device *device, rt_wlan_dev_event_t event, rt_wlan_dev_event_handler handler);

void rt_wlan_dev_indicate_event_handle(struct rt_wlan_device *device, rt_wlan_dev_event_t event, struct rt_wlan_buff *buff);

/* wlan device promisc interface */

rt_err_t rt_wlan_dev_enter_promisc(struct rt_wlan_device *device);

rt_err_t rt_wlan_dev_exit_promisc(struct rt_wlan_device *device);

rt_err_t rt_wlan_dev_set_promisc_callback(struct rt_wlan_device *device, rt_wlan_pormisc_callback_t callback);

void rt_wlan_dev_promisc_handler(struct rt_wlan_device *device, void *data, int len);

/* wlan device filter interface */

rt_err_t rt_wlan_dev_cfg_filter(struct rt_wlan_device *device, struct rt_wlan_filter *filter);

/* wlan device channel interface */

rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel);

int rt_wlan_dev_get_channel(struct rt_wlan_device *device);

/* wlan device country interface */

rt_err_t rt_wlan_dev_set_country(struct rt_wlan_device *device, rt_country_code_t country_code);

rt_country_code_t rt_wlan_dev_get_country(struct rt_wlan_device *device);

/* wlan device datat transfer interface */

rt_err_t rt_wlan_dev_report_data(struct rt_wlan_device *device, void *buff, int len);

/* wlan device register interface */

rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name,

const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data);

WLAN Device层提供的这些接口函数咱们虽然能够在应用程序中直接调用,但函数参数有不少结构体类型,在调用这些接口函数前,须要先构造接口函数参数须要的结构体,这就给函数调用带来了不便。WLAN Device层上面的WLAN Manager 层则对这些接口函数进行了再次封装,使用一些全局变量保存必要的信息,简化了参数的构造,咱们直接调用WLAN Manager 层提供的接口函数更加方便友好,这些接口函数在下文介绍。缓存

2.2 AP6181 WLAN驱动移植

Pandora开发板的程序源码包并无为咱们提供AP6181 WLAN驱动的源码,而是以库文件的形式给出的,因此这里也无法分析AP6181 WLAN驱动的实现原理,只能根据 SDIO 设备管理框架与WLAN 管理框架对WLAN设备驱动的要求推测一些AP6181 WLAN驱动移植时应实现或调用的函数。这里忍不住吐槽一下提供Pandora开发板 AP6181 WLAN驱动库文件的同窗,起码应该给出一些关于AP6181 WLAN驱动库文件如何使用、须要为其实现哪些接口函数、对外提供哪些接口函数、简单的实现原理之类的说明文档,如今缺乏这些信息为WLAN驱动移植和调试带来了很大的不便。sass

AP6181 WLAN固件配置

从前篇博客:SDIO设备对象管理 + AP6181(BCM43362) WiFi模块了解到,AP6181 WIFI 模组内部是须要运行WLAN固件程序的,AP6181 内部可能没有ROM空间,这就须要咱们将AP6181 内运行的WLAN固件程序存放到主控端的Flash 空间内。在使用WLAN设备前,由WLAN驱动程序负责将Host 端Flash内存放的WLAN固件读取并传送到AP6181 模组内,以便AP6181 WIFI 模组能正常工做(好比完成WIFI数据帧与以太网数据帧之间的转换)。

这里提醒一点,本文使用的AP6181的WLAN固件与驱动都是从Pandora开发板提供的源码包中得到的,且因为WLAN固件与驱动都是以库文件的形式提供的,对运行环境(好比RT-Thread版本)变动比较敏感,所以最好选择与本身使用的RT-Thread版本一致的 Pandora IOT 源码包。好比我使用的是RT-Thread 4.0.1,正点原子官网给的Pandora IOT 源码包默认的基于RT-Thread 4.0.0开发的,我就须要到GitHub 下载基于RT-Thread 4.0.1 版本的Pandora IOT 源码包(本文使用的是Release 1.2.0版本)。下文中使用的AP6181 WLAN固件与驱动都是从Pandora IOT Board Release 1.2.0版本源码包拷贝来的。

AP6181 WLAN固件所在路径:

.\IoT_Board\examples\16_iot_wifi_manager\bin\wifi_image_1.0.rbl

咱们须要先将该WLAN固件放入Flash(Pandora上的W25Q128芯片)的 wifi_image 分区,本文使用的工程文件是基于博客:FAL分区管理与easyflash变量管理中完成FAL与Easyflash组件移植后的工程文件为基础的。在上面的博客中已经FAL(Flash Abstraction Layer)的实现原理及接口函数,并且在移植FAL组件时配置到分区表也包括wifi_image 分区,这里能够直接该分区存储 AP6181 WLAN 固件镜像文件。

咱们如何将AP6181 WLAN固件(wifi_image_1.0.rbl)放到W25Q128 Flash内的wifi_image 分区呢?能够参考下面的文档:

.\IoT_Board\docs\UM3001-RT-Thread-IoT Board WIFI 模块固件下载手册.pdf

比较简单的方法是先将WLAN固件放到SD卡以下目录中:

/SYSTEM/WIFI/wifi_image_1.0.rbl

而后将SD卡插入到Pandora开发板的SD卡插槽,将综合例程文件(以下路径)烧录到Pandora开发板中:

.\IoT_Board\examples\30_iot_board_demo\bin\all.bin

综合例程文件烧录完成后,Pandora开发板检测到WLAN固件,会自动执行读取、校验、升级WLAN固件的操做,Pandora开发板的LCD也会显示相应的升级信息(若是wifi_image

分区已存在WLAN固件,且与放入SD卡中的WLAN固件版本一致,则不会有相应的加载或升级操做)。

接下来就是AP6181 WLAN驱动负责将存储在W25Q128 Flash wifi_image 分区的WLAN固件读取出来,并经过SDIO总线传输到AP6181 模组内。因为WLAN驱动是以库文件的形式提供的,咱们直接从Pandora源码包将WLAN驱动库文件和WLAN驱动移植文件复制到咱们的工程中使用,这些文件在Pandora源码包中的路径和复制到咱们工程目录的路径以下:

// Pandora IOT Board Release 1.2.0中WLAN驱动库文件和WLAN驱动移植文件路径

.\IoT_Board\libraries\wifi\libwifi_6181_0.2.5_armcm4_gcc.a

.\IoT_Board\libraries\wifi\libwifi_6181_0.2.5_armcm4_iar.a

.\IoT_Board\libraries\wifi\libwifi_6181_0.2.5_armcm4_keil.lib

.\IoT_Board\libraries\wifi\SConscript

.\IoT_Board\drivers\drv_wlan.h

.\IoT_Board\drivers\drv_wlan.c

// WLAN驱动库文件和WLAN驱动移植文件拷贝到咱们工程中的目标路径

.\RT-Thread_Projects\libraries\wifi\libwifi_6181_0.2.5_armcm4_gcc.a

.\RT-Thread_Projects\libraries\wifi\libwifi_6181_0.2.5_armcm4_iar.a

.\RT-Thread_Projects\libraries\wifi\libwifi_6181_0.2.5_armcm4_keil.lib

.\RT-Thread_Projects\libraries\wifi\SConscript

.\RT-Thread_Projects\libraries\HAL_Drivers\drv_wlan.h

.\RT-Thread_Projects\libraries\HAL_Drivers\drv_wlan.c

WLAN驱动库文件和WLAN驱动移植文件复制到咱们工程中后,须要能编译进咱们的工程,所以须要修改SConscript文件和SConstruct文件,将咱们拷贝过来的文件添加进编译脚本,新增编译代码以下:

// .\RT-Thread_Projects\libraries\HAL_Drivers\SConscript

......

# add wlan driver code

if GetDepen

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值