[配网] 基于 Ai-M61-32S 的AP网页配网实现

[复制链接]
查看2297 | 回复15 | 2023-12-6 21:17:18 | 显示全部楼层 |阅读模式

本帖最后由 WT_0213 于 2023-12-7 11:21 编辑

本帖最后由 WT_0213 于 2023-12-6 21:19 编辑

目前实现上电后自动打开AP模式,连接无线AP后。打开网页提交要连接的WIFI名称 和 WIFI密码 点击提交。相应POST提交的WIFI名称和密码。

以下代码添加了关键点注释,方便大家理解。

发帖积分恢复了,又充满了动力。😄

演示

首先设备上电,上电后在电脑或手机上可以看到如下热点

屏幕截图2023-12-06092220.png

点击连接

屏幕截图2023-12-06092257.png

然后会让你输入密码

屏幕截图2023-12-06092322.png

这里密码是:1234567879

然后通过浏览器输入:

192.168.169.1

可以看到如下界面,简单写了个配置页面效果:

捕获.PNG

输入要连接的WIFI名称与密码,点击提交。

捕获1.PNG

成功后返回提交的WIFI名和密码;

捕获2.PNG

介绍一下实现方式和思路

打开AP模式
static void start_ap(void)
{
    wifi_mgmr_ap_params_t config = { 0 };

    config.channel = 3;
    config.key = USER_AP_PASSWORD;
    config.ssid = USER_AP_NAME;
    config.use_dhcpd = 1;

    if (wifi_mgmr_conf_max_sta(2) != 0) {
        return 5;
    }
    if (wifi_mgmr_ap_start(&config) == 0) {
        return 0;
    }
}
启动http_server
void mhttp_server_init()
{
    //常用变量
    int ss, sc;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    int snd_size = 0; /* 发送缓冲区大小 */
    socklen_t optlen; /* 选项值长度 */
    // int optlen;
    int err;
    socklen_t addrlen;
    // int addrlen;

    //建立套接字
    ss = socket(AF_INET, SOCK_STREAM, 0);

    if (ss < 0)
    {
        printf("socket error\n");
    }

    /*设置服务器地址*/
    bzero(&server_addr, sizeof(server_addr));

    /*清零*/
    server_addr.sin_family = AF_INET;
    /*协议族*/
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /*本地地址*/
    server_addr.sin_port = htons(80);
    /*服务器端口*/

    /*绑定地址结构到套接字描述符*/
    err = bind(ss, (struct sockaddr *)&server_addr, sizeof(server_addr));

    if (err < 0)
    {
        printf("bind error\n");
        return -1;
    }

    /*设置侦听*/
    err = listen(ss, 7);

    if (err < 0)
    {
        printf("listen error\n");
        return -1;
    }

    addrlen = sizeof(struct sockaddr_in);
    MYPARM parm11;
    while (1)
    {
        printf("accept start\r\n");
        sc = accept(ss, (struct sockaddr *)&client_addr, &addrlen);
        if ((sc < 0) || (mysemaphoreflag > 0))
        {
            printf("accept fail sc is:%d  semaphore is:%d\r\n", sc, mysemaphoreflag);
            if (sc > 0)
            {
                close(sc);
            }
            continue;
        }

        parm11.sc = sc;
        parm11.buf = NULL;

        mysemaphoreflag++;
        http_server_thread(&parm11);
        vTaskDelay(1);
    }
}

等待客户端连接即可。为了使设备启动状态更直观,增加了开机亮灯操作。启动后自动打开绿灯。

代码如下:

    gpio = bflb_device_get_by_name("gpio");
    bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT| GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
    bflb_gpio_set(gpio, GPIO_PIN_14);

主要代码讲解

