Просмотр исходного кода

add: 添加airkiss支持,然而一次都没成功过

Wendal Chen 6 лет назад
Родитель
Сommit
f455a3a961
6 измененных файлов с 2140 добавлено и 16 удалено
  1. 1 0
      README.md
  2. 2 2
      luat/SConscript
  3. 40 14
      luat/modules/luat_lib_wlan.c
  4. 1263 0
      luat/packages/airkiss/airkiss.c
  5. 259 0
      luat/packages/airkiss/airkiss.h
  6. 575 0
      luat/rtt/rtt_airkiss.c

+ 1 - 0
README.md

@@ -42,6 +42,7 @@ TODO: 构建工具链,IDE,刷机工具,等等
 * [rtt-ds18b20](https://github.com/willianchanlovegithub/ds18b20) 在RT-Thread环境下读取ds18b20
 * [LuaTask](https://github.com/openLuat/Luat_2G_RDA_8955) 合宙LuaTask
 * [iRTU](https://github.com/hotdll/iRTU) 基于Luat的DTU
+* [airkissOpen](https://github.com/heyuanjie87/airkissOpen)
 
 ## 授权协议
 

+ 2 - 2
luat/SConscript

@@ -3,8 +3,8 @@ Import('rtconfig')
 from building import *
 
 cwd = GetCurrentDir()
-src	= Glob('modules/*.c') + Glob('rtt/*.c') + Glob('w60x/*.c') + Glob('packages/lfs/*.c')
-CPPPATH = [cwd + "/inculde", cwd + "/packages/lfs/"]
+src	= Glob('modules/*.c') + Glob('rtt/*.c') + Glob('w60x/*.c') + Glob('packages/lfs/*.c') + Glob('packages/airkiss/*.c')
+CPPPATH = [cwd + "/inculde", cwd + "/packages/lfs/", cwd + "/packages/airkiss/"]
 
 group = DefineGroup('luat', src, depend = [''], CPPPATH = CPPPATH)
 

+ 40 - 14
luat/modules/luat_lib_wlan.c

@@ -226,15 +226,12 @@ static void reg_wlan_callbacks(void) {
     rt_wlan_register_event_handler(RT_WLAN_EVT_AP_DISASSOCIATED, wlan_cb, RT_NULL);
 }
 
-//--------------------------
-#ifdef WM_USING_ONESHOT
-static int32_t oneshot_autojoin = 0;
-static int32_t oneshot_re;
-
-static int luat_oneshot_msghandler(lua_State *L, void* ptr) {
+// ----------------------------
+//-----------------------------
+static int luat_PW_msghandler(lua_State *L, void* ptr) {
     lua_getglobal(L, "sys_pub");
     if (!lua_isnil(L, -1)) {
-        lua_pushstring(L, "ONESHOT_RE");
+        lua_pushstring(L, "WLAN_PW_RE");
         if (ptr == RT_NULL) {
             lua_call(L, 1, 0);
         }
@@ -249,16 +246,16 @@ static int luat_oneshot_msghandler(lua_State *L, void* ptr) {
     return 1;
 }
 
-static void _wm_oneshot_callback(int state, unsigned char *_ssid, unsigned char *_passwd) {
-    rt_kprintf("oneshot callback state=%ld\n", state);
+static void _PW_callback(int state, unsigned char *_ssid, unsigned char *_passwd) {
+    rt_kprintf("oneshot/airkiss callback state=%ld\n", state);
     if (_ssid != RT_NULL) {
-        rt_kprintf("oneshot ssid %s\n", _ssid);
+        rt_kprintf("oneshot/airkiss ssid %s\n", _ssid);
     }
     if (_passwd != RT_NULL) {
-        rt_kprintf("oneshot key %s\n", _passwd);
+        rt_kprintf("oneshot/airkiss key %s\n", _passwd);
     }
+    rt_memset(&jinfo, 0, sizeof(struct join_info));
     if (state == 0) {
-        rt_memset(&jinfo, 0, sizeof(struct join_info));
         rt_strncpy(jinfo.ssid, _ssid, rt_strlen(_ssid));
         if (_passwd)
         {
@@ -268,15 +265,22 @@ static void _wm_oneshot_callback(int state, unsigned char *_ssid, unsigned char
     
     // 发送msgbus消息
     rtos_msg_t msg;
-    msg.handler = luat_oneshot_msghandler;
+    msg.handler = luat_PW_msghandler;
     msg.ptr = state == 0 ? (void*)1 : RT_NULL;
     luat_msgbus_put(&msg, 1);
 }
+
+//--------------------------
+#ifdef WM_USING_ONESHOT
+static int32_t oneshot_autojoin = 0;
+static int32_t oneshot_re;
+
+
 static int l_wlan_oneshot_start(lua_State *L) {
     WM_ONESHOT_MODE mode = (WM_ONESHOT_MODE)luaL_optinteger(L, 1, WM_UDP);
     oneshot_autojoin = luaL_optinteger(L, 2, 1);
     rt_kprintf("oneshot mode=%d\n", mode);
-    int re = wm_oneshot_start(mode, _wm_oneshot_callback);
+    int re = wm_oneshot_start(mode, _PW_callback);
     rt_kprintf("oneshot re=%ld\n", re);
     lua_pushinteger(L, re);
     return 1;
@@ -292,6 +296,26 @@ static int l_wlan_oneshot_state(lua_State *L) {
 #endif
 //--------------------------
 
+static int l_wlan_join_info(lua_State *L) {
+    if (jinfo.ssid[0] != RT_NULL) {
+        lua_pushstring(L, jinfo.ssid);
+        if (jinfo.passwd[0] != RT_NULL) {
+            lua_pushstring(L, jinfo.passwd);
+            return 2;
+        }
+        return 1;
+    }
+    return 0;
+}
+
+// airkiss open
+
+static int l_wlan_airkiss_start(lua_State* L){
+    rt_wlan_set_mode("wlan0", RT_WLAN_STATION);
+    airkiss_set_callback(_PW_callback);
+    lua_pushinteger(L, airkiss_start());
+    return 1;
+}
 
 #include "rotable.h"
 static const rotable_Reg reg_wlan[] =
@@ -315,6 +339,8 @@ static const rotable_Reg reg_wlan[] =
     { "oneshotStop" ,   l_wlan_oneshot_stop ,  0},
     { "oneshotState" ,  l_wlan_oneshot_state , 0},
     #endif
+    { "lastInfo" ,      l_wlan_join_info , 0},
+    { "airkiss_start",  l_wlan_airkiss_start, 0},
     // ---
     
     { "NONE",      NULL , RT_WLAN_NONE},

+ 1263 - 0
luat/packages/airkiss/airkiss.c

@@ -0,0 +1,1263 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author           Notes
+ * 2019-05-16     heyuanjie87      first version
+*/
+
+#include "airkiss.h"
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef AIRKISS_LOG_ENABLE
+#define AKLOG_D                     \
+    if (lc->cfg && lc->cfg->printf) \
+    lc->cfg->printf
+#else
+#define AKLOG_D(...)
+#endif
+
+#define AKSTATE_WFG 0
+#define AKSTATE_WFM 1
+#define AKSTATE_WFP 2
+#define AKSTATE_WFD 4
+#define AKSTATE_CMP 5
+
+typedef uint16_t akwire_seq_t;
+
+typedef struct
+{
+    uint16_t val[6];
+    uint8_t pos;
+    uint8_t scnt; /* 成功计数 */
+    uint8_t err;
+    uint8_t rcnt; /* 接收计数 */
+} akcode_t;
+
+typedef struct
+{
+    akwire_seq_t ws;
+    uint8_t crc;
+    uint8_t ind;
+}akdatf_seq_t;
+
+typedef struct
+{
+    uint8_t crc;
+    uint8_t ind;
+}akdatf_header_t;
+
+typedef struct
+{
+    uint8_t id[4];
+}akaddr_t;
+
+typedef struct
+{
+    akwire_seq_t ws;
+    uint8_t val[4];
+    uint8_t pos : 4;
+    uint8_t scnt : 4;
+    uint8_t err;
+    uint8_t wval;
+    uint8_t seqcnt;
+    akaddr_t sa;
+} akcode_guide_t;
+
+typedef struct
+{
+    char data[16]; /* 保留后4个 */
+    uint8_t pos[16];
+}akdatf_conflict_t;
+
+typedef struct
+{
+    union {
+        akcode_guide_t code1[3];
+        akcode_t code2[1];
+    } uc;
+
+    akdatf_conflict_t dcfl; /* 记录有冲突的数据 */
+    akwire_seq_t prews;
+    akdatf_seq_t preseq;
+    akdatf_seq_t curseq;
+    akdatf_header_t pendseq[10]; /* 未完成的序列 */
+    akaddr_t locked;
+
+    uint8_t seqstep;/* 序列增量 */
+    uint8_t reclen;
+    uint8_t state;
+    uint8_t nossid;
+    uint8_t seq[16]; /* 标记已完成的序列 */
+
+    char data[66];
+    uint8_t random;
+    uint8_t baselen;
+    uint8_t prslen;
+    uint8_t ssidcrc;
+    uint8_t pwdlen;
+    const airkiss_config_t *cfg;
+} akloc_context_t;
+
+#define AKLOC_CODE1(x, i) ((x)->uc.code1[i])
+#define AKLOC_CODE2(x) (&(x)->uc.code2[0])
+
+#define AKLOC_DFSEQ_PREV(lc) ((lc)->preseq)
+#define AKLOC_DFSEQ_CUR(lc) ((lc)->curseq)
+
+unsigned char airkiss_crc8(unsigned char *message, unsigned char len)
+{
+    uint8_t crc = 0;
+    uint8_t i;
+
+    while (len--)
+    {
+        crc ^= *message++;
+        for (i = 0; i < 8; i++)
+        {
+            if (crc & 0x01)
+                crc = (crc >> 1) ^ 0x8c;
+            else
+                crc >>= 1;
+        }
+    }
+
+    return crc;
+}
+
+static akwire_seq_t akwseq_make(uint8_t seq[2])
+{
+    akwire_seq_t ws = 0;
+
+    ws = (seq[1] << 4) | (seq[0] >> 4);
+
+    return ws;
+}
+
+static void akloc_reset(akloc_context_t *lc)
+{
+    const airkiss_config_t *cfg;
+
+    cfg = lc->cfg;
+    memset(lc, 0, sizeof(*lc));
+    lc->cfg = cfg;
+}
+
+static uint8_t akinfo_getu8(uint16_t v[2])
+{
+    uint8_t ret = 0;
+
+    ret = ((v[0] & 0xF) << 4) | (v[1] & 0xF);
+
+    return ret;
+}
+
+static uint16_t aklen_udp(akloc_context_t *lc, uint16_t len)
+{
+    return (len - lc->baselen);
+}
+
+static int ak_get_magicfield(akloc_context_t *lc, akcode_t *ac)
+{
+    int ret = 1;
+
+    if (ac->val[0] == 8)
+        ac->val[0] = 0;
+    lc->prslen = akinfo_getu8(&ac->val[0]);
+    lc->ssidcrc = akinfo_getu8(&ac->val[2]);
+
+    if (lc->prslen > (sizeof(lc->data) - 1))
+    {
+        ret = 0;
+        AKLOG_D("prslen(%d) large than(%d)", lc->prslen, (sizeof(lc->data) - 1));
+    }
+
+    return ret;
+}
+
+static int ak_magicfield_input(akcode_t *ac, uint16_t len)
+{
+    int mc;
+
+    mc = len >> 4;
+    if (mc == 0)
+    {
+        ac->val[0] = len;
+        ac->pos = 1;
+    }
+    else if (mc == ac->pos)
+    {
+        ac->val[ac->pos] = len;
+        ac->pos ++;
+    }
+    else
+    {
+        ac->pos = 0;
+    }
+
+    return (ac->pos == 4);
+}
+
+static int ak_get_prefixfield(akloc_context_t *lc, akcode_t *ac)
+{
+    int ret;
+    uint8_t crc;
+
+    lc->pwdlen = akinfo_getu8(&ac->val[0]);
+    crc = akinfo_getu8(&ac->val[2]);
+    if (airkiss_crc8(&lc->pwdlen, 1) != crc)
+        ret = 0;
+
+    return ret;
+}
+
+static int ak_prefixfield_input(akcode_t *ac, uint16_t len)
+{
+    int mc;
+
+    mc = len >> 4;
+    if (mc == 4)
+    {
+        ac->val[0] = len;
+        ac->pos = 1;
+    }
+    else if (mc == (ac->pos + 4))
+    {
+        ac->val[ac->pos] = len;
+        ac->pos ++;
+    }
+    else
+    {
+        ac->pos = 0;
+    }
+
+    return (ac->pos == 4);
+}
+
+static int ak_get_datafield(akloc_context_t *lc, akcode_t *ac)
+{
+    uint8_t tmp[6];
+    int n;
+    int ret = 0;
+    int pos;
+    int seqi;
+
+    seqi = ac->val[1] & 0x7f;
+    if (seqi > (lc->prslen/4))
+    {
+        return 0;
+    }
+
+    if (lc->seq[seqi])
+        return 0;
+
+    pos = seqi * 4;
+    n = lc->prslen - pos;
+    if (n > 4)
+        n = 4;
+
+    tmp[0] = ac->val[0] & 0x7F;
+    tmp[1] = ac->val[1] & 0x7F;
+    tmp[2] = ac->val[2] & 0xFF;
+    tmp[3] = ac->val[3] & 0xFF;
+    tmp[4] = ac->val[4] & 0xFF;
+    tmp[5] = ac->val[5] & 0xFF;
+
+    ret = ((airkiss_crc8(&tmp[1], n + 1) & 0x7F) == tmp[0]);
+    if (ret)
+    {
+        memcpy(&lc->data[pos], &tmp[2], n);
+        lc->reclen += n;
+        lc->seq[seqi] = 1;
+
+#ifdef AIRKISS_LOG_GDO_ENABLE
+        AKLOG_D("getdata(%d, %d)\n", seqi, n);
+#endif
+    }
+
+    return ret;
+}
+
+static void akaddr_fromframe(akaddr_t *a, uint8_t *f)
+{
+    f += 10;
+
+    a->id[0] = f[4];
+    a->id[1] = f[5];
+    a->id[2] = f[10];
+    a->id[3] = f[11];
+}
+
+static akcode_guide_t *ak_guide_getcode(akloc_context_t *lc, unsigned char *f)
+{
+    akcode_guide_t *ac;
+
+    if (f == NULL) /* 是模拟测试 */
+    {
+        ac = &AKLOC_CODE1(lc, 2);
+    }
+    else
+    {
+        akaddr_t sa;
+        unsigned i;
+        int found = 0;
+        akcode_guide_t *imin;
+
+        akaddr_fromframe(&sa, f);
+        imin = &AKLOC_CODE1(lc, 0);
+        ac = imin;
+        for (i = 0; i < sizeof(lc->uc.code1) / sizeof(lc->uc.code1[0]); i++)
+        {
+            /* 匹配地址 */
+            found = !memcmp(&sa, &ac->sa, sizeof(ac->sa));
+            if (found)
+                break;
+            /* 记录权值最小的 */
+            if (ac->wval < imin->wval)
+                imin = ac;
+            ac++;
+        }
+
+        if (!found)
+        {
+            /* 淘汰输入最少的 */
+            ac = imin;
+            ac->pos = 0;
+            ac->err = 0;
+            ac->scnt = 0;
+            ac->wval = 0;
+            ac->sa = sa;
+        }
+    }
+
+    return ac;
+}
+
+static int ak_guidefield_input(akcode_guide_t *ac, uint8_t *f, uint16_t len)
+{
+    akwire_seq_t ws = 0;
+
+    if (f)
+        ws = akwseq_make(f + 22);
+
+    if (ac->pos < 4)
+    {
+        if ((ac->pos != 0) && ((len - ac->val[ac->pos - 1]) != 1))
+        {
+            ac->pos = 0;
+            if (ac->wval > 0)
+                ac->wval--;
+        }
+
+        if (ac->pos == 0)
+        {
+            ac->ws = ws;
+            ac->seqcnt = 0;
+        }
+        ac->seqcnt += (ws - ac->ws);
+
+        ac->val[ac->pos] = len;
+        ac->pos++;
+        ac->wval += ac->pos;
+    }
+
+    return (ac->pos == 4);
+}
+
+static int ak_waitfor_guidefield(akloc_context_t *lc, uint8_t *f, uint16_t len)
+{
+    int ret = AIRKISS_STATUS_CONTINUE;
+    akcode_guide_t *ac;
+
+    ac = ak_guide_getcode(lc, f);
+
+    if (ak_guidefield_input(ac, f, len))
+    {
+        ac->pos = 0;
+        ac->scnt++;
+
+        /* 至少两次相同的guide code才算获取成功 */
+        if ((ac->scnt >= 2) && ac->wval >= 20)
+        {
+            lc->state = AKSTATE_WFM;
+            lc->baselen = ac->val[0] - 1;
+            lc->seqstep = ac->seqcnt/6;
+
+            AKLOG_D("guide baselen(%d) seqstep(%d)\n", lc->baselen, lc->seqstep);
+        }
+
+        if (lc->state == AKSTATE_WFM)
+        {
+            lc->locked = ac->sa;
+            memset(&lc->uc, 0, sizeof(lc->uc));
+            ret = AIRKISS_STATUS_CHANNEL_LOCKED;
+        }
+    }
+
+    return ret;
+}
+
+static int ak_waitfor_magicfield(akloc_context_t *lc, uint16_t len)
+{
+    int ret = AIRKISS_STATUS_CONTINUE;
+    akcode_t *ac = AKLOC_CODE2(lc);
+    int udplen;
+
+    udplen = aklen_udp(lc, len);
+
+    if (ak_magicfield_input(ac, udplen))
+    {
+        ac->pos = 0;
+
+        if (ak_get_magicfield(lc, ac))
+        {
+            lc->state = AKSTATE_WFP;
+
+            AKLOG_D("magic: prslen(%d) ssidcrc(%X)\n", lc->prslen, lc->ssidcrc);
+        }
+    }
+
+    if (ac->rcnt++ > 250)
+    {
+        akloc_reset(lc);
+        AKLOG_D("reset from magic\n");
+    }
+
+    return ret;
+}
+
+static int ak_waitfor_prefixfield(akloc_context_t *lc, uint16_t len)
+{
+    int ret = AIRKISS_STATUS_CONTINUE;
+    akcode_t *ac = AKLOC_CODE2(lc);
+    int udplen;
+
+    udplen = aklen_udp(lc, len);
+
+    if (ak_prefixfield_input(ac, udplen))
+    {
+        ac->pos = 0;
+
+        if (ak_get_prefixfield(lc, ac))
+        {
+            lc->state = AKSTATE_WFD;
+
+            AKLOG_D("prefix: pwdlen(%d)\n", lc->pwdlen);
+        }
+    }
+
+    return ret;
+}
+
+#ifdef AIRKISS_LOG_DFDUMP_ENABLE
+static void akdata_dump(akloc_context_t *lc, uint8_t *f, uint16_t len)
+{
+    uint8_t seq[2];
+    uint16_t dseq;
+
+    seq[0] = f[22];
+    seq[1] = f[23];
+
+    dseq = (seq[1] << 4) | (seq[0]>> 4);
+    if (len & 0x100)
+    {
+        AKLOG_D("(%d) %X %c", dseq, len, len & 0xff);
+    }
+    else
+    {
+        AKLOG_D("(%d) %X", dseq, len);
+    }
+}
+#endif
+
+/*
+  只判断密码和random是否收完
+*/
+static int ak_is_pwdrand_complete(akloc_context_t *lc)
+{
+    int ret = 0;
+    unsigned i;
+    int n = 0;
+
+    for (i = 0; i < (sizeof(lc->seq) / sizeof(lc->seq[0])); i++)
+    {
+        if (lc->seq[i] == 0)
+            break;
+
+        n += 4;
+        if (n >= (lc->pwdlen + 1))
+        {
+            ret = 1;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static int ak_datainput_onlylength(akloc_context_t *lc, akcode_t *ac, uint16_t len)
+{
+    int n = 6;
+
+    if (len & 0x100)
+    {
+        if (ac->pos > 1)
+        {
+            int size;
+
+            ac->val[ac->pos] = len;
+            ac->pos ++;
+
+            size = (ac->val[1] & 0x7f) * 4;
+            if (size <  lc->prslen)
+            {
+                size = lc->prslen - size;
+                if (size < 4) /* 最后一个包不足4 */
+                {
+                    n = size + 2;
+                }
+            }
+        }
+        else
+        {
+            ac->pos = 0;
+        }
+    }
+    else
+    {
+        if (ac->pos < 2)
+        {
+            ac->val[ac->pos] = len;
+            ac->pos ++;
+        }
+        else
+        {
+            ac->val[0] = len;
+            ac->pos = 1;
+        }
+    }
+
+    return (ac->pos == n);
+}
+
+static akdatf_header_t* akseq_getpend(akloc_context_t *lc, uint8_t ind)
+{
+    akdatf_header_t* ret = 0;
+    unsigned i;
+
+    for (i = 0; i < sizeof(lc->pendseq)/sizeof(lc->pendseq[0]); i ++)
+    {
+        akdatf_header_t *p = &lc->pendseq[i];
+
+        if (p->ind == ind)
+        {
+            ret = p;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static int ak_pendinput_mark(akloc_context_t *lc, uint8_t ind)
+{
+    int ret = 0;
+    akdatf_header_t* pd;
+
+    pd = akseq_getpend(lc, ind);
+    if (pd)
+    {
+        int size, pos, i;
+        char d[6] = {0};
+        uint8_t crc;
+
+        ind = ind & 0x7f;
+        pos = ind * 4;
+        size = lc->prslen - pos;
+        if (size > 4)
+            size = 4;
+
+        for (i = 0; i < size; i ++)
+        {
+            if (lc->data[pos + i] == 0)
+                return 0;
+        }
+
+        d[0] = ind;
+        memcpy(&d[1], &lc->data[pos], size);
+        crc = airkiss_crc8((uint8_t*)d, size + 1) & 0x7f;
+        if (crc == (pd->crc & 0x7f))
+        {
+            memset(pd, 0, sizeof(*pd));
+            lc->seq[ind] = 1;
+            lc->reclen += size;
+            ret = 1;
+
+#ifdef AIRKISS_LOG_GDO_ENABLE
+            AKLOG_D("getdata-p(%d, %d)[%s]", ind, size, &d[1]);
+#endif
+        }
+    }
+
+    return ret;
+}
+
+static int ak_penddata_getpos(akloc_context_t *lc, akdatf_seq_t *ref, akwire_seq_t ws)
+{
+    int ret = -1;
+    uint8_t refind, ind;
+    int offs;
+
+    if (ws < ref->ws)
+    {//todo
+        AKLOG_D("ws-d overflow(%d, %d)", ws, ref->ws);
+    }
+    else
+    {
+        int maxoffs;
+        int fmpos;
+
+        offs = (ws - ref->ws)/lc->seqstep;
+        if ((offs % 6) < 2)
+            return -1;
+        maxoffs = lc->prslen + ((lc->prslen + 3)/4) * 2;
+        if (offs > maxoffs) /* 相差太大出错几率增大 */
+            return ret;
+
+        refind = ref->ind & 0x7f;
+        fmpos = refind * 6 + offs;
+        fmpos = fmpos % maxoffs; /* 指向下一轮 */
+        ind = fmpos/6;
+
+        ret = ind * 4 + (fmpos % 6) - 2;
+    }
+
+    return ret;
+}
+
+static int ak_pendcrc_getpos(akloc_context_t *lc, akdatf_seq_t *ref, akwire_seq_t ws)
+{
+    int offs;
+    int pos = -1;
+    int maxoffs;
+
+    maxoffs = lc->prslen + ((lc->prslen + 3)/4) * 2;
+
+    if (ws < ref->ws)
+    {//todo
+        AKLOG_D("ws-c overflow(%d, %d)", ws, ref->ws);
+    }
+    else
+    {
+        offs = (ws - ref->ws)/lc->seqstep;
+        if (offs > maxoffs)
+            return -1;
+        offs = offs + (ref->ind & 0x7f) * 6;
+        offs = offs % maxoffs;
+        pos = (offs/6) | 0x80;
+    }
+
+    return pos;
+}
+
+static void ak_dataconflict_add(akloc_context_t *lc, uint8_t pos, uint8_t d, int mode)
+{
+    unsigned i;
+    int zi = -1;
+    int s, e;
+
+    pos ++;
+    if (mode == 0)
+    {
+        s = 0;
+        e = sizeof(lc->dcfl.pos) - 4;
+    }
+    else
+    {
+        s = sizeof(lc->dcfl.pos) - 4;
+        e = sizeof(lc->dcfl.pos);
+    }
+
+    for (i = s; i < e; i ++)
+    {
+        if ((lc->dcfl.pos[i] == pos) && (lc->dcfl.data[i] == d))
+            return;
+        if (lc->dcfl.pos[i] == 0)
+            zi = i;
+    }
+
+    if (zi >= 0)
+    {
+        lc->dcfl.data[zi] = d;
+        lc->dcfl.pos[zi] = pos;
+    }
+}
+
+static int ak_dataconflict_getchar(akloc_context_t *lc, uint8_t pos, uint8_t *cpos)
+{
+    int ch = -1;
+    uint8_t i;
+
+    if (*cpos >= sizeof(lc->dcfl.pos))
+        return -1;
+
+    pos ++;
+    for (i = *cpos; i < sizeof(lc->dcfl.pos); i ++)
+    {
+        if (lc->dcfl.pos[i] == pos)
+        {
+            ch = lc->dcfl.data[i];
+            i ++;
+            break;
+        }
+    }
+
+    *cpos = i;
+
+    return ch;
+}
+
+static void ak_dataconflict_clear(akloc_context_t *lc, int pos)
+{
+    unsigned i;
+
+    if (pos < 0)
+    {
+        i = sizeof(lc->dcfl.pos) - 4;
+        for (; i < sizeof(lc->dcfl.pos); i ++)
+        {
+            lc->dcfl.pos[i] = 0;
+            lc->dcfl.data[i] = 0;
+        }
+    }
+    else
+    {
+        pos ++;
+        for (i = 0; i < sizeof(lc->dcfl.pos) - 4; i ++)
+        {
+            if (lc->dcfl.pos[i] == pos)
+            {
+                lc->dcfl.pos[i] = 0;
+                lc->dcfl.data[i] = 0;
+            }
+        }
+    }
+}
+
+static int _dataconflict_crccheck(akloc_context_t *lc, akdatf_header_t* pd, uint8_t dpos, char *d, int size)
+{
+    int ret = 0;
+    uint8_t crc;
+
+    crc = airkiss_crc8((uint8_t*)d, size + 1) & 0x7f;
+    if (crc == (pd->crc & 0x7f))
+    {
+        int pos;
+
+        pos = (pd->ind & 0x7f) * 4;
+        memcpy(&lc->data[pos], &d[1], size);
+        memset(pd, 0, sizeof(*pd));
+        lc->seq[(uint8_t)d[0]] = 1;
+        lc->reclen += size;
+        ak_dataconflict_clear(lc, dpos);
+        ret = 1;
+
+#ifdef AIRKISS_LOG_GDO_ENABLE
+        AKLOG_D("getdata-c(%d, %d)[%s]", d[0], size, &d[1]);
+#endif
+    }
+
+    return ret;
+}
+
+static int ak_dataconflict_crccheck(akloc_context_t *lc, akdatf_header_t* pd, int size)
+{
+    char d[6] = {0};
+    uint8_t spos;
+    uint8_t cflpos0 = 0, cflpos1 = 0, cflpos2 = 0, cflpos3 = 0;
+    int i;
+
+    d[0] = pd->ind & 0x7f;
+    spos = d[0] * 4;
+
+    /* 把所有冲突的数据都校验一遍 */
+
+    for (i = 0; i < size; i ++)
+    {
+        ak_dataconflict_add(lc, spos + i, lc->data[spos + i], 1);
+    }
+
+    while (size > 0)
+    {
+        int ch;
+
+        ch = ak_dataconflict_getchar(lc, spos + 0, &cflpos0);
+        if (ch < 0)
+            break;
+        d[1] = ch;
+        cflpos1 = 0;
+
+        while (size > 1)
+        {
+            int ch;
+
+            ch = ak_dataconflict_getchar(lc, spos + 1, &cflpos1);
+            if (ch < 0)
+                break;
+            d[2] = ch;
+            cflpos2 = 0;
+
+            while (size > 2)
+            {
+                int ch;
+
+                ch = ak_dataconflict_getchar(lc, spos + 2, &cflpos2);
+                if (ch < 0)
+                    break;
+                d[3] = ch;
+                cflpos3 = 0;
+
+                while (size > 3)
+                {
+                    int ch;
+
+                    ch = ak_dataconflict_getchar(lc, spos + 3, &cflpos3);
+                    if (ch < 0)
+                        break;
+                    d[4] = ch;
+
+                    if (_dataconflict_crccheck(lc, pd, spos + 3, d, size))
+                    {
+                        goto _out;
+                    }
+                }
+            }
+        }
+    }
+
+_out:
+    ak_dataconflict_clear(lc, -1);
+
+    return 0;
+}
+
+static int ak_dataconflict_input(akloc_context_t *lc, uint8_t ind, uint8_t pos, uint8_t data)
+{
+    int ret = 0;
+    int i;
+    int size;
+    int spos;
+    akdatf_header_t* pd;
+
+    spos = ind * 4;
+    size = lc->prslen - spos;
+    if (size > 4)
+        size = 4;
+
+    ak_dataconflict_add(lc, pos, data, 0);
+
+    /* 检查接收是否足够 */
+    for (i = 0; i < size; i ++)
+    {
+        if (lc->data[spos + i] == 0)
+        {
+            return 0;
+        }
+    }
+
+    /* 查找包头 */
+    pd = akseq_getpend(lc, ind | 0x80);
+    if (!pd)
+        return 0;
+
+    ret = ak_dataconflict_crccheck(lc, pd, size);
+
+    return ret;
+}
+
+static int ak_databody_input(akloc_context_t *lc, akdatf_seq_t *ref, akwire_seq_t ws, uint8_t data)
+{
+    int pos;
+    uint8_t ind;
+    uint8_t dif;
+
+    /* 与上一个帧相差太大则不接受 */
+    dif = (ws - lc->prews)/lc->seqstep;
+    if (dif > 5)
+        return 0;
+
+    pos = ak_penddata_getpos(lc, ref, ws);
+    if (pos < 0)
+    {
+        return 0;
+    }
+
+    ind = pos / 4;
+    if (lc->seq[ind])
+    {
+        return 0;
+    }
+
+#if AIRKISS_LOG_RIO_ENABLE
+    AKLOG_D("ref(%d %X) input(%d) %c", ref->ws, ref->ind, pos, data);
+#endif
+
+    if (lc->data[pos] == 0)
+    {
+        lc->data[pos] = data;
+        ak_pendinput_mark(lc, ind | 0x80);
+    }
+    else if (lc->data[pos] != data)
+    {
+        /* 出现数据冲突 */
+        ak_dataconflict_input(lc, ind, (uint8_t)pos, data);
+    }
+
+    return 1;
+}
+
+static void akseq_allocpend(akloc_context_t *lc, uint8_t crc, uint8_t ind)
+{
+    akdatf_header_t *found = 0, *idle = 0;
+    unsigned i;
+
+    if (lc->seq[ind & 0x7f])
+        return;
+
+    AKLOG_D("{%X %X}", crc, ind);
+    idle = &lc->pendseq[0];
+    for (i = 0; i < sizeof(lc->pendseq)/sizeof(lc->pendseq[0]); i ++)
+    {
+        akdatf_header_t *p = &lc->pendseq[i];
+
+        if (p->ind == ind)
+        {
+            found = p;
+            p->crc = crc;
+            break;
+        }
+
+        if (p->crc == 0)
+            idle = p;
+    }
+
+    if (found == NULL)
+    {
+        found = idle;
+        found->crc = crc;
+        found->ind = ind;
+    }
+}
+
+static void ak_datahead_input(akloc_context_t *lc, akdatf_seq_t *cur, akwire_seq_t ws, uint8_t head)
+{
+    int seqmax;
+    uint8_t dif;
+
+    seqmax = (lc->prslen/4) | 0x80;
+
+    if (cur->crc != 0)
+    {
+        dif = (ws - cur->ws)/lc->seqstep;
+
+        if (head <= seqmax)
+        {
+            cur->ind = head;
+            cur->ws = ws - lc->seqstep;
+            AKLOC_DFSEQ_PREV(lc) = *cur;
+
+            if (dif < 3)
+            {
+                /* 暂存包头 */
+                akseq_allocpend(lc, cur->crc, cur->ind);
+            }
+        }
+
+        if (head > seqmax)
+        {
+            cur->crc = head;
+            cur->ind = 0;
+            cur->ws = ws;
+        }
+    }
+    else
+    {
+        if (head > seqmax) //很大几率是crc
+        {
+            cur->crc = head;
+            cur->ws = ws;
+            cur->ind = 0;
+        }
+        else if (ak_pendcrc_getpos(lc, cur, ws) == head)
+        {
+            /* 没收到crc */
+            cur->ind = head;
+            cur->ws = ws - lc->seqstep; /* 设置crc的帧序号 */
+        }
+    }
+}
+
+static int ak_datainput_withwireseq(akloc_context_t *lc, uint8_t *f, uint16_t len)
+{
+    akwire_seq_t ws;
+    akdatf_seq_t *cur;
+
+    ws = akwseq_make(f + 22);
+    cur = &AKLOC_DFSEQ_CUR(lc);
+
+    if (len & 0x100) /* 输入数据 */
+    {
+        akdatf_seq_t *ref;
+
+        ref = &AKLOC_DFSEQ_PREV(lc);
+
+        if ((cur->ind == 0) && (cur->crc != 0))
+        {
+            int pos;
+
+            /* 如果只收到了crc就根据前一个包推测一个序号 */
+            pos = ak_pendcrc_getpos(lc, ref, ws);
+            if (pos > 0)
+            {
+                cur->ind = (uint8_t)pos;
+                akseq_allocpend(lc, cur->crc, cur->ind);
+            }
+        }
+
+        if (cur->ind)
+        {
+            if (!ak_databody_input(lc, cur, ws, len))
+            {
+                memset(&AKLOC_DFSEQ_CUR(lc), 0 , sizeof(*cur));
+            }
+
+            if (lc->reclen == lc->prslen)
+            {
+                lc->state = AKSTATE_CMP;
+            }
+        }
+
+        AKLOC_DFSEQ_CUR(lc).crc = 0;/* 标记已收到数据 */
+    }
+    else
+    {
+        /* 输入包头 */
+        ak_datahead_input(lc, cur, ws, len);
+    }
+
+    lc->prews = ws;
+
+    return 0;
+}
+
+static int ak_waitfor_datafield(akloc_context_t *lc, uint8_t *f, uint16_t len, int nossid)
+{
+    int ret = AIRKISS_STATUS_CONTINUE;
+    akcode_t *ac = AKLOC_CODE2(lc);
+    uint16_t udplen;
+
+    udplen = aklen_udp(lc, len);
+    if (udplen < 0x80)
+    {
+        return ret;
+    }
+
+#ifdef AIRKISS_LOG_DFDUMP_ENABLE
+    if (f)
+    {
+        akdata_dump(lc, f, udplen);
+    }
+#endif
+
+    if (ak_datainput_onlylength(lc, ac, udplen))
+    {
+        ac->pos = 0;
+
+        ak_get_datafield(lc, ac);
+
+        if (lc->reclen == lc->prslen)
+        {
+            lc->state = AKSTATE_CMP;
+            goto _out;
+        }
+    }
+
+    if (f)
+    {
+        ak_datainput_withwireseq(lc, f, udplen);
+    }
+
+    if (nossid && ak_is_pwdrand_complete(lc))
+    {
+        lc->state = AKSTATE_CMP;
+        AKLOG_D("data complete nossid\n");
+    }
+
+_out:
+    if (lc->state == AKSTATE_CMP)
+    {
+        lc->nossid = nossid;
+        ret = AIRKISS_STATUS_COMPLETE;
+    }
+
+    return ret;
+}
+
+static int ak_sa_filter(akloc_context_t *lc, uint8_t *f)
+{
+    int ret = 0;
+
+    if (lc->state != AKSTATE_WFG)
+    {
+        akaddr_t sa;
+
+        akaddr_fromframe(&sa, f);
+        ret = memcmp(&lc->locked, &sa, sizeof(sa));
+    }
+
+    return ret;
+}
+
+int airkiss_filter(const void *f, int len)
+{
+    int ret = 0;
+    unsigned char *da, *p;
+    int i;
+
+    p = (unsigned char *)f;
+    if ((len < 25) || (p[0] != 0x08))
+        return 1;
+
+    da = p + 4;
+
+    for (i = 0; i < 6; i++)
+    {
+        if (da[i] != 0xFF)
+        {
+            ret = 1;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static int _ak_recv(airkiss_context_t *c, const void *frame, uint16_t length, int nossid)
+{
+    int ret = AIRKISS_STATUS_CONTINUE;
+    akloc_context_t *lc = (akloc_context_t *)c;
+    unsigned char *f = (unsigned char *)frame;
+
+    if (frame != NULL) /* 模拟测试时可只传length */
+    {
+        if (airkiss_filter(frame, length))
+            return ret;
+        if (ak_sa_filter(lc, f))
+            return ret;
+    }
+
+    switch (lc->state)
+    {
+    case AKSTATE_WFG:
+    {
+        ret = ak_waitfor_guidefield(lc, f, length);
+    }
+    break;
+    case AKSTATE_WFM:
+    {
+        ret = ak_waitfor_magicfield(lc, length);
+    }
+    break;
+    case AKSTATE_WFP:
+    {
+        ret = ak_waitfor_prefixfield(lc, length);
+    }
+    break;
+    case AKSTATE_WFD:
+    {
+        ret = ak_waitfor_datafield(lc, f, length, nossid);
+    }
+    break;
+    case AKSTATE_CMP:
+    {
+        ret = AIRKISS_STATUS_COMPLETE;
+    }
+    break;
+    }
+
+    return ret;
+}
+
+const char *airkiss_version(void)
+{
+    return "airkiss-1.0.0-open";
+}
+
+int airkiss_init(airkiss_context_t *c, const airkiss_config_t *config)
+{
+    akloc_context_t *lc = (akloc_context_t *)c;
+
+    lc->cfg = config;
+    akloc_reset(lc);
+
+    return 0;
+}
+
+int airkiss_recv(airkiss_context_t *c, const void *frame, unsigned short length)
+{
+    return _ak_recv(c, frame, length, 0);
+}
+
+int airkiss_get_result(airkiss_context_t *c, airkiss_result_t *res)
+{
+    akloc_context_t *lc = (akloc_context_t *)c;
+
+    if (lc->state != AKSTATE_CMP)
+        return -1;
+
+    res->pwd = (char *)&lc->data[0];
+    res->pwd_length = lc->pwdlen;
+    if (lc->data[lc->pwdlen] == 0)
+    {
+        res->random = lc->random;
+    }
+    else
+    {
+        res->random = lc->data[lc->pwdlen];
+        lc->random = lc->data[lc->pwdlen];
+        lc->data[lc->pwdlen] = 0;
+    }
+
+    res->ssid_crc = lc->ssidcrc;
+    if (lc->nossid)
+    {
+        res->ssid = "";
+        res->ssid_length = 0;
+    }
+    else
+    {
+        res->ssid = (char *)&lc->data[lc->pwdlen + 1];
+        res->ssid_length = lc->prslen - lc->pwdlen - 1;
+    }
+    lc->data[lc->prslen] = 0;
+
+    return 0;
+}
+
+int airkiss_recv_nossid(airkiss_context_t *c, const void *frame, unsigned short length)
+{
+    return _ak_recv(c, frame, length, 1);
+}
+
+int airkiss_change_channel(airkiss_context_t *c)
+{
+    akloc_context_t *lc = (akloc_context_t *)c;
+
+    akloc_reset(lc);
+
+    return 0;
+}

+ 259 - 0
luat/packages/airkiss/airkiss.h

@@ -0,0 +1,259 @@
+/*
+ * airkiss.h
+ *
+ *  Created on: 2015-1-26
+ *      Author: peterfan
+ */
+
+#ifndef AIRKISS_H_
+#define AIRKISS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * 定义AIRKISS_ENABLE_CRYPT为1以启用AirKiss加密功能
+ */
+#ifndef AIRKISS_ENABLE_CRYPT
+#define AIRKISS_ENABLE_CRYPT 0
+#endif
+
+
+typedef void* (*airkiss_memset_fn) (void* ptr, int value, unsigned int num);
+typedef void* (*airkiss_memcpy_fn) (void* dst, const void* src, unsigned int num);
+typedef int (*airkiss_memcmp_fn) (const void* ptr1, const void* ptr2, unsigned int num);
+typedef int (*airkiss_printf_fn) (const char* format, ...);
+
+
+/*
+ * 对AirKiss库进行配置,目前仅定义了一些回调函数
+ */
+typedef struct
+{
+	/*
+	 * 为尽量减少库文件体积,如下c标准库函数需要上层使用者提供
+	 * 其中printf可以为NULL
+	 */
+	airkiss_memset_fn memset;
+	airkiss_memcpy_fn memcpy;
+	airkiss_memcmp_fn memcmp;
+	airkiss_printf_fn printf;
+
+} airkiss_config_t;
+
+
+
+/*
+ * AirKiss API工作需要的结构体,必须为全局变量或者通过malloc动态分配
+ */
+typedef struct
+{
+	int dummyap[26];
+	int dummy[32];
+} airkiss_context_t;
+
+
+
+/*
+ * AirKiss解码成功后的结果
+ */
+typedef struct
+{
+	char* pwd;						/* wifi密码,以'\0'结尾 */
+	char* ssid;						/* wifi ssid,以'\0'结尾 */
+	unsigned char pwd_length;		/* wifi密码长度 */
+	unsigned char ssid_length;		/* wifi ssid长度 */
+	unsigned char random;			/* 随机值,根据AirKiss协议,当wifi连接成功后,需要通过udp向10000端口广播这个随机值,这样AirKiss发送端(微信客户端或者AirKissDebugger)就能知道AirKiss已配置成功 */
+    unsigned char ssid_crc;			/* SSID crc8 */
+} airkiss_result_t;
+
+
+
+/*
+ * airkiss_recv()正常情况下的返回值
+ */
+typedef enum
+{
+	/* 解码正常,无需特殊处理,继续调用airkiss_recv()直到解码成功 */
+	AIRKISS_STATUS_CONTINUE = 0,
+
+	/* wifi信道已经锁定,上层应该立即停止切换信道 */
+	AIRKISS_STATUS_CHANNEL_LOCKED = 1,
+
+	/* 解码成功,可以调用airkiss_get_result()取得结果 */
+	AIRKISS_STATUS_COMPLETE = 2
+
+} airkiss_status_t;
+
+
+
+#if AIRKISS_ENABLE_CRYPT
+
+/*
+ * 设置解密key,最长可以为128bit,若传入的key不足128bit,则默认用0填充
+ *
+ * 返回值
+ * 		< 0:出错,通常是参数错误
+ * 		  0:成功
+ */
+int airkiss_set_key(airkiss_context_t* context, const unsigned char* key, unsigned int length);
+
+#endif
+
+
+
+/*
+ * 获取AirKiss库版本信息
+ */
+const char* airkiss_version(void);
+
+
+
+/*
+ * 初始化AirKiss库,如要复用context,可以多次调用
+ *
+ * 返回值
+ * 		< 0:出错,通常是参数错误
+ * 		  0:成功
+ */
+int airkiss_init(airkiss_context_t* context, const airkiss_config_t* config);
+
+
+
+/*
+ * 开启WiFi Promiscuous Mode后,将收到的包传给airkiss_recv以进行解码
+ *
+ * 参数说明
+ * 		frame:802.11 frame mac header(must contain at least first 24 bytes)
+ * 		length:total frame length
+ *
+ * 返回值
+ * 		 < 0:出错,通常是参数错误
+ * 		>= 0:成功,请参考airkiss_status_t
+ */
+int airkiss_recv(airkiss_context_t* context, const void* frame, unsigned short length);
+
+
+
+/*
+ * 当airkiss_recv()返回AIRKISS_STATUS_COMPLETE后,调用此函数来获取AirKiss解码结果
+ *
+ * 返回值
+ * 		< 0:出错,解码状态还不是AIRKISS_STATUS_COMPLETE
+ * 		  0:成功
+ */
+int airkiss_get_result(airkiss_context_t* context, airkiss_result_t* result);
+
+
+/*
+ * 上层切换信道以后,可以调用一下本接口清缓存,降低锁定错信道的概率,注意调用的逻辑是在airkiss_init之后
+ *
+ * 返回值
+ * 		< 0:出错,通常是参数错误
+ * 		  0:成功
+ */
+int airkiss_change_channel(airkiss_context_t* context);
+
+/*
+ *
+ * 以上是实现智能配置网络的相关API,以下是微信内网发现相关API
+ *
+ */
+
+/*
+ * airkiss_lan_recv()的返回值
+ */
+typedef enum
+{
+	/* 提供的数据缓冲区长度不足 */
+	AIRKISS_LAN_ERR_OVERFLOW = -5,
+
+	/* 当前版本不支持的指令类型 */
+	AIRKISS_LAN_ERR_CMD = -4,
+
+	/* 打包数据出错 */
+	AIRKISS_LAN_ERR_PAKE = -3,
+
+	/* 函数传递参数出错 */
+	AIRKISS_LAN_ERR_PARA = -2,
+
+	/* 报文数据错误 */
+	AIRKISS_LAN_ERR_PKG = -1,
+
+	/* 报文格式正确,但是不需要设备处理的数据包 */
+	AIRKISS_LAN_CONTINUE = 0,
+
+	/* 接收到发现设备请求数据包 */
+	AIRKISS_LAN_SSDP_REQ = 1,
+
+	/* 数据包打包完成 */
+	AIRKISS_LAN_PAKE_READY = 2
+
+
+} airkiss_lan_ret_t;
+
+
+typedef enum
+{
+	AIRKISS_LAN_SSDP_REQ_CMD = 0x1,
+	AIRKISS_LAN_SSDP_RESP_CMD = 0x1001,
+	AIRKISS_LAN_SSDP_NOTIFY_CMD = 0x1002
+} airkiss_lan_cmdid_t;
+
+/*
+ * 设备进入内网发现模式后,将收到的包传给airkiss_lan_recv以进行解析
+ *
+ * 参数说明
+ * 		body:802.11 frame mac header(must contain at least first 24 bytes)
+ * 		length:total frame length
+ * 		config:AirKiss回调函数
+ *
+ * 返回值
+ * 		 < 0:出错,请参考airkiss_lan_ret_t,通常是报文数据出错
+ * 		>= 0:成功,请参考airkiss_lan_ret_t
+ */
+int airkiss_lan_recv(const void* body, unsigned short length, const airkiss_config_t* config);
+
+/*
+ * 设备要发送内网协议包时,调用本接口完成数据包打包
+ *
+ * 参数说明
+ * 		body:802.11 frame mac header(must contain at least first 24 bytes)
+ * 		length:total frame length
+ * 		config:AirKiss回调函数
+ *
+ * 返回值
+ * 		 < 0:出错,请参考airkiss_lan_ret_t,通常是报文数据出错
+ * 		>= 0:成功,请参考airkiss_lan_ret_t
+ */
+int airkiss_lan_pack(airkiss_lan_cmdid_t ak_lan_cmdid, void* appid, void* deviceid, void* _datain, unsigned short inlength, void* _dataout, unsigned short* outlength, const airkiss_config_t* config);
+
+/*
+ * 过滤部分不符合要求的帧
+ * 
+ * 参数说明
+ * 		frame:802.11 frame mac header(must contain at least first 24 bytes)
+ * 		length:total frame length
+ *
+ * 返回值
+ * 		  0:有效
+ * 		  1:无效
+*/
+int airkiss_filter(const void *frame, int length);
+
+unsigned char airkiss_crc8(unsigned char *message, unsigned char len);
+
+int airkiss_recv_nossid(airkiss_context_t* context, const void* frame, unsigned short length);
+
+typedef int (*airkiss_callback) (int state, char *_ssid, char *_passwd);
+
+void airkiss_set_callback(airkiss_callback cb);
+
+int airkiss_start(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AIRKISS_H_ */

+ 575 - 0
luat/rtt/rtt_airkiss.c

@@ -0,0 +1,575 @@
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#ifdef RT_WLAN_MANAGE_ENABLE
+#include <sys/socket.h>
+
+#include "airkiss.h"
+
+#include <stdlib.h>
+
+#define AKDEMO_BUFSZ 16
+
+static rt_list_t _bflist;
+static struct rt_mailbox _bfready;
+static int _akrun = 0;
+static airkiss_callback airkiss_cb;
+
+typedef struct
+{
+    rt_list_t list;
+    short fmlen;
+    char f[24];
+} akbuf_t;
+
+typedef struct
+{
+    char n;
+    unsigned char tm;
+    unsigned short cnt;
+} akchn_t;
+
+static akbuf_t *ak_bufinit(int cnt)
+{
+    int i;
+    akbuf_t *buf, *p;
+
+    rt_list_init(&_bflist);
+
+    buf = (akbuf_t *)rt_calloc(cnt, sizeof(akbuf_t));
+    p = buf;
+    for (i = 0; (i < cnt) && buf; i++)
+    {
+        p->fmlen = 0;
+        rt_list_init(&p->list);
+        rt_list_insert_after(&_bflist, &p->list);
+        p++;
+    }
+
+    return buf;
+}
+
+static int _airkiss_filter(const void *f, int len)
+{
+    int ret = 0;
+    unsigned char *da, *p;
+    int i;
+
+    p = (unsigned char *)f;
+    if ((len < 25) || (p[0] != 0x08))
+        return 1;
+
+    da = p + 4;
+
+    for (i = 0; i < 6; i++)
+    {
+        if (da[i] != 0xFF)
+        {
+            ret = 1;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static void prom_callback(struct rt_wlan_device *device, void *d, int s)
+{
+    akbuf_t *buf;
+
+    if (_airkiss_filter(d, s))
+        return;
+
+    if (rt_list_isempty(&_bflist))
+    {
+        rt_kprintf("ak no buf\n");
+        return;
+    }
+
+    buf = rt_list_first_entry(&_bflist, akbuf_t, list);
+    rt_list_remove(&buf->list);
+
+    rt_memcpy(buf->f, d, 24);
+    buf->fmlen = s;
+    if (rt_mb_send(&_bfready, (rt_ubase_t)buf) != 0)
+    {
+        rt_list_insert_before(&_bflist, &buf->list);
+        rt_kprintf("ak send fail\n");
+    }
+}
+
+static int ak_recv(airkiss_context_t *ac, int ms, int *rcnt)
+{
+    akbuf_t *buf = 0;
+    int status = AIRKISS_STATUS_CONTINUE;
+    rt_tick_t st, max;
+    int len = 0;
+
+    st = rt_tick_get();
+
+    while (1)
+    {
+        if (rt_mb_recv(&_bfready, (rt_ubase_t *)&buf, rt_tick_from_millisecond(10)) == 0)
+        {
+            status = airkiss_recv(ac, buf->f, buf->fmlen);
+            rt_list_insert_after(&_bflist, &buf->list);
+            if (status != AIRKISS_STATUS_CONTINUE)
+                break;
+
+            if (rcnt && (buf->fmlen != len))
+            {
+                (*rcnt)++;
+                len = buf->fmlen;
+                if (ms < 180)
+                    ms += 12;
+            }
+        }
+        else
+        {
+            if ((ms > 30) && rcnt)
+                ms -= 2;
+        }
+
+        max = rt_tick_from_millisecond(ms);
+        if ((rt_tick_get() - st) > max)
+            break;
+    }
+
+    return status;
+}
+
+static int ak_recv_chn(struct rt_wlan_device *dev,
+                       airkiss_context_t *ac, akchn_t *chn)
+{
+    int status;
+    int t;
+    int rcnt = 0;
+
+    rt_wlan_dev_set_channel(dev, chn->n);
+    airkiss_change_channel(ac);
+
+    status = ak_recv(ac, chn->tm, &rcnt);
+
+    if (status == AIRKISS_STATUS_CHANNEL_LOCKED)
+    {
+        rt_kprintf("airkiss locked chn %d\n", chn->n);
+        status = ak_recv(ac, 1000 * 30, RT_NULL);
+    }
+
+    chn->cnt += rcnt;
+    if (chn->cnt > 5)
+        chn->cnt -= 3;
+    t = chn->cnt * chn->cnt * chn->cnt;
+
+    if (t)
+    {
+        if (t > 170)
+            t = 170;
+        chn->tm = 30 + t;
+
+        rt_kprintf("tm(%d) cnt(%d) on chn %d\n", chn->tm, chn->cnt, chn->n);
+    }
+
+    return status;
+}
+
+static void akchn_init(akchn_t *chn, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++)
+    {
+        chn[i].n = i + 1;
+        chn[i].cnt = 0;
+        chn[i].tm = 20;
+    }
+}
+
+static int ak_wifi_connetct(char *ssid, char *passwd)
+{
+    int result = RT_EOK;
+    rt_uint8_t time_cnt = 0;
+
+#define NET_READY_TIME_OUT (rt_tick_from_millisecond(8 * 1000))
+
+    result = rt_wlan_connect(ssid, passwd);
+    if (result != RT_EOK)
+    {
+        rt_kprintf("\nconnect ssid %s error:%d!\n", ssid, result);
+        return result;
+    };
+
+    do
+    {
+        rt_thread_mdelay(1000);
+        time_cnt++;
+        if (rt_wlan_is_ready())
+        {
+            break;
+        }
+    } while (time_cnt <= (NET_READY_TIME_OUT / 1000));
+
+    if (time_cnt <= (NET_READY_TIME_OUT / 1000))
+    {
+        rt_kprintf("networking ready!\n");
+    }
+    else
+    {
+        rt_kprintf("wait ip got timeout!\n");
+        result = -1;
+    }
+
+    return result;
+}
+
+static void airkiss_send_notification(uint8_t random)
+{
+    int sock = -1;
+    int udpbufsize = 2;
+    struct sockaddr_in UDPBCAddr, UDPBCServerAddr;
+
+    sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0)
+    {
+        rt_kprintf("notify create socket error!\n");
+        goto _exit;
+    }
+
+    UDPBCAddr.sin_family = AF_INET;
+    UDPBCAddr.sin_port = htons(10000);
+    UDPBCAddr.sin_addr.s_addr = htonl(0xffffffff);
+    rt_memset(&(UDPBCAddr.sin_zero), 0, sizeof(UDPBCAddr.sin_zero));
+
+    UDPBCServerAddr.sin_family = AF_INET;
+    UDPBCServerAddr.sin_port = htons(10000);
+    UDPBCServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    rt_memset(&(UDPBCServerAddr.sin_zero), 0, sizeof(UDPBCServerAddr.sin_zero));
+
+    if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &udpbufsize, sizeof(int)) != 0)
+    {
+        rt_kprintf("notify socket setsockopt error\n");
+        goto _exit;
+    }
+
+    if (bind(sock, (struct sockaddr *)&UDPBCServerAddr, sizeof(UDPBCServerAddr)) != 0)
+    {
+        rt_kprintf("notify socket bind error\n");
+        goto _exit;
+    }
+
+    for (int i = 0; i <= 20; i++)
+    {
+        int ret = sendto(sock, (char *)&random, 1, 0, (struct sockaddr *)&UDPBCAddr, sizeof(UDPBCAddr));
+        rt_thread_mdelay(10);
+    }
+
+_exit:
+    if (sock >= 0)
+    {
+        closesocket(sock);
+    }
+}
+
+void airkiss_set_callback(airkiss_callback cb) {
+    airkiss_cb = cb;
+}
+
+static void do_airkiss_configwifi(void)
+{
+    airkiss_context_t ac;
+    struct rt_wlan_device *dev;
+    akbuf_t *pbuf;
+    int n;
+    akchn_t chns[13];
+    int round = 120;
+    int re = -1;
+    airkiss_config_t acfg =
+        {
+            (airkiss_memset_fn)&rt_memset,
+            (airkiss_memcpy_fn)&rt_memcpy,
+            (airkiss_memcmp_fn)&rt_memcmp,
+            (airkiss_printf_fn)&rt_kprintf};
+    int _mbuf[AKDEMO_BUFSZ];
+
+    rt_kprintf("airkiss thread start\n");
+    if ((pbuf = ak_bufinit(AKDEMO_BUFSZ)) == RT_NULL)
+    {
+        rt_kprintf("akdemo init buf err\n");
+        return;
+    }
+
+    airkiss_init(&ac, &acfg);
+
+    rt_mb_init(&_bfready, "ak", _mbuf, AKDEMO_BUFSZ, 0);
+    rt_wlan_config_autoreconnect(0);
+    rt_wlan_disconnect();
+    dev = (struct rt_wlan_device *)rt_device_find(RT_WLAN_DEVICE_STA_NAME);
+    rt_wlan_dev_set_promisc_callback(dev, prom_callback);
+
+    rt_wlan_dev_enter_promisc(dev);
+
+    akchn_init(chns, sizeof(chns) / sizeof(chns[0]));
+
+    rt_kprintf("%s\n", airkiss_version());
+
+    while (round-- > 0)
+    {
+        //rt_kprintf("ak round\n");
+        for (n = 0; n < sizeof(chns) / sizeof(chns[0]); n++)
+        {
+            if (ak_recv_chn(dev, &ac, &chns[n]) == AIRKISS_STATUS_COMPLETE)
+            {
+                airkiss_result_t res;
+
+                rt_wlan_dev_exit_promisc(dev);
+
+                airkiss_get_result(&ac, &res);
+                rt_kprintf("ssid %s pwd %s\n", res.ssid, res.pwd);
+                if (airkiss_cb) {
+                    re = 0;
+                    airkiss_cb(0, res.ssid, res.pwd);
+                }
+
+                if (ak_wifi_connetct(res.ssid, res.pwd) == 0)
+                {
+                    airkiss_send_notification(res.random);
+                }
+
+                goto _out;
+            }
+        }
+    }
+
+    rt_wlan_dev_exit_promisc(dev);
+
+_out:
+    rt_wlan_dev_set_promisc_callback(dev, RT_NULL);
+    rt_wlan_config_autoreconnect(1);
+    rt_mb_detach(&_bfready);
+    rt_free(pbuf);
+    _akrun = 0;
+    if (airkiss_cb && re != 0) {
+        airkiss_cb(re, RT_NULL, RT_NULL);
+    }
+    rt_kprintf("airkiss exit\n");
+}
+
+static void airkiss_thread(void *p)
+{
+    do_airkiss_configwifi();
+}
+
+int airkiss_start(void)
+{
+    rt_thread_t tid;
+    int ret = -1;
+
+    if (_akrun)
+        return ret;
+
+    tid = rt_thread_create("airkiss",
+                           airkiss_thread,
+                           0,
+                           2048,
+                           22,
+                           20);
+
+    if (tid)
+    {
+        ret = rt_thread_startup(tid);
+    }
+    _akrun = (ret == 0);
+
+    return ret;
+}
+
+#ifdef RT_USING_FINSH
+/* 用于测试 */
+
+typedef struct
+{
+    char isrun;
+    char schn;
+    char echn;
+    char omode;
+} akcap_t;
+
+static void showakbuf(akbuf_t *buf, int mode)
+{
+    char str[58];
+    int i, pos = 0;
+    int fs = mode & 0x1f;
+
+    if (fs < 24)
+    {
+        for (i = fs; i < 24; i++)
+        {
+            rt_sprintf(str + pos, "%02X", buf->f[i]);
+            pos += 2;
+        }
+        rt_sprintf(str + pos, ":%d\n", buf->fmlen);
+
+        if (mode & 0x80)
+        {
+            pos = rt_strlen(str) - 1;
+            rt_sprintf(str + pos, ":%d\n", rt_tick_get());
+        }
+
+        rt_kprintf(str);
+    }
+}
+
+static int recv_no_change(airkiss_context_t *ac, int omode)
+{
+    akbuf_t *buf = 0;
+    int status;
+
+    if (rt_mb_recv(&_bfready, (rt_ubase_t *)&buf, rt_tick_from_millisecond(10)) == 0)
+    {
+        status = airkiss_recv(ac, buf->f, buf->fmlen);
+        showakbuf(buf, omode);
+        rt_list_insert_after(&_bflist, &buf->list);
+    }
+
+    return (status == AIRKISS_STATUS_COMPLETE);
+}
+
+static void airkiss_thread_cap(void *p)
+{
+    akcap_t *cap = (akcap_t *)p;
+    airkiss_context_t ac;
+    struct rt_wlan_device *dev;
+    akbuf_t *pbuf;
+    akchn_t chns[14];
+    int _mbuf[AKDEMO_BUFSZ];
+
+    if ((pbuf = ak_bufinit(AKDEMO_BUFSZ)) == RT_NULL)
+    {
+        rt_kprintf("akdemo init buf err\n");
+        return;
+    }
+
+    airkiss_init(&ac, RT_NULL);
+
+    rt_mb_init(&_bfready, "ak", _mbuf, AKDEMO_BUFSZ, 0);
+    if (rt_wlan_is_connected()) {
+        rt_wlan_disconnect();
+        rt_wlan_config_autoreconnect(0);
+    }
+    dev = (struct rt_wlan_device *)rt_device_find(RT_WLAN_DEVICE_STA_NAME);
+    rt_wlan_set_mode(RT_WLAN_DEVICE_STA_NAME, RT_WLAN_NONE);
+    rt_wlan_dev_set_promisc_callback(dev, prom_callback);
+
+    rt_wlan_dev_enter_promisc(dev);
+
+    akchn_init(chns, sizeof(chns) / sizeof(chns[0]));
+
+    rt_kprintf("airkiss cap start\n");
+
+    if (cap->schn == cap->echn)
+    {
+        rt_wlan_dev_set_channel(dev, cap->schn);
+
+        while (cap->isrun)
+        {
+            if (recv_no_change(&ac, cap->omode))
+            {
+                airkiss_result_t res;
+
+                rt_wlan_dev_exit_promisc(dev);
+
+                airkiss_get_result(&ac, &res);
+                rt_kprintf("pwd %s ssid %s\n", res.pwd, res.ssid);
+                break;
+            }
+        }
+    }
+    else
+    {
+    }
+
+    rt_wlan_dev_exit_promisc(dev);
+    rt_wlan_dev_set_promisc_callback(dev, RT_NULL);
+    rt_mb_detach(&_bfready);
+    rt_free(pbuf);
+    _akrun = 0;
+
+    rt_kprintf("airkiss exit\n");
+}
+
+static int airkiss_cap_start(akcap_t *cap)
+{
+    rt_thread_t tid;
+    int ret = -1;
+
+    if (_akrun)
+        return ret;
+
+    tid = rt_thread_create("airkiss",
+                           airkiss_thread_cap,
+                           cap,
+                           2048,
+                           22,
+                           20);
+
+    if (tid)
+    {
+        ret = rt_thread_startup(tid);
+    }
+    _akrun = (ret == 0);
+
+    return ret;
+}
+
+static void airkiss(int c, char **v)
+{
+    static akcap_t cap = {0};
+    int chn = 0;
+    int op = 0;
+
+    while (c)
+    {
+        switch (c)
+        {
+        case 5:
+            if (v[4][0] == 't')
+                cap.omode = 0x80;
+            break;
+        case 4:
+            cap.omode |= atoi(&(v[3][1]));
+            break;
+        case 3:
+            chn = atoi(v[2]);
+            break;
+        case 2:
+            op = v[1][0];
+            break;
+        }
+
+        c--;
+    }
+
+    if (op == 0)
+    {
+        airkiss_start();
+    }
+    else if (op == 'c')
+    {
+        if (chn == 0)
+        {
+            cap.schn = 1;
+            cap.echn = 13;
+        }
+        else
+        {
+            cap.schn = chn;
+            cap.echn = chn;
+        }
+        cap.isrun = 1;
+        airkiss_cap_start(&cap);
+    }
+}
+MSH_CMD_EXPORT(airkiss, start airkiss);
+#endif
+
+#endif