Hi3516如何连接Wifi(三)

    小伙伴们大家好,上一篇(Hi3516如何连接Wifi(二))介绍了用程序启动wap_supplicant,也就是Wifi的Daemon。下一步就是如何向Daemon发信息,我们可以参考//applications/sample/camera/communication/wpa_cli,他实现了连接Daemon、扫描热点、连接热点等功能。

    我们打开wpa_cli_sample.c文件,核心功能在于这几个函数:

  •  ● InitControlInterface:初始化
  •  ● TestScan:扫描周围热点
  •  ● TestNetworkConfig:连接到指定热点

    首先看InitControlInterface函数,他先调用了wpa_ctrl_open函数,获取了用于发送命令的控制接口g_ctrlConn,是一个类型为struct wpa_ctrl的结构体。又调用一遍wpa_ctrl_open打开了一个用于事件监控的控制接口g_monitorConn。然后启动了事件监控的线程执行MonitorTask函数,这个监控线程不是必须,可以省略。

int InitControlInterface()
{
    g_ctrlConn = wpa_ctrl_open(WPA_IFACE_NAME); // create control interface for send cmd
    g_monitorConn = wpa_ctrl_open(WPA_IFACE_NAME); // create control interface for event monitor
    if (!g_ctrlConn || !g_monitorConn) {
        SAMPLE_ERROR("open wpa control interface failed.");
        return -1;
    }
    if (wpa_ctrl_attach(g_monitorConn) == 0) { // start monitor
        pthread_create(&g_wpaThreadId, NULL, MonitorTask, NULL); // create thread for read event
        return 0;
    }
    return -1;
}

然后我们来着重分析一下TestNetworkConfig函数。实际上就是一系列SendCtrlCommand向Daemon发送指令。

static void TestNetworkConfig(void)
{
    char networkId[20] = {0};
    size_t networkIdLen = sizeof(networkId);
    int ret = SendCtrlCommand("DISCONNECT", networkId, &networkIdLen);
    ret += SendCtrlCommand("ADD_NETWORK", networkId, &networkIdLen);
    if (ret != 0) {
        SAMPLE_ERROR("add network failed.");
        return;
    }
    SAMPLE_INFO("add network success, network id [%.*s]", networkIdLen, networkId);
    char reply[100] = {0};
    size_t replyLen = sizeof(reply);
    char cmd[200] = {0};
    sprintf_s(cmd, sizeof(cmd), "SET_NETWORK %.*s ssid \"example\"", networkIdLen, networkId);
    ret += SendCtrlCommand(cmd, reply, &replyLen);
    replyLen = sizeof(reply);
    sprintf_s(cmd, sizeof(cmd), "SET_NETWORK %.*s psk \"012345678\"", networkIdLen, networkId);
    ret += SendCtrlCommand(cmd, reply, &replyLen);
    replyLen = sizeof(reply);
    sprintf_s(cmd, sizeof(cmd), "ENABLE_NETWORK %.*s", networkIdLen, networkId);
    ret += SendCtrlCommand(cmd, reply, &replyLen);
    replyLen = sizeof(reply);
    ret += SendCtrlCommand("RECONNECT", reply, &replyLen);
    replyLen = sizeof(reply);
    if (ret == 0) {
        SAMPLE_INFO("network config success.");
        return;
    }
    sprintf_s(cmd, sizeof(cmd), "REMOVE_NETWORK %.*s", networkIdLen, networkId);
    SendCtrlCommand(cmd, reply, &replyLen);
    SAMPLE_ERROR("network config failed remove network [%.*s].", networkIdLen, networkId);
}

wpa_supplicant定义了许多命令,常见的有:

  •  ● PING:心跳检测命令。客户端用它判断WPAS是否工作正常。WPAS收到”PING”命令后需要回复“PONG”。
  •  ● MIB:客户端用该命令获取设备的MIB信息。
  •  ● STATUS:客户端用该命令来获取WPAS的工作状态。
  •  ● ADD_NETWORK:为WPAS添加一个新的无线网络。它将返回此新无线网络的id(从0开始)。注意:此network id非常重要,客户端后续将通过它来指明自己想操作的无线网络。
  •  ● SET_NETWORK<network id> <variable> <value>:network id是无线网络的id。此命令用于设置指定无线网络的信息。其中variable为参数名,value为参数的值。
  •  ● ENABLE_NETWORK<network id>:使能某个无线网络。此命令最终将促使WPAS发起一系列操作以加入该无线网络。
  •  ● SCAN: 扫描附近AP
  •  ● SCAN_RESULT:列出最近一次扫描的结果
  •  ● LIST_NETWORKS: 列出添加的所有AP

    看完上边就很好理解了,先是DISCONNECT断开已有连接,ADD_NETWORK添加一个新的无线网络,SET_NETWORK设置ssid和psk,ENABLE_NETWORK使能这个无线网络,最后一个RECONNECT重新连接有点迷,去掉应该也没关系,不过本人没有尝试。

    TestScan函数就留给读者自行分析。

    了解了这些,我们就可以在自己的代码中去连接WIFI热点了,我是放在了ACE模块IDE自建module中,这样就可以在JS中调用了。还可以传递ssid和psk参数,连接指定的热点。如果需要,也可以增加扫描热点并获得热点列表的功能。

    在移植的过程中,需要注意的是,BUILD.gn文件需要增加相关配置,头文件目录增加:

    "//third_party/wpa_supplicant/wpa_supplicant-2.9/src/",

依赖项deps增加:

    "//third_party/wpa_supplicant/wpa_supplicant-2.9:wpa_supplicant",

ldflags选项增加"-lwpa_client"。

    这样应该就可以正常编译了。

    运行后观察日志输出,有点多:


文章后续内容和相关附件可以点击下面的原文链接前往学习

原文链接:https://harmonyos.51cto.com/posts/3764#bkwz


想了解更多关于鸿蒙的内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com/#bkwz