zoukankan      html  css  js  c++  java
  • Hi3516如何连接Wifi(二)

    目录:

    一、总体思路

    二、启动Daemon

    三、作者文章合集

    书承上回(Hi3516如何连接Wifi(一)),上一篇聊了一下怎样在Hi3516中用wpa_supplicant连接到Wifi热点,本文讲一下如何通过编程实现。

    一、总体思路

        首先我们需要搞清楚Hi3516中Wifi的相关模块,以及他们之间的关系,其实和linux是很相似的。首先,我们需要运行一个的Daemon,也就是上文提到的wpa_supplicant,负责对网卡的硬件调用,比如连接wifi、断开wifi、启动热点等等。这个Daemon开放一个socket端口,外部程序可以通过本地连接向其发送指令实现间接对wifi的调用,这无疑是给我们提供了很大的便利,不用从底层重新造轮子了。

        鸿蒙OS代码中,有一个示例,在//applications/sample/camera/communication/wpa_cli,实现了连接Daemon、扫描热点、连接热点等功能。

        现在方案就很明确了,第一启动Daemon,第二向Daemon发送命令。下面我们就来详细分析如何实现。

    二、启动Daemon

        查看代码//applications/sample/camera/communication/wpa_supplicant/src/wpa_sample.c,找到main函数,发现它只做了一件事情,那就是调用pthread_create创建了一个线程,线程执行的函数是ThreadMain。而ThreadMain也只做了一件事情,那就是加载/usr/lib/libwpa.so,然后执行了其中的wpa_main函数,同时把命令行参数传递了进去。而wpa_main函数具体调用网卡就是通过hdf框架向内核态发送消息了,这里就不再赘述。

    static void* ThreadMain()
    {
        printf("[WpaSample]init wpa_supplicant.
    ");
    
        void *handleLibWpa = dlopen("/usr/lib/libwpa.so", RTLD_NOW | RTLD_LOCAL);
        if (handleLibWpa == NULL) {
            printf("[WpaSample]dlopen libwpa failed.
    ");
            return NULL;
        }
        int (*func)(int, char **) = NULL;
        func =  dlsym(handleLibWpa, "wpa_main");
        if (func == NULL) {
            dlclose(handleLibWpa);
            printf("[WpaSample]dlsym wpa_main failed.
    ");
            return NULL;
        }
        int ret = func(g_wpaArgc, g_wpaArg);
    
        printf("[WpaSample]run wpa_main failed, ret:%d.
    ", ret);
        for (int i = 0; i < g_wpaArgc; i++) {
            printf("[WpaSample]arg %d:%s.
    ", i, g_wpaArg[i]);
        }
    
        if (dlclose(handleLibWpa) != 0) {
            printf("[WpaSample]dlclose libwpa failed.
    ");
            return NULL;
        }
        return NULL;
    }
    
    int main(int argc, char *argv[])
    {
        g_wpaArgc = argc;
        for (int i = 0; i < g_wpaArgc; i++) {
            g_wpaArg[i] = argv[i];
        }
    
        int ret = pthread_create(&g_wpaThread, NULL, ThreadMain, NULL);
        if (ret != 0) {
            printf("[WpaSample]create thread failed error:%s.
    ", strerror(ret));
            return 1;
        }
        pthread_join(g_wpaThread, NULL);
        return 0;
    }

        我们要做的就是仿照main函数写自己的代码,把参数固定就可以了。我们的参数是这样的:g_wpaArg[0]="",g_wpaArg[1]="-iwlan0",g_wpaArg[2]="-c/etc/wpa_supplicant.conf",其中第0个参数是可执行文件的名称,这里可以随意填或者直接留空。

        如果只是想启动Daemon,不连接到任何Wifi热点,那这里第二个参数-c指向的.conf文件中,不应该包含ssid和psk,也就是直接使用系统自带的默认conf就可以。我们在上一篇文章中修改了wpa_supplicant.conf,加入了ssid和psk。这里做一个改进,原wpa_supplicant.conf保持不变,新增一个wpa_supplicant_(你的热点名称).conf,加入ssid和psk,然后修改//applications/sample/camera/communication/wpa_supplicant/BUILD.gn,添加需要copy的文件:

    copy("config2") {
        sources = [
            "config/wpa_supplicant_(xxx).conf"
        ]
        outputs = [
            "$root_out_dir/etc/wpa_supplicant_(xxx).conf"
        ]
    }

        这样我们wpa_supplicant就有两种操作了,只启动Daemon,和启动Daemon且连接到指定热点,只需要改变-c指定的conf文件。

        补充一下,我曾尝试过使用system函数执行wpa_supplicant的方式启动Daemon,但是失败了,原因是鸿蒙暂时还不支持system函数。具体可以看一下system的代码实现\third_partymuslsrcprocesssystem.c

    int system(const char *cmd)
    {
        pid_t pid;
        sigset_t old, reset;
        struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
        int status = -1, ret;
        posix_spawnattr_t attr;
    
        unsupported_api(__FUNCTION__);//不受支持的api
    ...

        另外,尝试了用fork创建线程也是可行的。

        还有一个文件权限问题。如果你用上述方法编写一个控制台程序来运行是没有问题的,无非就是重写了一个sample里的wpa_supplicant。但是当你在hap中通过ace调用时就出现了错误:

    OHOS # 01-01 00:40:03.661 17 59 I 03900/ACE: InitWifi invoked!
    [WpaSample]init wpa_supplicant.
    01-01 00:40:03.661 17 59 I 03900/ACE: InitDaemon2
    Successfully initialized wpa_supplicant
    [HDF:E/hdf_syscall_adapter]Open file node failed: /dev/hdfwifi
    [HDF:E/HDF_LOG_TAG]WpaMsgServiceInit: fail to get remote service!

        看样子是打开/dev/hdfwifi失败了,这个问题我研究了很久,最后意识到hap的执行用户可能和shell不同,shell是root用户在执行,而hap肯定不是root在执行,这导致了权限不足。我看了一下/dev/hdfwifi的权限

    OHOS # ls /dev
    Directory /dev:
    (略)
    -rw-rw-r-- 0        u:0     g:99    hdfwifi
    (略)
     

        其他用户是r权限,显然我们也需要w权限。执行chmod 0666 /dev/hdfwifi就可以了,但烧写后通过连接shell做这件事很不方便,最好能自动化。

        这里我们可以借助鸿蒙系统初始化阶段执行的job来实现我们的目的,在\basestartupservicesinit_litesrcmain.c负责执行系统启动后的任务,包括各种job和service,job分为pre-init,init,post-init三个阶段。具体要执行哪些命令,都写在\vendorhuaweicamerainit_configsinit_liteos_a_3516dv300.cfg配置文件中,我们要做的就是在job中找到post-init,然后在cmds添加我们的指令chmod 0666 /dev/hdfwifi

    {
        "jobs" : [{
                "name" : "pre-init",
                "cmds" : [
                    "mkdir /storage/data/log",
                    (略)
                ]
            }, {
                "name" : "init",
                "cmds" : [
                    "start shell",
                    (略)
                ]
            }, {
                "name" : "post-init",
                "cmds" : [
                    "chown 0 99 /dev/dev_mgr",
                    "chown 0 99 /dev/hdfwifi",
                    "chmod 0666 /dev/hdfwifi",//这里
     

    下一篇再将如何连接Daemon,真正实现连接Wifi,以及如何通过ACE在UI界面中操作连接Wifi。

    作者:老船夫

    想了解更多内容,请访问51CTO和华为合作共建的鸿蒙社区:https://harmonyos.51cto.com

  • 相关阅读:
    HDU 5977 Garden of Eden(点分治求点对路径颜色数为K)
    HDU 5828 Rikka with Sequence(线段树区间加开根求和)
    TZOJ 1689 Building A New Barn(求平面上有几个其它点求到n个点的曼哈顿距离最小)
    HDU 5734 Acperience(数学推导)
    POJ 1741 Tree(点分治点对<=k)
    HDU 5723 Abandoned country(kruskal+dp树上任意两点距离和)
    HDU 5988 Coding Contest(最小费用最大流变形)
    TZOJ 1693 Silver Cow Party(最短路+思维)
    TZOJ 4602 高桥和低桥(二分或树状数组+二分)
    TZOJ 2099 Sightseeing tour(网络流判混合图欧拉回路)
  • 原文地址:https://www.cnblogs.com/HarmonyOS/p/14595885.html
Copyright © 2011-2022 走看看