main.c
int main(void)
{
    //中开启时钟
    board_init();
    // 亮绿灯
    gpio = bflb_device_get_by_name("gpio");
    bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT| GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
    bflb_gpio_set(gpio, GPIO_PIN_14);

    //设置中断分组
    bflb_irq_set_nlbits(4);
    //设置中断优先级
    bflb_irq_set_priority(37, 3, 0);
    bflb_irq_set_priority(WIFI_IRQn, 1, 0);

    // 拿到 gpio 
    gpio = bflb_device_get_by_name("gpio");
    // 拿到 uart 
    uart0 = bflb_device_get_by_name("uart0");
    shell_init_with_task(uart0);

    // 初始化tcp ip
    tcpip_init(NULL, NULL);
    wifi_start_firmware_task();

    // 创建http服务
    create_http_server_task();
    vTaskStartScheduler();
    while (1) {
    }
}
创建http服务
void create_http_server_task(void)
{
    MuxSem_Handle = xSemaphoreCreateMutex();
    if (NULL != MuxSem_Handle)
    {
        printf("MuxSem_Handle creat success!\r\n");
    }

    xTaskCreate(http_server_task, (char*)"fw", WIFI_HTTP_SERVER_STACK_SIZE, NULL, HTTP_SERVERTASK_PRIORITY, &http_server_task_hd);
}

这里使用了xTaskCreate,FreeRTOS的任务。

不了解的可以看下Ai-M61-32S AP 配网学习 之 FreeRTOS任务 https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43670

接下来是 http_server_task
void http_server_task(void* param)
{
    // 打开AP
    start_ap();
    // 启动http服务,也就是响应网页的服务
    mhttp_server_init();
}

这里比较简单。

打开ap代码
static void start_ap(void)
{
    wifi_mgmr_ap_params_t config = { 0 };
    // 通道
    config.channel = 3;
    // 设置AP热点名称
    config.ssid = USER_AP_NAME;
    // 设置密码
    config.key = USER_AP_PASSWORD;
    // 启动dhcp
    config.use_dhcpd = 1;

    // 设置最大连接数
    if (wifi_mgmr_conf_max_sta(2) != 0) {
        return 5;
    }
    // 启动AP模式
    if (wifi_mgmr_ap_start(&config) == 0) {
        return 0;
    }
}
WIFI信息设置
#define USER_AP_NAME "Ai-M61-32s"
#define USER_AP_PASSWORD "123456789"

然后是http服务的启动

mlwip_https.c

