上篇文章:嵌入式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)證代碼功能。