加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 1 准备工作
    • 2 编写代码
    • 3 实测验证
    • 4 总结
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

嵌入式Linux之wifi配网C++版

20小时前
119
阅读需 13 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

上篇文章:嵌入式Linux之wifi配网脚本分析,介绍了嵌入式Linux开发板中,通过sh脚本调用wpa_supplicant等工具进行配网。

本篇,来介绍如何通过C++编程 ,来实现同样的功能。

1 准备工作

我这个开发板,之前配置了开机自动启动配网脚本,为了便于测试C++编程,可以先关掉开机配网的自动脚本。

在/etc/init.d目录下,之前添加一个S99myinit文件,注释掉启动配网脚本的语句

#!/bin/sh

#fltest_wifi.sh -i wlan0 -s "wifi_name" -p wifi_password

如果需要联网,可以先手动启动

fltest_wifi.sh -i mlan0 -s "MERCURY_3394" -p "2H2+O2=2H2O"

另外,之前在学习飞凌的这个开发板时,在Ubuntu中搭建过交叉编译环境,在进行编译时,我这里是输入类似如下指令,指定交叉编译工具链,进行交叉编译

export PATH=/home/xxpcb/myTest/OK3568/gcc_aarch64/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
aarch64-linux-gnu-g++ test_wifi.cpp -o test_wifi

2 编写代码

2.1 主函数

参考sh脚本的配网流程,编写对应的C++代码,先来看下主函数:

#include <unistd.h>
#include <cstdlib> // 用于调用系统命令
#include <fstream>
#include <iostream>
#include <string>

#define NET_PORT "mlan0"

int main(int argc, char *argv[])
{
    std::string ssid = "MERCURY_3394";
    std::string password = "2H2+O2=2H2O";
    printf("[%s] argc:%dn", __func__, argc);
    if (argc > 1)
    {
        if (argc == 3)
        {
            ssid = argv[1];
            password = argv[2];
        }
        else
        {
            printf("[%s] please input para: ssid passwordn", __func__);
            return -1;
        }
    }
    printf("[%s] ssid:%s password:%sn", __func__, ssid.c_str(), password.c_str());

    SYS_CMD(std::string("/etc/init.d/S80dnsmasq stop > /dev/null"));
    CreateWpaConfig(ssid, password);
    ConnectWiFi();

    return 0;
}
    有一个默认的wifi名称和密码,也支持运行时传入参数,如果有对应的参数,则使用参数中的wifi名称和密码先执行S80dnsmasq stop(可参考上篇文章中的介绍)然后创建一个wpa的配置文件最后进行联网

2.2 执行Linux指令

在C++中实现Linux指令的执行,可使用std::system,为了便于分析程序的执行,在每次执行Linux指令时,打印出对应执行的指令内容,这里做了一个函数封装以及宏定义封装,用于打印是哪个函数调用了哪个指令:

#define SYS_CMD(cmd) SysCmd(__func__, cmd)

int SysCmd(const char *funcName, std::string cmd)
{
    printf("[%s] do %sn", funcName, cmd.c_str());
    return std::system(cmd.c_str());
}

2.3 创建wpa配置文件

#define WPA_CONF_FILE "/etc/wpa_supplicant.conf"

void CreateWpaConfig(const std::string &ssid, const std::string &password)
{
    printf("[%s] inn", __func__);
    std::ofstream configFile(WPA_CONF_FILE);
    if (configFile.is_open())
    {
        configFile << "ctrl_interface=/var/run/wpa_supplicant" << std::endl;
        configFile << "ctrl_interface_group=0" << std::endl;
        configFile << "update_config=1" << std::endl;

        configFile << "network={" << std::endl;
        configFile << "    ssid="" << ssid << """ << std::endl;
        configFile << "    psk="" << password << """ << std::endl;
        configFile << "key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE" << std::endl;
        configFile << "group=CCMP TKIP WEP104 WEP40" << std::endl;
        configFile << "}" << std::endl;

        configFile.close();
    }
    else
    {
        printf("write config file errn");
    }
    printf("[%s] outn", __func__);
}

主要功能就是打开"/etc/wpa_supplicant.conf",并写入对应的配置项。

2.4 配网处理

调用各种Linux指令,进行配网

void ConnectWiFi()
{
    printf("[%s] inn", __func__);
    std::string tmpCmd;
    // down NET_PORT
    tmpCmd = "ifconfig " + std::string(NET_PORT) + " down > /dev/null";
    if (-1 == SYS_CMD(tmpCmd.c_str()))
    {
        printf("[%s] do %s failed!n", __func__, tmpCmd.c_str());
        goto END;
    }

    // stop wpa_supplication
    tmpCmd = "ps -fe|grep wpa_supplicant |grep -v grep > /dev/null";
    if (0 == SYS_CMD(tmpCmd.c_str()))
    {
        tmpCmd = "kill -9 $(pidof wpa_supplicant)";
        if (-1 == SYS_CMD(tmpCmd.c_str()))
        {
            printf("[%s] do %s failed!n", __func__, tmpCmd.c_str());
            goto END;
        }
    }

    // up NET_PORT
    tmpCmd = "ifconfig " + std::string(NET_PORT) + " up > /dev/null";
    if (-1 == SYS_CMD(tmpCmd.c_str()))
    {
        printf("[%s] do %s failed!n", __func__, tmpCmd.c_str());
        goto END;
    }

    // start wpa_supplication
    tmpCmd = "(wpa_supplicant -Dnl80211,wext -i" + std::string(NET_PORT) + " -c " +
             std::string(WPA_CONF_FILE) + " >/dev/null) &";
    if (-1 == SYS_CMD(tmpCmd.c_str()))
    {
        printf("[%s] do %s failed!n", __func__, tmpCmd.c_str());
        goto END;
    }
    sleep(3);

    // check status
    tmpCmd =
        "wpa_cli -i" + std::string(NET_PORT) + " status |grep COMPLETED |grep -v grep >/dev/null";
    if (-1 == SYS_CMD(tmpCmd.c_str()))
    {
        printf("[%s] do %s failed!n", __func__, tmpCmd.c_str());
        goto END;
    }

    // udhcpc
    tmpCmd = "udhcpc -i" + std::string(NET_PORT) + "";
    if (-1 == SYS_CMD(tmpCmd.c_str()))
    {
        printf("[%s] do %s failed!n", __func__, tmpCmd.c_str());
        goto END;
    }

END:
    printf("[%s] outn", __func__);
}

处理流程可归纳为如下流程图:

这里只描述了正常的情况,中间环节若出错,则需要异常退出。

3 实测验证

先不加参数运行测试程序,使用的默认的wifi名称和密码进行连接,可以看到最后的IP是192.168.5.111。

使用手机再开一个热点(模拟另一个wifi),然后指定手机热点的名称和密码作为参数,运行测试程序,可以看到最后的IP是192.168.174.243

4 总结

本篇介绍了如何使用C++编程,来实现嵌入式Linux开发中,调用wpa_supplicant等工具进行wifi配网,通过编写测试例程,并进行实际测试,验证代码功能。

相关推荐

电子产业图谱

控制科学与工程硕士,日常分享单片机、嵌入式、C/C++、Linux等学习经验干货~