The previous article “Analysis of WiFi Configuration Scripts in Embedded Linux” introduced how to configure WiFi on embedded Linux development boards using shell scripts to call tools like wpa_supplicant.
This article will introduce how to achieve the same functionality through C++ programming.

1. Preparation
My development board previously had a script set to automatically start WiFi configuration at boot. To facilitate testing of C++ programming, you can disable the automatic script.
In the /etc/init.d directory, I previously added a file named S99myinit and commented out the line that starts the WiFi configuration script.
#!/bin/sh
#fltest_wifi.sh -i wlan0 -s "wifi_name" -p wifi_password
If network access is needed, it can be manually started first.
fltest_wifi.sh -i mlan0 -s "MERCURY_3394" -p "2H2+O2=2H2O"
Additionally, when I was studying this development board from Feilin, I set up a cross-compilation environment in Ubuntu. During compilation, I input commands like the following to specify the cross-compilation toolchain:
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. Writing Code
2.1 Main Function
Based on the WiFi configuration flow of the shell script, I wrote the corresponding C++ code. Let’s first look at the main function:
#include <unistd.h>
#include <cstdlib> // For calling system commands
#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:%d\n", __func__, argc);
if (argc > 1)
{
if (argc == 3)
{
ssid = argv[1];
password = argv[2];
}
else
{
printf("[%s] please input para: ssid password\n", __func__);
return -1;
}
}
printf("[%s] ssid:%s password:%s\n", __func__, ssid.c_str(), password.c_str());
SYS_CMD(std::string("/etc/init.d/S80dnsmasq stop > /dev/null"));
CreateWpaConfig(ssid, password);
ConnectWiFi();
return 0;
}
-
There is a default WiFi name and password, and it also supports runtime parameters. If corresponding parameters are provided, it will use the WiFi name and password from the parameters. -
First, execute S80dnsmasq stop (as described in the previous article). -
Then create a wpa configuration file. -
Finally, connect to the network.
2.2 Executing Linux Commands
In C++, to execute Linux commands, you can use std::system. To facilitate the analysis of program execution, print the command being executed each time a Linux command is run. Here, a function and macro definition are encapsulated to print which function called which command:
#define SYS_CMD(cmd) SysCmd(__func__, cmd)
int SysCmd(const char *funcName, std::string cmd)
{
printf("[%s] do %s\n", funcName, cmd.c_str());
return std::system(cmd.c_str());
}
2.3 Creating the WPA Configuration File
#define WPA_CONF_FILE "/etc/wpa_supplicant.conf"
void CreateWpaConfig(const std::string &ssid, const std::string &password)
{
printf("[%s] in\n", __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 err\n");
}
printf("[%s] out\n", __func__);
}
The main function is to open “/etc/wpa_supplicant.conf” and write the corresponding configuration items.
2.4 WiFi Configuration Processing
Call various Linux commands to configure WiFi.
void ConnectWiFi()
{
printf("[%s] in\n", __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_supplicant
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_supplicant
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] out\n", __func__);
}
The processing flow can be summarized in the following flowchart:

This only describes the normal situation; if there is an error in the process, it needs to exit abnormally.
3. Testing and Verification
First, run the test program without any parameters, using the default WiFi name and password for connection. The final IP address is 192.168.5.111.
Using a mobile phone, create another hotspot (simulating another WiFi), then specify the mobile hotspot’s name and password as parameters to run the test program. The final IP address is 192.168.174.243.

4. Conclusion
This article introduced how to use C++ programming to implement WiFi configuration in embedded Linux development by calling tools like wpa_supplicant. By writing test routines and conducting actual tests, the functionality of the code was verified.

END