void mhttp_server_init()
{
    //常用变量
    int ss, sc;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    int snd_size = 0; /* 发送缓冲区大小 */
    socklen_t optlen; /* 选项值长度 */
    // int optlen;
    int err;
    socklen_t addrlen;
    // int addrlen;

    //建立套接字
    ss = socket(AF_INET, SOCK_STREAM, 0);

    if (ss < 0)
    {
        printf("socket error\n");
    }

    /*设置服务器地址*/
    bzero(&server_addr, sizeof(server_addr));

    /*清零*/
    server_addr.sin_family = AF_INET;
    /*协议族*/
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /*本地地址*/
    server_addr.sin_port = htons(80);
    /*服务器端口*/

    /*绑定地址结构到套接字描述符*/
    err = bind(ss, (struct sockaddr *)&server_addr, sizeof(server_addr));

    if (err < 0)
    {
        printf("bind error\n");
        return -1;
    }

    /*设置侦听*/
    err = listen(ss, 7);

    if (err < 0)
    {
        printf("listen error\n");
        return -1;
    }

    addrlen = sizeof(struct sockaddr_in);
    MYPARM parm11;
    while (1)
    {
        printf("accept start\r\n");
        sc = accept(ss, (struct sockaddr *)&client_addr, &addrlen);
        if ((sc < 0) || (mysemaphoreflag > 0))
        {
            printf("accept fail sc is:%d  semaphore is:%d\r\n", sc, mysemaphoreflag);
            if (sc > 0)
            {
                close(sc);
            }
            continue;
        }

        parm11.sc = sc;
        parm11.buf = NULL;

        mysemaphoreflag++;
        http_server_thread(&parm11);
        vTaskDelay(1);
    }
}
接下来就是响应请求
void http_server_thread(void *msg)
{
    // printf("http_server_thread\r\n");
    MYPARM *parm11;
    parm11 = (MYPARM *)msg;

    int sc;
    char readbuffer[1024];
    int size = 0;
    char command[1024];
    char head_buf[1000];
    memset(command, 0, sizeof(command));
    memset(head_buf, 0, sizeof(head_buf));
    sc = parm11->sc;

    memset(readbuffer, 0, sizeof(readbuffer));


    while (1)
    {
        // printf("read stop\r\n");
        size = read(sc, readbuffer, 1024);
        // int rc = recv(sc, readbuffer, sizeof(readbuffer), 0);
        printf("read len:%d\r\n", size);
        printf("get:%s\r\n", readbuffer);

        if (size <= 0)
        {
            printf("size <= 0\r\n");
            break;
        }
        int len = get_http_command(readbuffer, command); //得到http 请求中 GET后面的字符串
        printf("get:%s len:%d\r\n", command, len);

        if (strcmp(command, "/") == 0)
        {
            printf("command1\r\n");
            streatask = 0;
            sprintf(head_buf, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html;charset=UTF-8\r\n\r\n", sizeof(html_page));

            // head_buf
            // strlen(index_ov2640_html)
            // 返回html页面
            int ret = write(sc, head_buf, strlen(head_buf));
            if (ret == -1)
            {
                printf("send failed");
                close(sc);
                mysemaphoreflag--;
                return NULL;
            }
            ret = write(sc, html_page, sizeof(html_page));
            if (ret < 0)
            {
                printf("text write failed");
            }
            close(sc);
            mysemaphoreflag--;
            break;
        } 
        else if (strstr(command, "set"))
        {
            printf("set\r\n");
            streatask = 0;
            // 获取POST提交过来的数据,拿到ssid部分
            char* wifiCfg = strstr(readbuffer, "ssid");

            printf("wifiCfg: %s \r\n", wifiCfg);

            sprintf(head_buf, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 433\r\nAccess-Control-Allow-Origin: *\r\n\r\n");

            int ret = write(sc, head_buf, strlen(head_buf));
            if (ret == -1)
            {
                printf("send failed");
                close(sc);
                mysemaphoreflag--;
                return NULL;
            }

            // 将post参数切开,分别拿到 ssid 和 pwd
            char* ssid = strtok(wifiCfg, "&");
            char* pwd =  strtok(NULL, "&");

            // 将ssid参数切开,分别拿到 key 和 value
            char* ssidKey = strtok(ssid, "=");
            char* ssidValue = strtok(NULL, "=");
            // 将pwd参数切开,分别拿到 key 和 value
            char* pwdKey = strtok(pwd, "=");
            char* pwdValue = strtok(NULL, "=");

            // ============================================

            // 待实现 将 wifi 信息写入 存储

            // 开启 sta 模式,连接WIFI

            // ============================================

            printf("OK ssid:%s, pwd:%s  \r\n", ssidValue, pwdValue);

            // 创建cJSON
            cJSON *json = cJSON_CreateObject();
            cJSON_AddStringToObject(json, "ssid", ssidValue);
            cJSON_AddStringToObject(json, "pwd", pwdValue);

            char data_buf[1024];

            sprintf(data_buf, "%s\r\n\r\n", cJSON_Print(json));

            printf("OK data_buf:%s  \r\n", data_buf);
            // static char data_buf[] = "{\"ssid\":1,\"pwd\":0}";
            // ret = write(sc, data_buf, 433);
            // 将获取到的数据通过json形式返回
            ret = write(sc, data_buf, sizeof(data_buf));
            if (ret < 0)
            {
                printf("text write failed");
            }
            close(sc);
            mysemaphoreflag--;
            break;
        }
        else
        {
            streatask = 0;
            close(sc);
            mysemaphoreflag--;
        }
        // write(sc,readbuffer,size);

    }
    //关中断
    // free(parm11->buf);
    // vTaskDelete(NULL);
    //开中断

}
html 代码 page.h 很简单的界面,可以做很多优化。
static const unsigned char html_page[] = R"(
    <html>
        <body>
            Hello Word!
            <form method="post" action="/set">
            <input name="ssid" type="text" />
            <br/>
              <input name="pwd" type="text" />
            <br/>
            <input type="submit" value="提交"/>
            </form>
        </body>
    </html>
)";

到这里基本,就可以实现 AP 配网的一些前置条件了。

下一步就是将 WIFI信息保存到 存储。

WIFI相关参考文档。

WiFi API指南 — 安信可科技 documentation (wb2-api-web.readthedocs.io)

Wi-Fi Manager — BL IoT SDK release_bl_iot_sdk_1.6.39-238-gf5ba0a7ee 文档 (bouffalolab.github.io)

书接上回,将WIFI名称和密码保存到存储当中。

使用easyflash保存WIFI名称和密码

创建 存储相关代码

storage/storage.h

#ifndef __CUSTOM_H_
#define __CUSTOM_H_
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#define SSID_KEY "SSID"
#define PASS_KEY "PASS"

#ifndef USER_FLASH_H
#define USER_FLASH_H
void flash_init(void);
void flash_erase_set(char* key, char* value);
char* flash_get_data(char* key, int len);

#endif

#ifdef __cplusplus
}
#endif
#endif /* EVENT_CB_H_ */

