
WIFI模块开发教程之W600网络篇6:Airkiss配网
设备信道切换:设备持续切换信道监听无线数据包。 信道锁定:设备接收到有效数据包后,锁定信道不再切换频道。 信息编码传输:设备接收路由器发送的长度域数据包,解析其中编码的SSID和密码。 配网完成:设备完成配网配置后,与路由器建立稳定连接。 下载 将 打开 打开项目开发环境中的 SConscript 文件,找到 添加文件: 运行配网功能: 在APP中进入配网界面: 待待接收设备配网结果。如果配置成功,设备将通过UDP广播发送随机数,通知APP完成配网。
发布日期:2021-05-15 00:02:30
浏览次数:26
分类:精选文章
本文共 7632 字,大约阅读时间需要 25 分钟。
如何使用微信Airkiss协议实现路由器配网
前言
本文探讨如何通过Airkiss协议实现设备与路由器的无线网络配网配置。配网即设备通过接收特定数据包,获取所需的路由器SSID和密码等信息。本文将从理论、实例分析以及具体配置等多个方面展开讨论。
一、理论基础
1. Airkiss协议原理
Airkiss协议是一种无线网络配网技术,核心理念为:设备处于混杂模式监听无线网络数据包,每隔一定时间发送广播包或组播包。通过对无线包的长度域(Length)进行编码传输,路由器转发数据包,当设备与路由器处于同一信道时,便可接收有效数据。与市面上的一键配网类似,Airkiss通过对length字段进行编码传输路由器信息给设备,这既是技术本质也是实现的关键。
2. Airkiss配网流程
Airkiss配网流程主要包含以下步骤:
二、使用实例
1. 程序分析
1.1 设备信道切换
static void airkiss_switch_channel(void *parameter) { g_current_channel++; if (g_current_channel > MAX_CHANNEL_NUM) { g_current_channel = 1; } rt_wlan_set_channel(g_wlan_device, g_current_channel); airkiss_change_channel(ak_contex); AIRKISS_PRINTF("Switch channel %d \n", g_current_channel); }
1.2 混杂包监听回调函数
static void airkiss_monitor_callback(uint8_t *data, int len, void *user_data) { airkiss_recv_ret = airkiss_recv(ak_contex, data, len); if (airkiss_recv_ret == AIRKISS_STATUS_CHANNEL_LOCKED) { rt_timer_stop(g_switch_timer); AIRKISS_PRINTF("Lock channel in %d \n", g_current_channel); rt_timer_start(g_doing_timer); } else if (airkiss_recv_ret == AIRKISS_STATUS_COMPLETE) { rt_timer_stop(g_doing_timer); rt_sem_release(g_cfg_done_sem); AIRKISS_PRINTF("AIRKISS_STATUS_COMPLETE \n"); } }
1.3 发送配网后收到的random,通知APP配网成功
static void airkiss_send_notification_thread(void *parameter) { int sock = -1; int udpbufsize = 2; uint8_t random = (uint32_t)parameter; struct sockaddr_in g_stUDPBCAddr, g_stUDPBCServerAddr; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { AIRKISS_PRINTF("notify create socket error!\n"); goto _exit; } g_stUDPBCAddr.sin_family = AF_INET; g_stUDPBCAddr.sin_port = htons(10000); g_stUDPBCAddr.sin_addr.s_addr = htonl(0xffffffff); rt_memset(&g_stUDPBCAddr.sin_zero, 0, sizeof(g_stUDPBCAddr.sin_zero)); g_stUDPBCServerAddr.sin_family = AF_INET; g_stUDPBCServerAddr.sin_port = htons(10000); g_stUDPBCServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); rt_memset(&g_stUDPBCServerAddr.sin_zero, 0, sizeof(g_stUDPBCServerAddr.sin_zero)); if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &udpbufsize, sizeof(int)) != 0) { AIRKISS_PRINTF("notify socket setsockopt error\n"); goto _exit; } if (bind(sock, (struct sockaddr *)&g_stUDPBCServerAddr, sizeof(g_stUDPBCServerAddr)) != 0) { AIRKISS_PRINTF("notify socket bind error\n"); goto _exit; } for (int i = 0; i <= 20; i++) { int ret = sendto(sock, (char *)&random, 1, 0, (struct sockaddr *)&g_stUDPBCAddr, sizeof(g_stUDPBCAddr)); rt_thread_delay(10); } AIRKISS_PRINTF("airkiss notification thread exit!\n"); _exit: if (sock >= 0) { close(sock); } }
1.4 配网入口函数
static void airkiss_thread_entry(void *parameter) { int result; g_switch_timer = rt_timer_create("switch_channel", airkiss_switch_channel, RT_NULL, AIRKISS_SWITCH_TIMER, RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_PERIODIC); if (!g_switch_timer) { rt_kprintf("Create airkiss swtich channel timer failed \n"); goto _exit; } g_doing_timer = rt_timer_create("doing_timeout", airkiss_doing_timeout, RT_NULL, AIRKISS_DOING_TIMER, RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT); if (!g_doing_timer) { rt_kprintf("Create airkiss doing timeout timer failed \n"); goto _exit; } g_cfg_done_sem = rt_sem_create("tlink", 0, RT_IPC_FLAG_FIFO); if (!g_cfg_done_sem) { rt_kprintf("Create airkiss config done sem failed! \n"); goto _exit; } ak_contex = (airkiss_context_t *)rt_malloc(sizeof(airkiss_context_t)); if (!ak_contex) { rt_kprintf("Malloc memory for airkiss context \n"); goto _exit; } result = airkiss_init(ak_contex, &ak_conf); if (result != RT_EOK) { rt_kprintf("Airkiss init failed!!\r\n"); goto _exit; } AIRKISS_PRINTF("Airkiss version: %s\r\n", airkiss_version()); g_wlan_device = (struct rt_wlan_device *)rt_device_find(WIFI_DEVICE_STA_NAME); if (g_wlan_device == RT_NULL) { rt_kprintf("Device not found\n"); return; } g_current_channel = 1; rt_wlan_set_channel(g_wlan_device, g_current_channel); rt_wlan_set_monitor_callback(g_wlan_device, airkiss_monitor_callback); rt_wlan_cfg_monitor(g_wlan_device, WIFI_MONITOR_START); rt_timer_start(g_switch_timer); if (rt_sem_take(g_cfg_done_sem, rt_tick_from_millisecond(1000 * 90)) != RT_EOK) { AIRKISS_PRINTF("Wait semaphore timeout \n"); } if (airkiss_recv_ret == AIRKISS_STATUS_COMPLETE) { int8_t err; int8_t tick = 0; airkiss_result_t result; err = airkiss_get_result(ak_contex, &result); if (err == 0) { AIRKISS_PRINTF("airkiss_get_result() ok!\n"); AIRKISS_PRINTF(" ssid = %s \n pwd = %s \n, ssid_length = %d \n pwd_length = %d \n, random = 0x%02x\r\n", result.ssid, result.pwd, result.ssid_length, result.pwd_length, result.random); } rt_wlan_cfg_monitor(g_wlan_device, WIFI_MONITOR_STOP); rt_wlan_set_monitor_callback(g_wlan_device, RT_NULL); station_connect(result.ssid, result.pwd); do { tick++; rt_thread_delay(rt_tick_from_millisecond(1000)); if (tick >= 30) { rt_kprintf("GET IP Time Out!!! \n"); goto _exit; } } while (!get_wifi_status(g_wlan_device->parent.netif)); { rt_thread_t tid; tid = rt_thread_create("air_echo", airkiss_send_notification_thread, (void *)result.random, 1536, RT_THREAD_PRIORITY_MAX - 3, 20); if (tid != RT_NULL) { rt_thread_startup(tid); } } } _exit: if (g_switch_timer != RT_NULL) { rt_timer_stop(g_switch_timer); rt_timer_delete(g_switch_timer); } if (g_doing_timer != RT_NULL) { rt_timer_stop(g_doing_timer); rt_timer_delete(g_doing_timer); } if (ak_contex != RT_NULL) { rt_free(ak_contex); ak_contex = RT_NULL; } if (g_cfg_done_sem != RT_NULL) { rt_sem_delete(g_cfg_done_sem); g_cfg_done_sem = RT_NULL; } }
2. 配置
配置步骤一:组件下载
smartconfig
包,从GitHub下载获取。smartconfig
文件放在支持板的 BSP.Publish Ginger PA6/PA6X 系统路径下。rtconfig.h
文件,在文件尾部添加以下宏定义:#define RT_CFG_USE_AIRKISS 1 #define RT_CFG_AIRKISS_TX_CHANNEL 6 #define RT_CFG_AIRKISS_RX_CHANNEL 7 #define RT_CFG_AIRKISS_FEATURE_LOG 1
配置步骤二:编译与配置
2-net/6-config_airkiss
文件夹。Import('RTT_ROOT')Import('rtconfig') from building import * cwd = GetCurrentDir() src = Glob('2-net/6-config_airkiss/*.c') CPPPATH = [cwd] group = DefineGroup('Applications', src, depend = ['']) CPPPATH = CPPPATH + [group.CPPPATH] Return('group')
三、下载与运行
下载
通过ancode build工具获取最新版 rtthread_1M.FLS
Bin文件。
烧录
将固件烧录至开发板。
配网流程
四、结语
总结
在实际应用中,需注意以下几点:
- 定期更新配置文件版本,避免因版本冲突导致配网失败。
- 此方法依赖于无线环境稳定性,安静的网络环境更有利于成功配网。
- 建议将配网逻辑放在专用线程处理,避免影响主线程性能。
如需进一步了解或调试,可访问相关技术社区或开发者论坛,如:
以上内容可根据实际需求进行调整,协助解决实际场景中的配网问题。
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2025年05月01日 11时23分30秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
MapStruct 映射过程中忽略某个字段
2025-04-12
MapStruct 超神进阶用法,让你的代码效率提升十倍!
2025-04-12
MapXtreme 2005 学习心得 一些基础函数代码(四)
2025-04-12
Map中key和value值是否可以为null或空字符串?
2025-04-12
map函数
2025-04-12
map反转key value
2025-04-12
map和bean的相互转换
2025-04-12
map和filter使用方法与区别
2025-04-12
Map如何获取所有value的值
2025-04-12
Map存入的数据丢失类型任意
2025-04-12
Map排序
2025-04-12
Map的深浅拷贝的探究
2025-04-12
Map的遍历方式
2025-04-12
map遍历测试结果
2025-04-12
Map集合
2025-04-12
Map集合循环遍历的几种方式
2025-04-12
Map(关联式容器)
2025-04-12
Mariadb 分表
2025-04-12
MariaDB密码重置
2025-04-12