Introduction¶
The CCpilot V1000 and V1200 has variants with built-in Wifi & Bluetooth, enabling software updates over the air, smartphone integration and other wireless features. This document will provide an introduction to Wifi and what tools to use in different scenarios.
Overview¶
Glossary¶
Word/Abbrevation | Explanation |
---|---|
IEEE 802.11 | MAC and PHY layer specifications for implementing wireless local area network communication |
MAC | Medium Access Control |
PHY | Physical layer |
Wi-Fi | Wireles Fidelity, Wi-Fi is also a trademark of the Wi-Fi Allicane |
ISM | Industrial Scientific Medical, the frequency band at 2.4GHz that is used for wifi |
OFDM | Orthogonal frequency division multiplexing, a technique that increased the raw data rate to 54Mbit/s in the 5GHz frequency band |
AP | Access point, a device providing wireless connectivity |
BSS | Basic Service Set, a closed group of devices with a central access point |
BSSID | Unique id of the AP (mac address) |
SSID | Service Set Id, is the network name of a BSS |
BSA | Basic Service Area, the physical border of the area the AP antennas work within |
CELL | Another word for BSA |
DS | Distribution System, the link between an AP and a wired network, permits wireless clients to talk to a wired network |
ESS | Extended Service Set, multiple AP cover a larger area using the same SSID and are usually connected to the same switch, permits roaming |
ROAMING | Clients seamlessly switch between cells in the same ESS without losing connectivity, very much like how mobile phones work |
IBSS | Independent Basic Service Set, Ad hoc / Wi-Fi Direct, clients communicate directly with each other without any AP |
OSI model | Open Systems Interconnection model, describes the universal standard of communication functions of a computing system |
STA | Station, a computer with a wireless network interface controller |
WEP | Wifi Protected Privacy, old security protocol |
WPA1/2/3 | Wifi Protected Access, successor to WEP with better security |
WPA-Personal | For home and small business |
WPA-PSK | Another word for WPA-Personal |
WPA-Enterprise | For enterprise networks, needs an authentication server |
WPA-802.1X | Another word for WPA-Enterprise |
NIC | Network Interface Card |
DNS | Domain Name System |
DHCP | Dynamic Host Configuration Protocol |
Wifi¶
Also Wi-Fi which is a trademark of Wi-Fi Alliance, is a family of protocols based on the IEEE 802.11 family of standards.
History¶
1985 - In USA parts of the ISM radio bands were released for unlicenced communication. The same range of frequency bands are used by other equipment such as microwave ovens, baby monitors, cordless telephones and bluetooth devices.
1991 - NCR corp and AT&T corp invented WaveLan to be used in cashier systems.
1992 - The radiophysics division of CSIRO in Australia built a prototype test bed for wireless local area network.
1997 - The first version of 802.11 protocol was released with a link speed of 2Mbit/s.
1999 - The updated 802.11b protocol was released which permits a link speed of 11MBit/s.
Also the Wi-Fi allicance were formed as a trade association to hold the Wi-Fi trademark under which most products are sold.
Apple made Wi-Fi popular at this time when using it in the iBook laptops. The first mass produced consumer product with Wi-Fi. Apple branded it as AirPort.
Further down the road
Generation | IEEE Standard | Maximum Linkrate (Mbit/s) | Adopted | Radio Frequency (GHz) |
---|---|---|---|---|
Wi-Fi 7 | 802.11be | 40000 | TBA | 2.4/5/6 |
Wi-Fi 6/6E | 802.11ax | 600 to 9608 | 2019/2020 | 2.4/5/6 |
Wi-Fi 5 | 802.11.ac | 433 to 6933 | 2014 | 5 |
Wi-Fi 4 | 802.11n | 72 to 600 | 2008 | 2.4/5 |
Wi-Fi 3 | 802.11g | 6 to 54 | 2003 | 2.4 |
Wi-Fi 2 | 802.11a | 6 to 54 | 1999 | 5 |
Wi-Fi 1 | 802.11b | 1 to 11 | 1999 | 2.4 |
Wi-Fi 0 | 802.11 | 1 to 2 | 1997 | 2.4 |
Technique¶
Using radio techniques to modulate/demodulate a carrier signal (with the modulation in the sidebands). For the first version of wifi they used a number of 5MHz wide bands from 2400MHz
up to 2465MHz (13 channels). Often standards allow for channels to be bonded together for higher throughput so a transmitter normally occupy at least 20MHz. New standars
also allow for wider channels.
Wi-Fi 4 permits more antennas to be used which boosts speeds and range. The maximum power of the antennas is locally regulated. Within the EU the equivalent isotropically radiated
power(EIRP) is limited to 20dBm (100mW).
Modes¶
Infrastructure¶
All traffic goes through the same base station. As long as the communicating devices can reach the base station they can communicate with each other. It is used to provide communication between wireless clients and wired network resources through an access point. The basic setup with one access point and a number computers connected wirelessly is called a BSS (Basic Service Set) which forms a cell.
Multiple access points¶
Using ESS (Extended service set) you can make a network with multiple access points using the same SSID, combining a number of BBSs o and ESS. Wifi client devices can then connect to the access point with the strongest signal using the same security settings. This is also known as roaming network and usually has a central controller which can administrate all access points. The access points are connected together through a distribution system (wired or wireless).
Ad hoc / Wi-Fi direct¶
Devices communicate directly without using a base station (router). This is popular among hand held game consoles for multiplayer games and also other consumer electronics like digital cameras and printers. Some devices can also share internet via ad hoc networks. A drawback is that two devices, lets call them A and B, much be in range of each other to be able to communicate with each other even with a third device C (within range of A and B) which would not automatically route traffic between A and B.
OSI model¶
The OSI model is used to describe networking. Each layer handles different aspects of networking and only exchange information with the layer below or above itself. The wifi standard 802-11 only deals with the two lowest layers of the OSI reference model.
Security¶
The first protocol called WEP (Wired equivalent Privacy) popular around 2000 and might still be used today has poor security. Using only 64-bit encryption and with other flaws made it easy to hack.
With WPA (Wifi protected access) they fixed some of the problems with WEP but there were still vulnerabilities. A big improvement were the use of TKIP (Temporal Key Integrity Protocol) to dynamically change a 128-bit per packet key.
WPA2 ratified in 2004 replaced WPA. All new devices needed to be WPA2 certified between 2006 and 2020 to bear the Wi-Fi trademark. AES (Advanced Encryption Standard) improved upon TKIP in WPA.
WPA3 announced in 2018 as a replacement for WPA2. Replaces the PSK (Pre-Shared Key) used in WPA2 with a more secure SAE(Simultaneous Authentication of Equals) method for initial key exchange in personal mode.
WPA-personal versus WPA-enterprise. WPA-personal (also referred to as WPA-PSK) is made for home or small office networks that doesn’t require an authentication server. In personal the network traffic is encrypted by a 128-bit key derived from a 256-bit shared key. WPA personal is available in all three versions av WPA. WPA enterprise on the other hand (also referred to as WPA-802.1X) are designed for enterprise networks and requires a RADIUS authentication server. Various kinds of EAP (Extensible Authentication Protocal) are used for authentication making it more secure than the person variant. WPA enterprise is also available in the three versions of WPA.
WPS (Wifi Protected Setup) is an alternative authentication method using a physical button or a PIN code to get access. It has a major security hole in the WPS PIN recovery attack. WPA3 has another way for devices that lack sufficient user interface capabilities to connect.
Tools/Software¶
A short description of useful tools when using wifi on a CCpilot display. The following tools except for dhclient are included from OS version 2.0.8.1.
NetworkManager¶
Very popular tool for managing network connections in modern Linux. Introduced by Red Hat in 2004 to simplify and automate network configuration, especially wireless connections. The NetworkManager is run as a systemd service and uses D-Bus to detect and configure network interfaces. It has a D-Bus interface to be used if you are coding a network app/program. See code example below on using NetworkManagerQt.
nmcli¶
The command line interface for NetworkManager. A very good tool for configurating network settings. It is easy to use and you can use SSH to connect to a remote device and then use nmcli for administration tasks. A lot of examples below uses nmcli.
wpa_supplicant¶
The wpa_supplicant handles security in wireless connections. NetworkManager will call wpa_supplicant via its D-Bus interface to use security. You can configurate wpa-supplicant manually via config files but the normal way is to let NetworkManager call wpa-supplicant via D-Bus.
wpa_cli¶
The command line interface for wpa-supplicant. If you decide not to use NetworkManager at all, this is a good tool for administrating the wireless security and wireless connection. Simpy type wpa_cli in the terminal to open up the interactive tool.
Dnsmasq¶
Is a software providing DNS caching and a DHCP server.
Hostapd¶
Software used for setting up an access point with lots of configuration options. To hand out ip addresses the DHCP server in dnsmasq will be used.
iw¶
A command line interface tool for configuring wifi. It is useful for quickly getting information about your wireless device. For example typing iw list
dhclient¶
Needed if you don’t use NetworkManager which has an in-built dhclient. For example if only using wpa-supplicant without NetworkManager you wouldn’t get an IP address after connecting to a wireless network.
Wifi scenarios¶
Examples using command line tools
Enable wifi¶
nmcli radio wifi on
Connect to an unprotected network¶
nmcli dev wifi connect "ssid"
Connect to a WPA2 encrypted network¶
Using –ask nmcli will prompt you for entering the password
nmcli --ask dev wifi connect "ssid"
Or submit password directly
nmcli dev wifi connect "ssid" password abcd1234
Commonly used commands with nmcli¶
Command | Comment |
---|---|
nmcli con | Show available connections |
nmcli con show "name" | Show details of a connection |
nmcli con edit "name" | Open up interactive edit of connection |
nmcli con up "name" | Activate connection |
nmcli con down "name" | Deactivate connection |
nmcli con delete "name" | Delete connection configuration |
Setup access point / hotspot using hostapd¶
It looks like hostapd doesn’t need NetworkManager nor wpa_supplicant. An active wlan connection will prevent hostapd from working correctly.
To give clients IP addresses you need to configure dnsmasq. Usually something like this is needed in /etc/dnsmasq.conf
dhcp-range=192.168.1.50,192.168.1.150,12h
Configuration file for hostapd at /etc/hostapd.conf.
Important settings below. Every setting has detailed information in the hostapd.conf file.
interface=wlan0
driver=nl80211
ctrl_interface_group=0
ssid=YourHotspotName
hw_mode=g
channel=1
auth_algs=3
ignore_broadcast_ssid=0
ieee8021x=0
eapol_key_index_workaround=0
eap_server=0
own_ip_addr=127.0.0.1
To use WPA2 which has a lot better security than WPA1 set.
wpa=2
wpa_passphrase=yourhardtoguesspassword
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
To hide your ssid from being scanned set
ignore_broadcast_ssid=1
Make sure you don’t have any active connections on wlan0 before initiating the Soft AP. Here is an example script for starting up hostapd setting your device IP to 192.168.1.50
#!/bin/bash
# Usage: ./initSoftAP
############### Initial wifi interface configuration #######
ip link set wlan0 down
ip addr flush dev wlan0
ip link set wlan0 up
ip addr add 192.168.1.50/24 dev wlan0
sleep 3
### Start dnsmasq ###
if [ -z "$(ps -e | grep -v grep | grep dnsmasq)" ]
then
echo "Starting dnsmasq"
dnsmasq
fi
### Enable NAT / Share internet via eth0 ###
iptables -F
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
### Start hostapd ###
hostapd /etc/hostapd.conf
Wifi code examples¶
In the following examples we use C++ with Qt and its D-Bus interface classes. You can of course use other programming languages. KDE has made a D-Bus Qt NetworkManager package that simplifies using the D-Bus interface to NetworkManager.
Install NetworkManagerQt¶
Get the latest version from KDE NetworkManagerQt reference and build it using cmake. If you have problem building it please contact support@crosscontrol.com.
Use NetworkManagerQt code example¶
Using the KDE NetworkManagerQt framework we get access to all features exposed by NetworkManager on the D-Bus. Below is an example for scanning and connecting to wireless networks.
Idea¶
Show a list of scanned networks
Show active connection in list
Long press an access point to activate connection
If no config for SSID, show an “enter password” pop up
If entered password is wrong, remove connection
Creating a new connection when entering password will bind it to SSID, not a specific access point (BSSID) letting
the connection roam between access points with the same SSID.
If long pressing an access point which we have a connection for. Bind connection to that specific access point.
UI¶
A simple UI with a button to trigger rescan of nearby access points. Main screen
If long pressing on an AP we don’t have a configurated connection to. Pop up a password box.
Clicking in input area will pop up a virtual keyboard
Displaying information
Showing active connection
Code snippet scan for networks¶
After initializing we have a pointer to the wireless device
NetworkManager::WirelessDevice::Ptr _wifiDevice;
Simply calling requestScan with an empty map
_wifiDevice->requestScan({});
Code for displaying / handling an access point¶
Using the Q_PROPERTY macro you can easily expose values to the UI (qml part). Since KDE didn’t provide that we created a simple wrapper class around their counterpart.
accespointwrapper.h
#ifndef ACCESSPOINTWRAPPER_H
#define ACCESSPOINTWRAPPER_H
#include <NetworkManagerQt/AccessPoint>
// Wrapper for KDE's AccessPoint class
// Now easy to show in UI
class AccessPointWrapper : public QObject
{
Q_OBJECT
Q_PROPERTY(int signalStrength READ signalStrength NOTIFY signalStrengthChanged)
Q_PROPERTY(QString hardwareAddress READ hardwareAddress CONSTANT)
Q_PROPERTY(QString ssid READ ssid CONSTANT)
Q_PROPERTY(QString maxBitRate READ maxBitRate NOTIFY maxBitRateChanged)
Q_PROPERTY(QString security READ security CONSTANT)
Q_PROPERTY(uint frequency READ frequency CONSTANT)
Q_PROPERTY(bool connected READ connected WRITE setConnected NOTIFY connectedChanged)
public:
explicit AccessPointWrapper(QObject *parent = nullptr);
void init(const QString path);
int signalStrength();
QString hardwareAddress();
QString ssid();
QString maxBitRate();
QString security();
uint frequency();
bool connected();
void setConnected(bool connected);
QString uni();
NetworkManager::AccessPoint* AccessPoint();
signals:
void signalStrengthChanged();
void maxBitRateChanged();
void connectedChanged();
public slots:
void newSignalStrength(int newValue);
void newBitRate(int newValue);
private:
NetworkManager::AccessPoint *_accessPoint;
bool _connected;
};
#endif // ACCESSPOINTWRAPPER_H
accesspointwrapper.cpp
#include "accesspointwrapper.h"
#include <qdebug.h>
#include <NetworkManagerQt/Manager>
AccessPointWrapper::AccessPointWrapper(QObject *parent) : QObject(parent)
{
_connected=false;
}
void AccessPointWrapper::init(const QString path)
{
// Create accesspoint instance and connect signals
_accessPoint = new NetworkManager::AccessPoint(path, this);
connect(_accessPoint, SIGNAL(signalStrengthChanged(int)), this, SLOT(newSignalStrength(int)));
connect(_accessPoint, SIGNAL(bitRateChanged(int)), this, SLOT(newBitRate(int)));
}
int AccessPointWrapper::signalStrength()
{
return _accessPoint->signalStrength();
}
QString AccessPointWrapper::hardwareAddress()
{
return _accessPoint->hardwareAddress();
}
QString AccessPointWrapper::ssid()
{
return _accessPoint->ssid();
}
QString AccessPointWrapper::maxBitRate()
{
return QString::number(_accessPoint->maxBitRate()/1000) + " Mbit/s";
}
QString AccessPointWrapper::security()
{
QString ans = "";
if (_accessPoint->wpaFlags() > 0)
ans.append("WPA1 ");
if (_accessPoint->rsnFlags() > 0)
ans.append("WPA2 ");
if (_accessPoint->rsnFlags() & NetworkManager::AccessPoint::KeyMgmtSAE)
ans.append("WPA3 ");
if (_accessPoint->rsnFlags() & NetworkManager::AccessPoint::KeyMgmt8021x)
ans.append("8021x");
return ans;
}
uint AccessPointWrapper::frequency()
{
return _accessPoint->frequency();
}
bool AccessPointWrapper::connected()
{
return _connected;
}
void AccessPointWrapper::setConnected(bool connected)
{
if (connected != _connected)
{
_connected = connected;
emit connectedChanged();
}
}
QString AccessPointWrapper::uni()
{
return _accessPoint->uni();
}
NetworkManager::AccessPoint *AccessPointWrapper::AccessPoint()
{
return _accessPoint;
}
void AccessPointWrapper::newSignalStrength(int newValue)
{
// qDebug() << "Got new signal strength value of " << newValue << " for " << uni();
emit signalStrengthChanged();
}
void AccessPointWrapper::newBitRate(int newValue)
{
//qDebug() << "Got new bitrate vale of " << newValue;
emit maxBitRateChanged();
}
Code for managing and displaying list of access points¶
By wrapping KDE’s Manager class and using the WirelessDevice class it was not such a big task to put it all together. Using a Q_PROPERTY to expose the list of access points for the UI and providing some Q_INVOKABLE for functions to be triggered via the UI.
wifiwrapper.h
#ifndef WIFIWRAPPER_H
#define WIFIWRAPPER_H
#include <QObject>
#include <NetworkManagerQt/Manager>
#include <NetworkManagerQt/WirelessDevice>
#include "accesspointwrapper.h"
#include <QList>
// Wrapping some wifi-specific parts via the NetworkManagerQt
// Exposing it to qml
class WifiWrapper : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<AccessPointWrapper*> accesspoints READ accesspoints NOTIFY accesspointsChanged)
public:
explicit WifiWrapper(QObject *parent = nullptr);
QList<AccessPointWrapper*> accesspoints();
Q_INVOKABLE void connectToAccesspoint(AccessPointWrapper* ap);
Q_INVOKABLE void createConnection(QString ssid, QString password, QString accesspointPath);
Q_INVOKABLE void scan();
signals:
void accesspointsChanged();
void showPasswordPopup(QString info, QString ssid, QString apPath);
void showInfoPopup(QString info);
public slots:
void updateAccesspoints();
void stateChanged(NetworkManager::Device::State newstate, NetworkManager::Device::State oldstate, NetworkManager::Device::StateChangeReason reason);
private:
static bool signalStrengthMoreThan(AccessPointWrapper* ap1, AccessPointWrapper* ap2);
QList<AccessPointWrapper*> _accesspoints;
NetworkManager::WirelessDevice::Ptr _wifiDevice;
QString _lastActiveConnectionPath = "";
};
#endif // WIFIWRAPPER_H
wifiwrapper.cpp
#include "wifiwrapper.h"
#include <NetworkManagerQt/WirelessSetting>
#include <NetworkManagerQt/Ipv4Setting>
#include <NetworkManagerQt/Utils>
#include <QUuid>
#include <QDebug>
using namespace NetworkManager;
WifiWrapper::WifiWrapper(QObject *parent) : QObject(parent)
{
// Find and use first wifi-device
const Device::List deviceList = networkInterfaces();
_wifiDevice = nullptr;
// We have to find some wireless device
for (Device::Ptr dev : deviceList) {
if (dev->type() == Device::Wifi) {
_wifiDevice = qobject_cast<WirelessDevice *>(dev);
break;
}
}
// If we have a wifi device, read out nearby accesspoints and connect signals
if (_wifiDevice)
{
updateAccesspoints();
connect(_wifiDevice.data(), SIGNAL(accessPointAppeared(QString)), this, SLOT(updateAccesspoints()));
connect(_wifiDevice.data(), SIGNAL(accessPointDisappeared(QString)), this, SLOT(updateAccesspoints()));
connect(_wifiDevice.data(), SIGNAL(activeAccessPointChanged(QString)), this, SLOT(updateAccesspoints()));
connect(_wifiDevice.data(), SIGNAL(stateChanged(NetworkManager::Device::State,NetworkManager::Device::State,NetworkManager::Device::StateChangeReason)),
this, SLOT(stateChanged(NetworkManager::Device::State,NetworkManager::Device::State,NetworkManager::Device::StateChangeReason)));
}
}
QList<AccessPointWrapper*> WifiWrapper::accesspoints()
{
return _accesspoints;
}
void WifiWrapper::connectToAccesspoint(AccessPointWrapper *ap)
{
// Called from UI after long press on access point
// First case, we are already connected.. Don't do anything
if (ap->connected())
return;
Connection::List connections = _wifiDevice->availableConnections();
for (Connection::Ptr con : connections)
{
//qDebug() << "Connection " << con;
//qDebug() << "Settings: " << con->settings()->setting(Setting::Wireless);
WirelessSetting::Ptr wirelessSetting = con->settings()->setting(Setting::Wireless).dynamicCast<WirelessSetting>();
//qDebug()<< "BBSID for " << wirelessSetting->ssid() << " is " << wirelessSetting->bssid();
// Do we already have a connection for this SSID? Try to change to a specific AP (bssid)
if (ap->ssid() == wirelessSetting->ssid())
{
QByteArray bssid = macAddressFromString( ap->hardwareAddress());
wirelessSetting->setBssid(bssid);
qDebug() << con->settings()->toMap();
QDBusPendingReply<void> replyUpd = con->update(con->settings()->toMap());
replyUpd.waitForFinished();
if (replyUpd.isValid())
{
QDBusPendingReply<void> reply = con->save();
reply.waitForFinished();
if (reply.isValid())
{
qDebug() << "Updated settings successfully";
qDebug() << "Try to activate connection " << con->uuid();
QDBusPendingReply<QDBusObjectPath> activateReply = activateConnection(con->path(),_wifiDevice->uni(),ap->uni());
activateReply.waitForFinished();
if (activateReply.isValid())
{
// This goes well even though password could be wrong. Faulty password is being catched at a later time
qDebug() << "Activated connection";
}
else
{
qDebug() << "Failed to activate connection " << activateReply.error();
}
}
else
{
qDebug() << reply.error();
}
}
else
{
qDebug() << "replyUpd is not valid!";
qDebug() << replyUpd.error();
}
return;
}
}
// If we got here, we don't have a connection for this ssid, figure out which security settings we have and ask for password
if(ap->AccessPoint()->wpaFlags() > 0 || ap->AccessPoint()->rsnFlags() > 0)
emit showPasswordPopup("Enter password for " + ap->ssid(), ap->ssid(), ap->uni());
}
void WifiWrapper::createConnection(QString ssid, QString password, QString accessPointPath)
{
// Called from UI after filling in password and pressing Connect button
// Create a new connection and activate it
qDebug() << "Create connection for " << ssid << " password: " << password;
ConnectionSettings *settings = new ConnectionSettings(ConnectionSettings::Wireless);
// Now we will prepare our new connection, we have to specify ID and create new UUID
settings->setId(ssid);
settings->setUuid(QUuid::createUuid().toString().mid(1, QUuid::createUuid().toString().length() - 2));
// For wireless setting we have to specify SSID
WirelessSetting::Ptr wirelessSetting = settings->setting(Setting::Wireless).dynamicCast<WirelessSetting>();
wirelessSetting->setSsid(ssid.toUtf8());
Ipv4Setting::Ptr ipv4Setting = settings->setting(Setting::Ipv4).dynamicCast<Ipv4Setting>();
ipv4Setting->setMethod(Ipv4Setting::Automatic);
// Optional password setting. Can be skipped if you do not need encryption.
WirelessSecuritySetting::Ptr wifiSecurity = settings->setting(Setting::WirelessSecurity).dynamicCast<WirelessSecuritySetting>();
wifiSecurity->setKeyMgmt(WirelessSecuritySetting::WpaPsk);
wifiSecurity->setPsk(password);
wifiSecurity->setInitialized(true);
wirelessSetting->setSecurity("802-11-wireless-security");
// We try to add and activate our new wireless connection
QDBusPendingReply<QDBusObjectPath, QDBusObjectPath> reply = addAndActivateConnection(settings->toMap(), _wifiDevice->uni(), accessPointPath);
reply.waitForFinished();
// Check if this connection was added successfuly
if (reply.isValid())
{
qDebug() << "Created new connection!";
emit showInfoPopup("Created a new connection");
}
else
{
qDebug() << "Failed to create connection " << reply.error();
emit showInfoPopup("Failed: " + reply.error().message());
}
}
void WifiWrapper::scan()
{
_wifiDevice->requestScan({});
}
void WifiWrapper::updateAccesspoints()
{
qDebug() << "Updating accesspoints";
const QStringList accessPointList = _wifiDevice->accessPoints();
qDeleteAll(_accesspoints);
_accesspoints.clear();
// Which accesspoint is active/connected?
AccessPoint::Ptr activeAP = _wifiDevice->activeAccessPoint();
QString activeAP_uni = "None";
if (activeAP != nullptr)
{
activeAP_uni = activeAP->uni();
ActiveConnection::Ptr acon = _wifiDevice->activeConnection();
if (acon != nullptr)
{
_lastActiveConnectionPath = acon->connection()->path();
}
}
else
{
//qDebug() << "No Active AP!!!!!!!";
}
for(QString s : accessPointList)
{
AccessPointWrapper *aw = new AccessPointWrapper();
aw->init(s);
if (s == activeAP_uni)
aw->setConnected(true);
_accesspoints.append(aw);
}
// Sort list of accesspoints according to signal strength
std::sort(_accesspoints.begin(), _accesspoints.end(), signalStrengthMoreThan);
emit accesspointsChanged();
}
void WifiWrapper::stateChanged(Device::State newstate, Device::State oldstate, Device::StateChangeReason reason)
{
// When having faulty password we come to this point
if (newstate == Device::Failed && reason == Device::NoSecretsReason)
{
Connection lastConnection(_lastActiveConnectionPath);
emit showInfoPopup("Faulty password for " + lastConnection.name());
// Try to remove it
lastConnection.remove();
}
}
bool WifiWrapper::signalStrengthMoreThan(AccessPointWrapper *ap1, AccessPointWrapper *ap2)
{
return ap1->signalStrength() > ap2->signalStrength();
}
main.cpp, hook things up¶
Setting up that we use the freevirtualkeyboard in the QT_IM_MODULE env variable. Also create the instace of our WifiWrapper class and setting the setContextProperty for it to be access via QML-code
main.cpp
#include <QGuiApplication>
#include <QtQml>
#include "wifiwrapper.h"
int main(int argc, char *argv[])
{
// Load virtualkeyboard input context plugin
qputenv("QT_IM_MODULE", QByteArray("freevirtualkeyboard"));
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
WifiWrapper wifiWrapper;
engine.rootContext()->setContextProperty("WifiWrapper", &wifiWrapper);
engine.load(url);
return app.exec();
}
QML code, the UI part¶
Since this is not a very complex application we kept the UI code in one qml-file. Usually the id: of parts in the UI will give a hint of what is happening. E g the idEnterPasswordPopup is for the Rectangle popping up when the user needs to type in a password. By using the Connections object it is easy to get a callback from the WifiWrapper when it is needed to type a password. Similar we have a Rectangle idInfoPopup for showing various information via a callback from WifiWrapper.
The InputPanel is provided with the freevirtualkeyboard and is the UI for showing the virtual keyboard.
By using a ListView for displaying the list of access points we do a template Component called idApInfo. All code for displaying a single instance of an access point is gathered here and then used by the ListView.
A simple RoundButton is used for the Scanning function.
main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.3
import QtQuick.FreeVirtualKeyboard 1.0
Window {
id: idWindow
width: 1280
height: 800
visible: true
color:"black"
onActiveFocusItemChanged: print("activeFoucusItem", activeFocusItem)
Component.onCompleted:
{
Qt.inputMethod.hide()
}
Component{
id: idApInfo
Rectangle{
id: idRectangle
width: idWindow.width
height: 50
color: "black"
property string textColor: modelData.signalStrength > 55 ? "orange" : modelData.signalStrength > 31 ? "purple" : "blue"
MouseArea{
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton) { // 'mouse' is a MouseEvent argument passed into the onClicked signal handler
console.log("right button clicked!")
} else if (mouse.button === Qt.LeftButton) {
console.log("left button clicked!")
}
}
onPressAndHold: {
console.log("Press and hold!!")
WifiWrapper.connectToAccesspoint(modelData)
}
}
RowLayout{
Layout.fillWidth: true
Layout.fillHeight: true
anchors.fill: parent
Text{
id: idConnected
color: textColor
fontSizeMode: Text.Fit
font.pixelSize: idRectangle.height-5
minimumPixelSize: 5
Layout.minimumWidth: 100
Layout.preferredWidth: 100
Layout.preferredHeight: idRectangle.height
Layout.alignment: Qt.AlignHCenter
text: modelData.connected ? " *" : " -"
}
Text{
id: idBSSID
color: textColor
fontSizeMode: Text.Fit
font.pixelSize: idRectangle.height-5
minimumPixelSize: 5
Layout.minimumWidth: 200
Layout.preferredWidth: 250
Layout.preferredHeight: idRectangle.height
Layout.alignment: Qt.AlignLeft
text: modelData.hardwareAddress
}
Text{
id: idSSID
color: textColor
fontSizeMode: Text.Fit
font.pixelSize: idRectangle.height-10
minimumPixelSize: 1
Layout.minimumWidth: 100
Layout.preferredWidth: 200
Layout.maximumWidth: 200
Layout.preferredHeight: idRectangle.height
Layout.alignment: Qt.AlignLeft
text: modelData.ssid
}
Text{
id: idRate
color: textColor
fontSizeMode: Text.HorizontalFit
font.pixelSize: idRectangle.height-10
minimumPixelSize: 1
Layout.minimumWidth: 100
Layout.preferredWidth: 150
Layout.preferredHeight: idRectangle.height
Layout.alignment: Qt.AlignLeft
text: modelData.maxBitRate
}
Text{
id: idSignalStrength
color: textColor
fontSizeMode: Text.HorizontalFit
font.pixelSize: idRectangle.height-10
minimumPixelSize: 1
Layout.minimumWidth: 20
Layout.preferredWidth: 50
Layout.preferredHeight: idRectangle.height
Layout.minimumHeight: 20
Layout.alignment: Qt.AlignLeft
text: modelData.signalStrength
}
Text{
id: idSecurity
color: textColor
fontSizeMode: Text.HorizontalFit
font.pixelSize: idRectangle.height-10
minimumPixelSize: 1
Layout.minimumWidth: 50
Layout.preferredWidth: 200
Layout.preferredHeight: idRectangle.height
Layout.minimumHeight: 20
Layout.alignment: Qt.AlignLeft
text: modelData.security
}
Text{
id: idFrequency
color: textColor
fontSizeMode: Text.HorizontalFit
font.pixelSize: idRectangle.height-10
minimumPixelSize: 1
Layout.minimumWidth: 50
Layout.preferredWidth: 200
Layout.preferredHeight: idRectangle.height
Layout.minimumHeight: 20
Layout.alignment: Qt.AlignLeft
text: modelData.frequency
}
}
}
}
RowLayout
{
id: idTitleRow
width: 1280
height: 50
Text {
Layout.fillWidth: true
Layout.fillHeight: true
font.pixelSize: 30
minimumPixelSize: 1
text: "ACTIVE BSSID SSID SPEED SIGNAL SECURITY FREQUENCY"
color:"green"
}
}
ListView
{
anchors.top: idTitleRow.bottom
anchors.bottom: parent.bottom
width: 1280
clip:false
model: WifiWrapper.accesspoints
delegate: idApInfo
}
RoundButton
{
id: idScanButton
anchors.bottom: parent.bottom
anchors.right: parent.right
text: "Scan"
radius: 20
onClicked: WifiWrapper.scan()
}
Rectangle
{
id: idEnterPasswordPopup
visible:false
width: parent.width*0.7
height: 250
anchors.centerIn: parent
anchors.verticalCenterOffset: -200
color: "darkgrey"
property string popupSSID : ""
property string accesspointPath : ""
Connections
{
target: WifiWrapper
function onShowPasswordPopup(info, ssid, apPath)
{
idEnterPasswordPopup.visible= true
idPopupTitle.text = info
idEnterPasswordPopup.popupSSID = ssid
idEnterPasswordPopup.accesspointPath = apPath
}
}
ColumnLayout
{
anchors.fill: parent
Rectangle
{
Layout.fillWidth: true
Layout.preferredHeight: 30
color: "#f7971c"
Text{
id:idPopupTitle
anchors.fill : parent
text : "Enter password for "
}
}
Rectangle
{
Layout.fillWidth: true
Layout.preferredHeight: 100
color: "lightgray"
TextEdit
{
id:idPasswordText
anchors.fill: parent
focus: true
MouseArea{
anchors.fill: parent
z:100
onClicked:{
console.log("Mousearea in popup clicked")
Qt.inputMethod.show()
Qt.inputMethod.commit()
idPasswordText.focus = true
}
}
}
}
Rectangle
{
id: idButtonRow
Layout.fillWidth: true
Layout.preferredHeight: 50
color: "darkgrey"
RoundButton {
anchors.left: idButtonRow.left
Layout.preferredHeight: 45
text: "Cancel"
radius: 10
onClicked: {
idEnterPasswordPopup.visible = false
Qt.inputMethod.hide()
}
}
RoundButton {
anchors.right: idButtonRow.right
Layout.preferredHeight: 45
radius: 10
text: "Connect"
onClicked: {
WifiWrapper.createConnection(idEnterPasswordPopup.popupSSID, idPasswordText.text, idEnterPasswordPopup.accesspointPath)
idEnterPasswordPopup.visible = false
Qt.inputMethod.hide()
}
}
}
}
}
InputPanel {
// Showing the virtual keyboard
id: inputPanel
y: idWindow.height
visible:true
anchors.left: idWindow.left
anchors.right: idWindow.right
states: State {
name: "visible"
when: Qt.inputMethod.visible
PropertyChanges {
target: inputPanel
y: idWindow.height - inputPanel.height
}
}
transitions: Transition {
from: ""
to: "visible"
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 150
easing.type: Easing.InOutQuad
}
}
}
}
Rectangle
{
id: idInfoPopup
visible: false
width: parent.width
height: 200
y:200
Connections
{
target: WifiWrapper
function onShowInfoPopup(info) {
idInfoPopup.visible = true
idInfoText.text = info
}
}
Text {
id: idInfoText
wrapMode: Text.Wrap
text: "Some debug text or similar"
anchors.fill: parent
}
RoundButton {
anchors.right: parent.right
anchors.bottom: parent.bottom
Layout.preferredHeight: 50
text: "OK"
radius: 10
onClicked: {
idInfoPopup.visible = false
}
}
}
}