storage/storage.c

/**
 * @file user_flash.c
 * @author your name ([email]you@domain.com[/email])
 * @brief
 * @version 0.1
 * @date 2023-08-07
 *
 * @copyright Copyright (c) 2023
 *
*/
#include "stdio.h"
#include "string.h"
#include "storage.h"
#include "easyflash.h"
#include "log.h"

void flash_init(void)
{
    //init easyflash
    bflb_mtd_init();
    easyflash_init();
}
/**
 * @brief
 *
 * @param key
 * @param value
*/
void flash_erase_set(char* key, char* value)
{
    size_t len = 0;
    int value_len = strlen(value);
    ef_set_and_save_env(key, value);
    // bflb_flash_read(key, flash_data, strlen(value));
    // printf("writer data:%s\r\n", flash_data);
    memset(value, 0, strlen(value));
    ef_get_env_blob(key, value, value_len, &len);
    LOG_W("flash_erase_set %s: %s", key, value);
}
/**
 * @brief
 *
 * @param key
 * @return char*
*/
char* flash_get_data(char* key, int len)
{
    static char* flash_data = NULL;
    flash_data = pvPortMalloc(len);
    memset(flash_data, 0, len);

    ef_get_env_blob(key, flash_data, len, (size_t)&len);
    LOG_W("flash_get_data %s: %s, len:%d\r\n", key, flash_data, strlen(flash_data));
    return flash_data;
}

修改web/mlwip_https.c增加如下内容:

#include "storage.h"
#include "wifi_event.h"
#include "log.h"

....


   // 将 wifi 信息写入 存储
   flash_erase_set(SSID_KEY, ssidValue);
   flash_erase_set(PASS_KEY, pwdValue);

   // 开启 sta 模式,连接WIFI
   // 重启设备
   LOG_W("system 2s reset ");
   vTaskDelay(2000/portTICK_PERIOD_MS);
   GLB_SW_System_Reset();

修改proj.conf增加如下内容:

# easy flash
set(CONFIG_PARTITION 1)
set(CONFIG_BFLB_MTD 1)
set(CONFIG_EASYFLASH4 1)

修改CMakeLists.txt增加如下内容:

...

sdk_add_include_directories(storage)

...

target_sources(app PRIVATE
    storage/storage.c
    web/cJSON.c
    web/mlwip_https.c
)

对 flash_prog_cfg.ini 配置文件进行了一些注释

#***************************************************#
#                 固件烧录配置                       #
#             Firmware burning configuration        #
#***************************************************#
[cfg]
# 0:无擦除,1:程序化截面擦除,2:芯片擦除
# 0: no erase, 1:programmed section erase, 2: chip erase
erase = 1
# skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated
skip_mode = 0x0, 0x0

# 复位下载功能使能(Reset download function enable)
# 0: not use isp mode, #1: isp mode
boot2_isp_mode = 1

# 配置boot2固件,否则无法使用复位烧录功能(Configure boot2 firmware, otherwise the reset burn function cannot be used)
[boot2]
filedir = ./build/build_out/boot2_*.bin
address = 0x000000

# 配置partition固件,这是必要的(Configuring partition firmware is necessary)
[partition]
filedir = ./build/build_out/partition*.bin
address = 0xE000

# 配置应用程序固件地址,需要新建工程时需要修改“Project_basic” 为新工程的名字,否则可能会导致烧录失败
#(To configure the application firmware address, when creating a new project, it is necessary to modify "Project_Basic" to the name of the new project, otherwise it may cause burning failure)
[FW]
filedir = ./build/build_out/smart_config_$(CHIPNAME).bin
address = @partition
address = 0x10000

