参考官网
确认流程通过浏览源码、增加打印以及查看打印来确认,如果遇到乐鑫SDK的函数,不作详细说明。
platform\mcu\esp8266\bsp\entry.c
static kinit_t kinit = {
.argc = 0,
.argv = NULL,
.cli_enable = 1
};
static void app_entry(void *arg)
{
aos_components_init(&kinit);
#ifndef AOS_BINS
application_start(kinit.argc, kinit.argv); /* jump to app/example entry */
#endif
}
extern uart_dev_t uart_0;
extern hal_wifi_module_t aos_wifi_esp8266;
void user_init(void)
{
int ret = 0;
extern int32_t hal_uart_init(uart_dev_t *uart);
extern void key_gpio_init(void);
key_gpio_init();
hal_uart_init(&uart_0);
hal_wifi_register_module(&aos_wifi_esp8266); //全局,hal_wifi_module_t *module
ret = hal_wifi_init();
if (ret){
printf("waring: wifi init fail ret is %d \r\n", ret);
}
#if defined(SUPPORT_SINGAPORE_DOMAIN)
aos_task_new("main", app_entry, 0, 7.5*1024);
#elif defined(ESP8266_CHIPSET)
aos_task_new("main", app_entry, 0, 2*1024);
#else
aos_task_new("main", app_entry, 0, 6*1024);
#endif
}
1、user_init的工作,注册 aos_wifi_esp8266 模块,然后初始化,创建app_entry任务。
2、app_entry 做了一些组建的初始化工作,然后application_start启动我们的sample
hal_wifi_module_t aos_wifi_esp8266 = {
.base.name = "aos_wifi_esp8266",
.init = wifi_init,
.get_mac_addr = wifi_get_mac_addr,
.start = wifi_start,
.start_adv = wifi_start_adv,
.get_ip_stat = get_ip_stat,
.get_link_stat = get_link_stat,
.start_scan = start_scan,
.start_scan_adv = start_scan_adv,
.power_off = power_off,
.power_on = power_on,
.suspend = suspend,
.suspend_station = suspend_station,
.suspend_soft_ap = suspend_soft_ap,
.set_channel = set_channel,
.start_monitor = start_monitor,
.stop_monitor = stop_monitor,
.start_ap = start_ap,
.stop_ap = stop_ap,
.register_monitor_cb = register_monitor_cb,
.register_wlan_mgnt_monitor_cb = register_wlan_mgnt_monitor_cb,
.wlan_send_80211_raw_frame = wlan_send_80211_raw_frame,
.get_wireless_info = get_wireless_info,
};
void hal_wifi_register_module(hal_wifi_module_t *module)
{
dlist_add_tail(&module->base.list, &g_wifi_module);
}
int hal_wifi_init(void)
{
int err = 0;
dlist_t *t;
/* do low level init */
dlist_for_each(t, &g_wifi_module) {
hal_wifi_module_t *m = (hal_wifi_module_t *)t;
#if ((WIFI_CONFIG_SUPPORT_LOWPOWER > 0) && (WIFI_CONFIG_LISTENSET_BINIT > 0))
m->set_listeninterval(m, WIFI_CONFIG_LISTEN_INTERVAL);
#endif
m->init(m);
#if ((WIFI_CONFIG_SUPPORT_LOWPOWER > 0) && (WIFI_CONFIG_LISTENSET_BINIT == 0))
m->set_listeninterval(m, WIFI_CONFIG_LISTEN_INTERVAL);
#endif
}
return err;
}
static int wifi_init(hal_wifi_module_t *m)
{
static int inited;
if (inited) {
printf("Wifi already started.\r\n");
return 0;
}
wifi_station_set_auto_connect(false); //默认不连接保存的AP
set_on_station_connect(on_wifi_connect); //设置连接上后的回调,就是一句打印
set_on_station_disconnect(on_wifi_disconnect); //设置连接断开后的回调
init_esp_wifi();
inited = 1;
printf("Wifi init success!!\n");
return 0;
};
void ICACHE_FLASH_ATTR set_on_station_first_connect(wifi_state_cb_t cb){
on_station_first_connect = cb;
}
void ICACHE_FLASH_ATTR set_on_station_connect(wifi_state_cb_t cb){
on_station_connect = cb;
}
void ICACHE_FLASH_ATTR set_on_station_disconnect(wifi_disco_cb_t cb){
on_station_disconnect = cb;
}
void ICACHE_FLASH_ATTR set_on_client_connect(wifi_state_cb_t cb){
on_client_connect = cb;
}
void ICACHE_FLASH_ATTR set_on_client_disconnect(wifi_state_cb_t cb){
on_client_disconnect = cb;
}
LOCAL void ICACHE_FLASH_ATTR on_wifi_connect(){
printf("Wifi connected.\n");
}
LOCAL void ICACHE_FLASH_ATTR on_wifi_disconnect(uint8_t reason){
hal_wifi_module_t *m = hal_wifi_get_default_module();
printf("Wifi disconnected (reason: %d)\n", reason);
if (m->ev_cb && m->ev_cb->stat_chg) {
m->ev_cb->stat_chg(m, NOTIFY_STATION_DOWN, NULL);
}
}
WIFI_MODE ICACHE_FLASH_ATTR init_esp_wifi(){
wifi_set_event_handler_cb(wifi_event_handler_cb); //注册消息回调
WIFI_MODE mode = wifi_get_opmode_default();
wifi_set_mode(mode);
return mode;
}
int aos_components_init(kinit_t *kinit)
{
#ifdef AOS_COMP_VFS
vfs_init();
#endif
...
ulog_init();
kv_init();
vfs_device_init();
aos_loop_init();
...
aos_show_welcome();
...
und_update_statis(UND_STATIS_DEV_EXCEPTION_IDX, (int)debug_reboot_reason_get());
...
return 0;
}
源代码并非如此,我将没有执行的代码,以及宏都给删了,这里认为是一些组件吧。
接下来看应用启动后的。
int application_start(int argc, char **argv)
{
...
aos_set_log_level(AOS_LL_DEBUG);
set_iotx_info();
netmgr_init();
aos_register_event_filter(EV_KEY, linkkit_key_process, NULL);
aos_register_event_filter(EV_WIFI, wifi_service_event, NULL);
aos_register_event_filter(EV_YUNIO, cloud_service_event, NULL);
IOT_RegisterCallback(ITE_MQTT_CONNECT_SUCC, mqtt_connected_event_handler);
...
IOT_SetLogLevel(IOT_LOG_DEBUG);
#ifdef EN_COMBO_NET
combo_net_init();
#else
#ifdef AWSS_SUPPORT_DEV_AP
aos_task_new("dap_open", awss_open_dev_ap, NULL, 4096);
#else
aos_task_new("netmgr_start", start_netmgr, NULL, 5120);
#endif
#endif
aos_loop_run();
return 0;
}
void set_iotx_info()
{
char _device_name[IOTX_DEVICE_NAME_LEN + 1] = {0};
HAL_GetDeviceName(_device_name);
if (strlen(_device_name) == 0) {
HAL_SetProductKey(PRODUCT_KEY);
HAL_SetProductSecret(PRODUCT_SECRET);
HAL_SetDeviceName(DEVICE_NAME);
HAL_SetDeviceSecret(DEVICE_SECRET);
}
}
1、设置打印级别
2、设置iotx_info,这个信息是几段字符串,后面再说。
3、 初始化
4、 注册几个回调
5、 创建任务 start_netmgr
先看看初始化函数netmgr_init
int netmgr_init(void)
{
#ifdef NET_WITH_WIFI
return netmgr_wifi_init();
#elif defined(NET_WITH_CELLULAR)
return netmgr_cellular_init();
#endif
}
int netmgr_wifi_init(void)
{
hal_wifi_module_t *module;
aos_register_event_filter(EV_WIFI, netmgr_events_executor, NULL);
#ifdef AOS_COMP_CLI
aos_cli_register_command(&ncmd);
#endif
module = hal_wifi_get_default_module();
memset(&g_netmgr_cxt, 0, sizeof(g_netmgr_cxt));
g_netmgr_cxt.ip_available = false;
g_netmgr_cxt.wifi_scan_complete_cb_finished = false;
g_netmgr_cxt.wifi_hal_mod = module;
#if !defined(WITH_SAL) || defined(DEV_SAL_ATHOST)
#if defined(CONFIG_YWSS) && (!defined(CSP_LINUXHOST) || defined(DEV_SAL_ATHOST))
add_autoconfig_plugin(&g_alink_smartconfig);
#else
add_autoconfig_plugin(&g_def_smartconfig);
#endif
#endif
hal_wifi_install_event(g_netmgr_cxt.wifi_hal_mod, &g_wifi_hal_event);
read_persistent_conf();
#ifdef CONFIG_AOS_MESH
umesh_init(MODE_RX_ON);
#endif
return 0;
}
1、获取wifi模块,这里是8266,并赋值给g_netmgr_cxt.wifi_hal_mod
2、注册一些函数,然后读配置文件,获取文件里保存的wifi信息
初始化函数接着写内容了,接着看管理的函数start_netmgr
static void start_netmgr(void *p)
{
iotx_event_regist_cb(linkkit_event_monitor); //注册,其实就只是一个状态的打印
LOG("%s\n", __func__);
aos_msleep(2000);
netmgr_start(true);
aos_task_exit(0);
}
int netmgr_start(bool autoconfig)
{
#ifdef NET_WITH_WIFI
return netmgr_wifi_start(autoconfig);
#elif defined(NET_WITH_CELLULAR)
return netmgr_cellular_start(autoconfig);
#endif
}
int netmgr_wifi_start(bool autoconfig)
{
stop_mesh();
if (has_valid_ap() == 1) { //如果已经保存了IP
aos_post_event(EV_WIFI, CODE_WIFI_CMD_RECONNECT, 0);
return 1;
}
#ifdef CONFIG_AOS_NETMGRYTS_NOSMARTCONFIG
else {
LOGI("netmgr",
"netmgr yts only supports valid AP connect test, "
"please ensure you have correct AP/passwd information set"
" in kv before you do this test.");
return -1;
}
#endif
if (autoconfig) {
#ifndef PREVALIDATE_TEST //使用测试的AP SSID 和 PASSWD 连接 WIFI
netmgr_wifi_config_start();
#endif
return 0;
}
start_mesh(false);
return -1;
}
1、mesh 函数可以先忽略,这里默认的未配置。
2、判断如果已经配过网,则直接连接。
3、autoconfig传进来的是true, 执行netmgr_wifi_config_start
static void netmgr_wifi_config_start(void)
{
autoconfig_plugin_t *valid_plugin = g_netmgr_cxt.autoconfig_chain;
if (valid_plugin != NULL) { //初始化时赋值
g_netmgr_cxt.doing_smartconfig = true;
valid_plugin->autoconfig_start(); //smart_config_start
} else {
LOGW(TAG, "net mgr none config policy");
start_mesh(false);
}
}
这里的autoconfig_start调用执行下面的函数,进入awss_start()
static int smart_config_start(void)
{
extern int awss_start();
awss_start();
return 0;
}
int awss_start(void)
{
if (awss_stopped == 0) {
awss_debug("awss already running\n");
return -1;
}
awss_stopped = 0;
awss_event_post(IOTX_AWSS_START);
produce_random(aes_random, sizeof(aes_random));
do {
__awss_start();
...
...
awss_start 先这么看着,why? 流程会卡在_awss_start()函数里面。
int __awss_start(void)
{
char ssid[OS_MAX_SSID_LEN + 1] = {0}, passwd[OS_MAX_PASSWD_LEN + 1] = {0};
/* enum AWSS_AUTH_TYPE auth = AWSS_AUTH_TYPE_INVALID;
enum AWSS_ENC_TYPE encry = AWSS_ENC_TYPE_INVALID;
uint8_t channel = 0;
*/
uint8_t bssid[OS_ETH_ALEN] = {0};
uint8_t token[ZC_MAX_TOKEN_LEN] = {0};
uint8_t find_token = 0;
int ret;
uint8_t i;
awss_stop_connecting = 0;
awss_finished = 0;
/* these params is useless, keep it for compatible reason */
aws_start(NULL, NULL, NULL, NULL);
...
__awss_start 会调用 aws_start(NULL, NULL, NULL, NULL);
void aws_start(char *pk, char *dn, char *ds, char *ps)
{
aws_info = awss_zalloc(sizeof(struct aws_info));
if (!aws_info) {
return;
}
aws_state = AWS_SCANNING;
/* start from -1 */
aws_chn_index = 0xff;
memcpy(aws_chn_list, aws_fixed_scanning_channels,
sizeof(aws_fixed_scanning_channels));
memset(aws_result_ssid, 0, sizeof(aws_result_ssid));
memset(aws_result_passwd, 0, sizeof(aws_result_passwd));
memset(aws_result_bssid, 0, sizeof(aws_result_bssid));
aws_result_auth = ZC_AUTH_TYPE_INVALID;
aws_result_encry = ZC_ENC_TYPE_INVALID;
aws_result_channel = 0;
zconfig_init();
HAL_Awss_Open_Monitor(aws_80211_frame_handler); //register_monitor_cb data_func
#ifndef AWSS_DISABLE_ENROLLEE
awss_init_enrollee_info();
#endif
aws_main_thread_func();
}
1、zconfig是一种管理和配置的方式,zconfig_init 负责分配内存。
2、HAL_Awss_Open_Monitor 设置Wi-Fi网卡工作在监听(Monitor)模式, 并在收到802.11帧的时候调用被传入的回调函数
3、开启一个线程,后面再说。
/*
* @brief 设置Wi-Fi网卡工作在监听(Monitor)模式,
* 并在收到802.11帧的时候调用被传入的回调函数
*
* @param[in] cb @n A function pointer, called back when wifi receive a frame.
*/
void HAL_Awss_Open_Monitor(awss_recv_80211_frame_cb_t cb)
{
hal_wifi_module_t *module = hal_wifi_get_default_module();
if (module == NULL) {
return;
}
#ifdef AOS_COMP_PWRMGMT
aos_pwrmgmt_lowpower_suspend(PWRMGMT_NETMGR);
#endif
g_ieee80211_handler = cb;
hal_wifi_register_monitor_cb(module, monitor_data_handler);
hal_wifi_start_wifi_monitor(module);
HAL_Awss_Switch_Channel(6, 0, NULL);
}
awss_recv_80211_frame_cb_t g_ieee80211_handler;
static void monitor_data_handler(uint8_t *buf, int len, hal_wifi_link_info_t *info)
{
int with_fcs = 0;
unsigned char rssi = -1;
int link_type = AWSS_LINK_TYPE_NONE;
if (info) {
rssi = info->rssi;
}
(*g_ieee80211_handler)((char *)buf, len, link_type, with_fcs, rssi);
}
static void start_monitor(hal_wifi_module_t *m)
{
wifi_set_mode(STATION_MODE); //设置 8266 sta模式
wifi_station_disconnect(); //断开连接
wifi_promiscuous_enable(0); //禁用混杂模式,百度翻译滥交...
wifi_set_promiscuous_rx_cb(sniffer_wifi_promiscuous_rx); //设置数据回调
wifi_promiscuous_enable(1); //启用混杂模式
}
1、获取wifi模块
2、给g_ieee80211_handler 赋值,并注册数据回调
3、hal_wifi_start_wifi_monitor 最终调用启动混杂模式
4、设置Wi-Fi网卡、模组或芯片切换到指定的信道(channel)上 6
sniffer_wifi_promiscuous_rx 数据处理函数 会调用到注册的 aws_80211_frame_handler函数
void aws_main_thread_func(void)
{
int interval = 0;
aws_start_timestamp = os_get_time_ms();
/* channel switch init */
aws_switch_channel();
rescanning:
/* start scaning channel */
memset(zc_bssid, 0, ETH_ALEN);
while (aws_amend_dst_chan != 0 || aws_state == AWS_SCANNING) {
awss_update_config_press();
switch (aws_is_chnscan_timeout()) {
case CHNSCAN_ONGOING:
break;
case CHNSCAN_NEXT_CHN:
aws_switch_channel();
break;
case CHNSCAN_TIMEOUT:
goto timeout_scanning;
default:
break;
}
if (aws_stop == AWS_STOPPING) { /* interrupt by user */
goto timeout_scanning;
}
if (aws_state != AWS_SCANNING) { /* channel is locked, don't need to tx probe req */
break;
}
interval = (awss_get_channel_scan_interval_ms() + 2) / 3;
if (interval < 1) {
interval = 1;
}
/* 80211 frame handled by callback */
HAL_SleepMs(interval);
#ifndef AWSS_DISABLE_ENROLLEE
awss_broadcast_enrollee_info();
#endif
HAL_SleepMs(interval);
#ifdef AWSS_SUPPORT_DISCOVER
aws_discover_send_beacon();
#endif
HAL_SleepMs(interval);
#ifdef AWSS_SUPPORT_AHA
aws_send_aha_probe_req();
#endif
}
...
在未配网的情况下,一直卡在这个wihle循环里面。
默认配网是通过按键触发的,GPIO14 我的8266管脚是D5,旁边就是 GND和3.3V的引脚,我们可以通过将D5先接GND,再接3.3V方式模拟,当然这样做很容易引起芯片复位重启。
默认配网触发函数在 application_start 函数里,前面已经讲过
aos_register_event_filter(EV_KEY, linkkit_key_process, NULL);
void linkkit_key_process(input_event_t *eventinfo, void *priv_data)
{
if (eventinfo->type != EV_KEY) {
return;
}
LOG("awss config press %u\n", eventinfo->value);
if (eventinfo->code == CODE_BOOT) {
if (eventinfo->value == VALUE_KEY_CLICK) {
do_awss_active();
} else if (eventinfo->value == VALUE_KEY_LTCLICK) {
do_awss_reset();
}
}
}
void do_awss_active()
{
LOG("do_awss_active %d\n", awss_running);
awss_running = 1;
#ifdef WIFI_PROVISION_ENABLED
extern int awss_config_press();
awss_config_press();
#endif
}
awss_config_press
函数路径 middleware\linkkit\wifi_provision\frameworks\awss.c
int awss_config_press(void)
{
config_press_start_timestamp = os_get_time_ms();
awss_trace("enable awss\r\n");
g_user_press = 1;
awss_event_post(IOTX_AWSS_ENABLE);
return 0;
}
awss_event_post
函数路径 middleware\linkkit\wifi_provision\dev_bind\awss_event.c
int awss_event_post(int event)
{
int ret = 0;
void *cb = NULL;
ret = iotx_event_post(event); //一句打印而已
cb = (void *)iotx_event_callback(ITE_AWSS_STATUS);
if (cb) {
ret = ((int (*)(int))cb)(event);
}
return ret;
}
int iotx_event_regist_cb(void (*monitor_cb)(int event))
{
g_event_monitor = (void *)monitor_cb;
return 0;
}
int iotx_event_post(int event)
{
if (g_event_monitor == NULL) {
return -1;
}
((void (*)(int))g_event_monitor)(event);
return 0;
}
awss_event_post
是调用函数,相应的,iotx_event_regist_cb是注册函数,配网注册的函数为
iotx_event_regist_cb(linkkit_event_monitor);
linkkit_event_monitor
里关于配网 IOTX_AWSS_ENABLE 的调用只是一行打印
static void linkkit_event_monitor(int event)
{
switch (event) {
case IOTX_AWSS_START: // AWSS start without enbale, just supports device discover
// operate led to indicate user
LOG("IOTX_AWSS_START");
break;
case IOTX_AWSS_ENABLE: // AWSS enable, AWSS doesn't parse awss packet until AWSS is enabled.
LOG("IOTX_AWSS_ENABLE");
// operate led to indicate user
break;
....
回到 cb = (void *)iotx_event_callback(ITE_AWSS_STATUS) 调用的地方。
iotx_event_callback 这个函数找了很久,最好发现没调用。也就是返回了NULL,所以这个地方只修改了两个标志位。
这个标志位可以通过awss_get_config_press 函数返回,加了打印,确认总共有一下三个函数调用用到它,智能配网 应该就是第三个,只是其它两个也应该脱不了干系。
awss_ieee80211_zconfig_process
awss_ieee80211_wps_process
awss_ieee80211_smartconfig_process
所以配网过程中,是放开了上面某个函数的流程,去检测分析了某类包