AliOS-Things ESP8266 配网 学习

三世轮回 提交于 2020-01-18 08:02:49

AliOS-Things ESP8266 配网 学习

1、环境搭建

参考官网

2、流程

确认流程通过浏览源码、增加打印以及查看打印来确认,如果遇到乐鑫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

所以配网过程中,是放开了上面某个函数的流程,去检测分析了某类包

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!