加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 1 準(zhǔn)備工作
    • 2 編寫代碼
    • 3 實(shí)測驗(yàn)證
    • 4 總結(jié)
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

嵌入式Linux之wifi配網(wǎng)C++版

12/16 13:00
339
閱讀需 13 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

上篇文章:嵌入式Linux之wifi配網(wǎng)腳本分析,介紹了嵌入式Linux開發(fā)板中,通過sh腳本調(diào)用wpa_supplicant等工具進(jìn)行配網(wǎng)。

本篇,來介紹如何通過C++編程 ,來實(shí)現(xiàn)同樣的功能。

1 準(zhǔn)備工作

我這個開發(fā)板,之前配置了開機(jī)自動啟動配網(wǎng)腳本,為了便于測試C++編程,可以先關(guān)掉開機(jī)配網(wǎng)的自動腳本。

在/etc/init.d目錄下,之前添加一個S99myinit文件,注釋掉啟動配網(wǎng)腳本的語句

#!/bin/sh

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

如果需要聯(lián)網(wǎng),可以先手動啟動

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

另外,之前在學(xué)習(xí)飛凌的這個開發(fā)板時,在Ubuntu中搭建過交叉編譯環(huán)境,在進(jìn)行編譯時,我這里是輸入類似如下指令,指定交叉編譯工具鏈,進(jìn)行交叉編譯

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ù)

參考sh腳本的配網(wǎng)流程,編寫對應(yīng)的C++代碼,先來看下主函數(shù):

#include <unistd.h>
#include <cstdlib> // 用于調(diào)用系統(tǒng)命令
#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;
}
    有一個默認(rèn)的wifi名稱和密碼,也支持運(yùn)行時傳入?yún)?shù),如果有對應(yīng)的參數(shù),則使用參數(shù)中的wifi名稱和密碼先執(zhí)行S80dnsmasq stop(可參考上篇文章中的介紹)然后創(chuàng)建一個wpa的配置文件最后進(jìn)行聯(lián)網(wǎng)

2.2 執(zhí)行Linux指令

在C++中實(shí)現(xiàn)Linux指令的執(zhí)行,可使用std::system,為了便于分析程序的執(zhí)行,在每次執(zhí)行Linux指令時,打印出對應(yīng)執(zhí)行的指令內(nèi)容,這里做了一個函數(shù)封裝以及宏定義封裝,用于打印是哪個函數(shù)調(diào)用了哪個指令:

#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 創(chuàng)建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",并寫入對應(yīng)的配置項(xiàng)。

2.4 配網(wǎng)處理

調(diào)用各種Linux指令,進(jìn)行配網(wǎng)

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__);
}

處理流程可歸納為如下流程圖:

這里只描述了正常的情況,中間環(huán)節(jié)若出錯,則需要異常退出。

3 實(shí)測驗(yàn)證

先不加參數(shù)運(yùn)行測試程序,使用的默認(rèn)的wifi名稱和密碼進(jìn)行連接,可以看到最后的IP是192.168.5.111。

使用手機(jī)再開一個熱點(diǎn)(模擬另一個wifi),然后指定手機(jī)熱點(diǎn)的名稱和密碼作為參數(shù),運(yùn)行測試程序,可以看到最后的IP是192.168.174.243

4 總結(jié)

本篇介紹了如何使用C++編程,來實(shí)現(xiàn)嵌入式Linux開發(fā)中,調(diào)用wpa_supplicant等工具進(jìn)行wifi配網(wǎng),通過編寫測試?yán)?,并進(jìn)行實(shí)際測試,驗(yàn)證代碼功能。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

控制科學(xué)與工程碩士,日常分享單片機(jī)、嵌入式、C/C++、Linux等學(xué)習(xí)經(jīng)驗(yàn)干貨~