# [mfg]
# filedir = ./build/build_out/mfg*.bin

easyflash4相关问题可以参考。

[答疑] easyflash4 使用问题及解决方法 https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43763

[参考] 基于 Ai-M61-32S 的AP网页配网实现 Step 2 https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=43766

接下来就是读取WIFI信息数据,并连接到WIFI。

创建 WIFI相关代码

wifi/wifi_event.h

/**
 * @file wifi_event.h
 * @author your name ([email]you@domain.com[/email])
 * @brief
 * @version 0.1
 * @date 2023-06-29
 *
 * @copyright Copyright (c) 2023
 *
*/
#ifndef WIFI_EVENT_H
#define WIFI_EVENT_H
#include "stdint.h"

int wifi_start_firmware_task(void);
void wifi_event_handler(uint32_t code);
uint8_t wifi_connect(char* ssid, char* passwd);
#endif

wifi/wifi_event.c

/**
 * @file wifi_event.c
 * @author your name ([email]you@domain.com[/email])
 * @brief
 * @version 0.1
 * @date 2023-06-29
 *
 * @copyright Copyright (c) 2023
 *
*/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include "bl_fw_api.h"
#include "wifi_mgmr_ext.h"
#include "wifi_mgmr.h"
#include "bflb_irq.h"
#include "bflb_uart.h"
#include "bflb_l1c.h"
#include "bflb_mtimer.h"

#include "bl616_glb.h"
#include "rfparam_adapter.h"

#include "board.h"
#include "log.h"

#include "storage.h"
#define DBG_TAG "WIFI EVENT"

#define WIFI_STACK_SIZE     (1024*4)
#define TASK_PRIORITY_FW    (16)

static wifi_conf_t conf =
{
    .country_code = "CN",
};
static TaskHandle_t wifi_fw_task;
static uint32_t sta_ConnectStatus = 0;
xQueueHandle queue;

/**
 * @brief WiFi 任务
 *
 * @return int
*/
int wifi_start_firmware_task(void)
{
    LOG_I("Starting wifi ...");

    /* enable wifi clock */

    GLB_PER_Clock_UnGate(GLB_AHB_CLOCK_IP_WIFI_PHY | GLB_AHB_CLOCK_IP_WIFI_MAC_PHY | GLB_AHB_CLOCK_IP_WIFI_PLATFORM);
    GLB_AHB_MCU_Software_Reset(GLB_AHB_MCU_SW_WIFI);

    /* set ble controller EM Size */

    GLB_Set_EM_Sel(GLB_WRAM160KB_EM0KB);

    if (0 != rfparam_init(0, NULL, 0)) {
        LOG_I("PHY RF init failed!");
        return 0;
    }

    LOG_I("PHY RF init success!");

    /* Enable wifi irq */

    extern void interrupt0_handler(void);
    bflb_irq_attach(WIFI_IRQn, (irq_callback)interrupt0_handler, NULL);
    bflb_irq_enable(WIFI_IRQn);

    xTaskCreate(wifi_main, (char*)"fw", WIFI_STACK_SIZE, NULL, TASK_PRIORITY_FW, &wifi_fw_task);

    return 0;
}
/**
 * @brief wifi event handler
 *      WiFi 事件回调
 *
 * @param code
*/


