目录:

一、总体思路

二、启动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.\n"); void *handleLibWpa = dlopen("/usr/lib/libwpa.so", RTLD_NOW | RTLD_LOCAL);
if (handleLibWpa == NULL) {
printf("[WpaSample]dlopen libwpa failed.\n");
return NULL;
}
int (*func)(int, char **) = NULL;
func = dlsym(handleLibWpa, "wpa_main");
if (func == NULL) {
dlclose(handleLibWpa);
printf("[WpaSample]dlsym wpa_main failed.\n");
return NULL;
}
int ret = func(g_wpaArgc, g_wpaArg); printf("[WpaSample]run wpa_main failed, ret:%d.\n", ret);
for (int i = 0; i < g_wpaArgc; i++) {
printf("[WpaSample]arg %d:%s.\n", i, g_wpaArg[i]);
} if (dlclose(handleLibWpa) != 0) {
printf("[WpaSample]dlclose libwpa failed.\n");
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.\n", 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_party\musl\src\process\system.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来实现我们的目的,在\\base\startup\services\init_lite\src\main.c负责执行系统启动后的任务,包括各种job和service,job分为pre-init,init,post-init三个阶段。具体要执行哪些命令,都写在\\vendor\huawei\camera\init_configs\init_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

Hi3516如何连接Wifi(二)的更多相关文章

  1. 手机连接wifi自动弹窗的原理及其实现方案

    一.手机连上wifi后会自动弹窗的原理 生活中,有很多需要认证的路由器,手机连接wifi热点后会自动弹出一个网页,让用户输入账号和密码,比如星巴克,肯地基,麦当劳,甚至是火车站和机场的候车室.其实这是 ...

  2. [Windows Phone] 如何撰写连接 Wifi、蓝芽、网路、飞航模式的网路设定功能

    原文:[Windows Phone] 如何撰写连接 Wifi.蓝芽.网路.飞航模式的网路设定功能 前言 为了可以使自己的 APP 具备操作网路的功能,在本文分享研究心得,包含在 Windows Pho ...

  3. 树莓派小用手册(安装系统,配置图形界面,连接WiFi,调用摄像头,安装ffmpeg)

    安装树莓派系统(重装) 准备工作: 安装需要干净的TF卡(最好 8G 以上),如果是重装的话,需要先将其清理后再使用.清理步骤下面会给出,清理需要工具 DiskGenius,下载链接:http://w ...

  4. 树莓派 连接wifi与路由器ip绑定

    先推荐几个手机软件 在酷安网里应该能找到 1.JuiceSSH  橘子ssh软件  手机连上路由器 就可以控制局域网内的树莓派 2.VNC Viewer  远程桌面软件VNC 也是连接局域网的树莓派 ...

  5. 树莓派连接wifi

    使用树莓派,通过无线网卡连接wifi,再通过远程桌面或者ssh的连接树莓派比较方便,本文记录树莓派wifi如何设置. 参考链接: http://www.jianshu.com/p/b42e8d3df4 ...

  6. android开发连接wifi addNetwork 返回-1

    如下代码:(注释掉的是会返回-1的代码,未注释的是能够正常连接wifi的代码) // public WifiConfiguration CreateWifiInfo(String SSID, Stri ...

  7. 为什么手机连接wifi会显示已停用?

    1.通常导致手机连接WiFi显示“已停用”故障的原因是由于无线路由器“安全模式”设置不当造成的,对此我们可以通过以下方法来解决: 2.根据无线路由器背面的信息(包括路由器IP地址,登陆用户名和密码), ...

  8. Android 连接Wifi和创建Wifi热点 demo

    android的热点功能不可见,用了反射的技术搞定之外. Eclipse设置语言为utf-8才能查看中文注释 上代码: MainActivity.java package com.widget.hot ...

  9. C#如何连接wifi和指定IP

    大家好哈,这是我第一次写博客,我也是才大一结束,自学了10多天C#,有不对的欢迎大家指正,最近因为项目的事而被Wifi和IP折磨了很久,后来借用了一下外国人的SimpleWifi.dll 再自己写了一 ...

随机推荐

  1. CSS event pass through

    CSS event pass through CSS 黑科技 / CSS 技巧: css 禁用点击事件, 实现事件冒泡的效果 https://caniuse.com/?search=CSS point ...

  2. 中文域名 & 原理剖析

    中文域名 & 原理剖析 https://zh.wikipedia.org/wiki/中文域名 原理 利用浏览器的对字符编码的转换算法,实现 unicode 字符显示! 国际化域名: 就是一个普 ...

  3. css grid layout in practice

    css grid layout in practice https://caniuse.com/#search=grid subgrid https://caniuse.com/#search=cal ...

  4. VOR/DME程序进近、复飞保护区的绘制

    今天尝试画一个典型的VOR/DME进近程序保护区. 读图 某机场VOR/DME进近程序平面图部分如下图所示:   该程序剖面图部分如下图所示:   分析 该机场采用了偏置导航台布局(导航台在机场内), ...

  5. django学习-25.admin管理后台里:把表名称和表字段名称的展示值都由英文显示改为由中文显示

    目录结构 1.前言 2.完整的操作步骤 2.1.第一步:修改模型类Article 2.2.第二步:重启服务 2.3.第三步:退出登录并再次成功登陆admin管理后台 2.4.第四步:查看最新的表名称展 ...

  6. 05.其他创建numpy数组的方法

    >>> import numpy as np >>> np.zeros(10,dtype=int) array([0, 0, 0, 0, 0, 0, 0, 0, 0 ...

  7. 关于Python 编码的一点认识

    在计算机中,所有数据的存储.运算以及传输都必须是二进制数字,因为计算机只认识0和1. 当一个人把一份数据传给另一个人时,计算机传递的是其实是二进制数字,但这些数字需要被还原为原始信息. 这个工作当然是 ...

  8. vue-eahars生产编译报错

    { test: /\.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_mo ...

  9. Linux安装与使用

    1.安装 1.1安装VMware 1.1.1VM12版本安装 1)下载:网盘:链接:https://pan.baidu.com/s/1Jnr--KIy3bSTvRhtB8nfiQ 提取码:czna 2 ...

  10. Java基本概念:类

    一.描述 类是一种抽象的数据类型,它是对某一类事物整体的描述或定义,但是并不能代表某一个具体的事物. 例如,我们生活中所说的词语:动物.植物.手机.电脑等等.这些也都是抽象的概念,而不是指的某一个 具 ...