void wifi_event_handler(uint32_t code)
{

    sta_ConnectStatus = code;
    BaseType_t xHigherPriorityTaskWoken;
    switch (code) {
        case CODE_WIFI_ON_INIT_DONE:
        {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE", __func__);
            wifi_mgmr_init(&conf);
        }
        break;
        case CODE_WIFI_ON_MGMR_DONE:
        {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE", __func__);

        }
        break;
        case CODE_WIFI_ON_SCAN_DONE:
        {
            char* scan_msg = pvPortMalloc(128);
            memset(scan_msg, 0, 128);
            wifi_mgmr_sta_scanlist();
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE SSID numbles:%d", __func__, wifi_mgmr_sta_scanlist_nums_get());
            sprintf(scan_msg, "{\"wifi_scan\":{\"status\":0}}");
            // xQueueSend(queue, scan_msg, );
            if (wifi_mgmr_sta_scanlist_nums_get()>0) {
                xQueueSendFromISR(queue, scan_msg, &xHigherPriorityTaskWoken);
                if (xHigherPriorityTaskWoken) {
                    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
                }
            }

            vPortFree(scan_msg);
        }
        break;
        case CODE_WIFI_ON_CONNECTED:
        {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED", __func__);
            void mm_sec_keydump();
            mm_sec_keydump();
        }
        break;
        case CODE_WIFI_ON_GOT_IP:
        {

            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP", __func__);
        }
        break;
        case CODE_WIFI_ON_DISCONNECT:
        {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT", __func__);
            char* queue_buff = pvPortMalloc(128);
            memset(queue_buff, 0, 128);
            sprintf(queue_buff, "{\"wifi_disconnect\":true}");
            xQueueSendFromISR(queue, queue_buff, pdTRUE);
            vPortFree(queue_buff);
        }
        break;
        case CODE_WIFI_ON_AP_STARTED:
        {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED", __func__);
        }
        break;
        case CODE_WIFI_ON_AP_STOPPED:
        {
            LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED", __func__);
        }
        break;
        case CODE_WIFI_ON_AP_STA_ADD:
        {
            LOG_I("[APP] [EVT] [AP] [ADD] %lld", xTaskGetTickCount());
        }
        break;
        case CODE_WIFI_ON_AP_STA_DEL:
        {
            LOG_I("[APP] [EVT] [AP] [DEL] %lld", xTaskGetTickCount());
        }
        break;
        default:
        {
            LOG_I("[APP] [EVT] Unknown code %u ", code);
        }
    }
}

uint8_t wifi_connect(char* ssid, char* passwd)
{
    int ret = 255;
    // struct fhost_vif_ip_addr_cfg ip_cfg = { 0 };
    uint32_t ipv4_addr = 0;
    char* queue_buff = pvPortMalloc(128);
    memset(queue_buff, 0, 128);
    if (NULL==ssid || 0==strlen(ssid)) {
        return 1;
    }

    if (wifi_mgmr_sta_state_get() == 1) {
        wifi_sta_disconnect();
    }
    if (wifi_sta_connect(ssid, passwd, NULL, NULL, 0, 0, 0, 1)) {
        return 4;
    }
    LOG_I("Wating wifi connet");
    //等待连接成功
    sta_ConnectStatus = 0;
    for (int i = 0;i<10*30;i++) {

        vTaskDelay(100/portTICK_PERIOD_MS);
        switch (sta_ConnectStatus) {
            case CODE_WIFI_ON_MGMR_DONE:
                // vTaskDelay(2000);
                // LOG_I("wifi_mgmr_sta_scan:%d", wifi_mgmr_sta_scan(wifi_scan_config));
                vPortFree(queue_buff);
                return 3;
            case CODE_WIFI_ON_SCAN_DONE:

                // LOG_I("WIFI STA SCAN DONE %s", wifi_scan_config[0].ssid_array);

                vPortFree(queue_buff);
                return 2;
            case CODE_WIFI_ON_DISCONNECT:   //连接失败(超过了重连次数还没有连接成功的状态)
                LOG_I("Wating wifi connet Faild");
                // wifi_sta_disconnect();

                vPortFree(queue_buff);
                return 4;
            case CODE_WIFI_ON_CONNECTED:    //连接成功(表示wifi sta状态的时候表示同时获取IP(DHCP)成功,或者使用静态IP)
                // LOG_I("Wating wifi connet OK \r\n");
                break;
            case CODE_WIFI_ON_GOT_IP:
                wifi_sta_ip4_addr_get(&ipv4_addr, NULL, NULL, NULL);
                LOG_I("wifi connened %s,IP:%s", ssid, inet_ntoa(ipv4_addr));
                sprintf(queue_buff, "{\"ip\":{\"IP\":\"%s\"}}", inet_ntoa(ipv4_addr));

                flash_erase_set(SSID_KEY, ssid);
                flash_erase_set(PASS_KEY, passwd);
                xQueueSend(queue, queue_buff, portMAX_DELAY);
                LOG_I("Wating wifi connet OK and get ip OK");
                vPortFree(queue_buff);

                return 0;
            default:
                //等待连接成功
                break;
        }

    }
    vPortFree(queue_buff);
    return 14; //连接超时
}

main.c增加如下内容:

.......

#include "wifi_event.h"


.......

/**
 * @brief  void queue_task(void* arg)
 * 消息队列循环读取
 * @param arg
*/
static void queue_task(void* arg)
{
    char* ssid = NULL;
    char* password = NULL;
    ssid = flash_get_data(SSID_KEY, 32);
    password = flash_get_data(PASS_KEY, 32);
    if (ssid!=NULL && strlen(ssid) > 0)
    {
        printf("read flash ssid:%s password:%s\r\n", ssid, password);
        wifi_connect(ssid, password);
    }
    else {
        printf("ssid read value is NULL:%06X\r\n", SSID_KEY);
    }
}

int main(void)
{
    .......
    // 初始化 存储
    flash_init();


    // 初始化tcp ip
    tcpip_init(NULL, NULL);
    // 启动WiFi任务
    wifi_start_firmware_task();
    char* ssid = NULL;
    ssid = flash_get_data(SSID_KEY, 32);
    if (ssid!=NULL && strlen(ssid) > 0){
        xTaskCreate(queue_task, "queue task", 1024*6, NULL, 2, NULL);
    }

   .......
}

修改 proj.conf 增加如下内容:

# wifi
set(CONFIG_VIF_MAX 2)
set(CONFIG_STA_MAX 4)
set(CONFIG_MAC_TXQ_DEPTH 32)
set(CONFIG_MAC_RXQ_DEPTH 12)

修改 CMakeLists.txt 增加如下内容:

target_sources(app PRIVATE
    wifi/wifi_event.c // 增加wifi相关代码
    storage/storage.c
    web/cJSON.c
    web/mlwip_https.c
)

目前当前方案存在以下问题:

  1. 中文WIFI名称无法连接
  2. 设置WIFI信息后AP消失
  3. WIFI信息填写错误,无法修复并且重新编译也不行

解决方案:

  1. 尽量使用和连接英文WIFI
  2. 重新烧写固件
  3. 擦除芯片内容烧写

flash_prog_cfg.ini 配置文件

[cfg] # 0:无擦除,1:程序化截面擦除,2:芯片擦除

0: no erase, 1:programmed section erase, 2: chip erase

erase = 1

改为

[cfg] # 0:无擦除,1:程序化截面擦除,2:芯片擦除

0: no erase, 1:programmed section erase, 2: chip erase

erase = 2

再执行 make flash COMX=COM?【?代表你的COM号】 命令就可以擦除数据了。

到这里基于 Ai-M61-32S 的AP网页配网实现就完成了。

gitee源码地址:

https://gitee.com/lazy-ai/ai-m61-32-sx_-network.git

源码:

ai-m61-32-sx_-network-master.zip

如果觉得不错 可以 给个 企业微信截图_20231207112020.png 哦。

本帖被以下淘专辑推荐:

回复

使用道具 举报

WT_0213 | 2023-12-6 21:19:11 | 显示全部楼层
ai-m61-32-sx_-network-master.zip (323.62 KB, 下载次数: 17)
回复 支持 反对

使用道具 举报

爱笑 | 2023-12-7 08:43:06 | 显示全部楼层
优秀~
用心做好保姆工作
回复

使用道具 举报

bzhou830 | 2023-12-7 08:47:21 | 显示全部楼层
选择去发光,而不是被照亮
回复

使用道具 举报

干簧管 | 2023-12-7 08:56:04 | 显示全部楼层
回复

使用道具 举报

lazy | 2023-12-7 09:00:12 | 显示全部楼层
太详细了
回复

使用道具 举报

lazy | 2023-12-7 09:06:30 | 显示全部楼层
写的太棒了
回复 支持 反对

使用道具 举报

silyhah | 2023-12-7 13:42:36 | 显示全部楼层
大佬
回复

使用道具 举报

1084504793 | 2023-12-7 16:52:13 | 显示全部楼层
不错的帖子
回复 支持 反对

使用道具 举报

lazy | 2023-12-8 08:46:15 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则