From a4f94761550f18a651b97aa04134f2c59b1d74eb Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 21 Mar 2013 11:08:33 +0100 Subject: Wifi testing code --- wifi/main.cpp | 23 ++++ wifi/main.qml | 158 ++++++++++++++++++++++++ wifi/qwifimanager.cpp | 306 ++++++++++++++++++++++++++++++++++++++++++++++ wifi/qwifimanager.h | 79 ++++++++++++ wifi/qwifinetwork.cpp | 13 ++ wifi/qwifinetwork.h | 51 ++++++++ wifi/qwifinetworklist.cpp | 106 ++++++++++++++++ wifi/qwifinetworklist.h | 33 +++++ wifi/wifitest.pro | 29 +++++ 9 files changed, 798 insertions(+) create mode 100644 wifi/main.cpp create mode 100644 wifi/main.qml create mode 100644 wifi/qwifimanager.cpp create mode 100644 wifi/qwifimanager.h create mode 100644 wifi/qwifinetwork.cpp create mode 100644 wifi/qwifinetwork.h create mode 100644 wifi/qwifinetworklist.cpp create mode 100644 wifi/qwifinetworklist.h create mode 100644 wifi/wifitest.pro (limited to 'wifi') diff --git a/wifi/main.cpp b/wifi/main.cpp new file mode 100644 index 0000000..79489ab --- /dev/null +++ b/wifi/main.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +#include "qwifimanager.h" + +#include + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType("QtWifi", 0, 1, "QWifiManager"); + qmlRegisterType(); + qmlRegisterType(); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl::fromLocalFile("main.qml")); + view.show(); + + return app.exec(); +} diff --git a/wifi/main.qml b/wifi/main.qml new file mode 100644 index 0000000..2627947 --- /dev/null +++ b/wifi/main.qml @@ -0,0 +1,158 @@ +import QtQuick 2.0 + +import QtWifi 0.1 + +Rectangle +{ + id: root + + color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1); + + QWifiManager { + id: wifiManager; + + Component.onCompleted: start(); + + onReadyChanged: { + print("QML: QWifiManager is now connected..."); + } + + onOnlineChanged: print(online ? "QML: WifiManager is online" : "QML: WifiManager is not online..."); + + scanning: ready && connectedSSID == ""; + } + + Component { + id: listDelegate + + Rectangle { + id: delegateBackground + property bool expanded: false + height: expanded ? 300 : 70 + clip: true // ### fixme + + Behavior on height { NumberAnimation { duration: 500; easing.type: Easing.InOutCubic } } + + width: parent.width + + gradient: Gradient { + GradientStop { position: 0; color: "white" } + GradientStop { position: 67 / delegateBackground.height; color: "lightgray" } + GradientStop { position: 1; color: "gray" } + } + + Text { + id: ssidLabel + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 10 + font.pixelSize: 24 + font.bold: true + text: network.ssid + (wifiManager.connectedSSID == network.ssid ? " (connected)" : ""); + } + + Text { + id: bssidLabel + anchors.top: ssidLabel.bottom + anchors.left: parent.left + anchors.margins: 5 + anchors.leftMargin: 40 + text: network.bssid + color: "gray" + font.pixelSize: ssidLabel.font.pixelSize * 0.5 + } + + Text { + id: flagsLabel + x: 200 + anchors.top: bssidLabel.top + text: (network.supportsWPA2 ? "WPA2 " : "") + + (network.supportsWPA ? "WPA " : "") + + (network.supportsWEP ? "WEP " : "") + + (network.supportsWPS ? "WPS " : ""); + color: "gray" + font.pixelSize: ssidLabel.font.pixelSize * 0.5 + font.italic: true + } + + Rectangle { + width: Math.max(100 + network.signalStrength, 0) / 100 * parent.width; + height: 20 + radius: 10 + antialiasing: true + anchors.margins: 20 + anchors.right: parent.right + anchors.top: parent.top + color: "white" + border.color: "lightgray" + } + + MouseArea { + anchors.fill: parent + onClicked: { + parent.expanded = !expanded + } + } + + Rectangle { + id: passwordInputBackground + anchors.fill: passwordInput + anchors.margins: -5 + color: "white" + radius: 5 + border.color: "gray" + } + + TextInput { + id: passwordInput + y: 100 + width: 300 + height: 50 + anchors.horizontalCenter: parent.horizontalCenter + font.pixelSize: 14 + } + + Rectangle { + id: connectButton + anchors.top: passwordInput.bottom + anchors.margins: 20 + anchors.horizontalCenter: parent.horizontalCenter + width: passwordInput.width + height: passwordInputBackground.height + + gradient: Gradient { + GradientStop { position: 0; color: "white" } + GradientStop { position: 1; color: buttonMouse.pressed ? "steelblue" : "lightsteelblue" } + } + + border.color: "gray" + + Text { + anchors.centerIn: parent + font.pixelSize: 24 + text: "Connect" + } + MouseArea { + id: buttonMouse + anchors.fill: parent + onClicked: wifiManager.connect(network, passwordInput.text); + } + } + + } + } + + ListView { + anchors.fill: root + model: wifiManager.networks + delegate: listDelegate; + } + + Image { + source: wifiManager.online ? "http://img3.imageshack.us/img3/9870/magepicture.jpg" : "" + anchors.bottom: parent.bottom + + width: parent.width + height: sourceSize.height * (width / sourceSize.width); + } +} diff --git a/wifi/qwifimanager.cpp b/wifi/qwifimanager.cpp new file mode 100644 index 0000000..984e8da --- /dev/null +++ b/wifi/qwifimanager.cpp @@ -0,0 +1,306 @@ +#include "qwifimanager.h" + +#include + +#include +#include + + +#define WLAN_INTERFACE "wlan0" + +static bool WIFI_DEBUG = !qgetenv("WIFI_DEBUG").isEmpty(); + +const QEvent::Type WIFI_SCAN_RESULTS = (QEvent::Type) (QEvent::User + 1); +const QEvent::Type WIFI_CONNECTED = (QEvent::Type) (QEvent::User + 2); + +class QWifiManagerEvent : public QEvent +{ +public: + QWifiManagerEvent(QEvent::Type type, const QByteArray &data = QByteArray()) + : QEvent(type) + , m_data(data) + { + } + + QByteArray data() const { return m_data; } + +private: + QByteArray m_data; +}; + + + +class QWifiManagerEventThread : public QThread +{ +public: + QWifiManagerEventThread(QWifiManager *manager) + : m_manager(manager) + { + + } + + void run() { + if (WIFI_DEBUG) qDebug("EventReceiver thread is running"); + char buffer[2048]; + while (1) { + int size = wifi_wait_for_event(WLAN_INTERFACE, buffer, sizeof(buffer) - 1); + if (size > 0) { + buffer[size] = 0; + + if (WIFI_DEBUG) qDebug("EVENT: %s", buffer); + + char *event = &buffer[11]; + if (strstr(event, "SCAN-RESULTS")) { + QWifiManagerEvent *e = new QWifiManagerEvent(WIFI_SCAN_RESULTS); + QCoreApplication::postEvent(m_manager, e); + } else if (strstr(event, "CONNECTED")) { + QWifiManagerEvent *e = new QWifiManagerEvent(WIFI_CONNECTED); + QCoreApplication::postEvent(m_manager, e); + } + } + } + } + + QWifiManager *m_manager; +}; + + + +QWifiManager::QWifiManager() + : m_networks(this) + , m_eventThread(0) + , m_scanTimer(0) + , m_internalState(IS_Uninitialized) + , m_scanning(false) +{ +} + + + +void QWifiManager::start() +{ + if (WIFI_DEBUG) qDebug("QWifiManager: start"); + connectToBackend(); +} + + + +void QWifiManager::setScanning(bool scanning) +{ + if (m_scanning == scanning) + return; + + m_scanning = scanning; + emit scanningChanged(scanning); + + if (m_scanning) { + if (WIFI_DEBUG) qDebug("QWifiManager: scanning"); + call("SCAN"); + m_scanTimer = startTimer(5000); + } else { + if (WIFI_DEBUG) qDebug("QWifiManager: stop scanning"); + killTimer(m_scanTimer); + } +} + + + +QByteArray int_to_ip(int i) { + QByteArray ip; + + ip.append(QByteArray::number(i & 0x000000ff)); + ip.append('.'); + ip.append(QByteArray::number((i & 0x0000ff00) >> 8)); + ip.append('.'); + ip.append(QByteArray::number((i & 0x00ff0000) >> 16)); + ip.append('.'); + ip.append(QByteArray::number(i >> 24)); + + return ip; +} + + +void QWifiManager::connectToBackend() +{ + if (m_internalState == IS_Uninitialized) + m_internalState = IS_StartBackend; + + if (m_internalState == IS_StartBackend + && wifi_start_supplicant(0) >= 0) + m_internalState = IS_ConnectToBackend; + + if (m_internalState == IS_ConnectToBackend + && wifi_connect_to_supplicant(WLAN_INTERFACE) >= 0) + m_internalState = IS_UpAndRunning; + + if (m_internalState == IS_UpAndRunning) { + emit readyChanged(true); + m_eventThread = new QWifiManagerEventThread(this); + m_eventThread->start(); + + qDebug("QWifiManager: started successfully"); + + handleConnected(); + } else { + if (WIFI_DEBUG) qWarning("QWifiManager: stuck at internal state level: %d", m_internalState); + } +} + + +QByteArray QWifiManager::call(const char *command) +{ + char data[2048]; + size_t len = sizeof(data); + if (wifi_command(WLAN_INTERFACE, command, data, &len) < 0) { + qWarning("QWifiManager: call failed: %s", command); + return QByteArray(); + } + QByteArray result = QByteArray::fromRawData(data, len); + qDebug("QWifiManager::call: %s ==>\n%s", command, result.constData()); + return result; +} + + +bool QWifiManager::event(QEvent *e) +{ + switch ((int) e->type()) { + case WIFI_SCAN_RESULTS: + m_networks.parseScanResults(call("SCAN_RESULTS")); + return true; + case WIFI_CONNECTED: + handleConnected(); + break; + case QEvent::Timer: { + int tid = static_cast(e)->timerId(); + if (tid == m_scanTimer) { + call("SCAN"); + return true; + } + break; } + } + + return QObject::event(e); +} + +void QWifiManager::connect(QWifiNetwork *network, const QString &passphrase) +{ + if (network->ssid() == m_connectedSSID) { + if (WIFI_DEBUG) qDebug("QWifiManager::connect(), already connected to %s", network->ssid().constData()); + return; + } + + QByteArray listResult = call("LIST_NETWORKS"); + + if (listResult.contains(network->ssid())) { + QList lines = listResult.split('\n'); + for (int i=1; issid())) { + int networkId = line.toInt(); + if (line.contains("[CURRENT]")) { + if (WIFI_DEBUG) qDebug("QWifiManager::connect(), network is already current"); + handleConnected(); + } else { + if (WIFI_DEBUG) qDebug("QWifiManager::connect(), network known, but not enabled"); + call(QByteArray("ENABLE_NETWORK ") + QByteArray::number(networkId)); + } + return; + } + } + } + + bool ok; + QByteArray id = call("ADD_NETWORK").trimmed(); + id.toInt(&ok); + if (!ok) { + qWarning("QWifiManager::connect(), failed to add network"); + return; + } + QByteArray setNetworkCommand = QByteArray("SET_NETWORK ") + id; + + QByteArray ssidOK = call(setNetworkCommand + QByteArray(" ssid ") + '"' + network->ssid() + '"'); + QByteArray pskOK = call(setNetworkCommand + QByteArray(" psk ") + '"' + passphrase.toLatin1() + '"'); + + if (ssidOK.trimmed() != QByteArray("OK") || pskOK.trimmed() != QByteArray("OK")) { + call("REMOVE_NETWORK " + id); + qWarning("QWifiManager::connect(), failed to set properties on network '%s'.\n'%s'\n'%s'", + id.constData(), + ssidOK.constData(), + pskOK.constData()); + return; + } + + call(QByteArray("ENABLE_NETWORK ") + id); +} + + +class ProcessRunner : public QThread { +public: + void run() { + QProcess::execute(QStringLiteral("dhcpcd"), QStringList() << QStringLiteral("wlan0")); + deleteLater(); + } +}; + + +void QWifiManager::handleConnected() +{ + QList lists = call("LIST_NETWORKS").split('\n'); + QByteArray connectedNetwork; + for (int i=1; i info = connectedNetwork.split('\t'); + m_connectedSSID = info.at(1); + emit connectedSSIDChanged(m_connectedSSID); + + if (WIFI_DEBUG) + qDebug("QWifiManager::handleConnected: starting dhcpcd..."); + QThread *t = new ProcessRunner(); + t->start(); + + int ipaddr, gateway, mask, dns1, dns2, server, lease; + if (do_dhcp_request(&ipaddr, &gateway, &mask, &dns1, &dns2, &server, &lease) == 0) { + if (WIFI_DEBUG) { + printf("ip ........: %s\n" + "gateway ...: %s\n" + "mask ......: %s\n" + "dns1 ......: %s\n" + "dns2 ......: %s\n" + "lease .....: %d\n", + int_to_ip(ipaddr).constData(), + int_to_ip(gateway).constData(), + int_to_ip(mask).constData(), + int_to_ip(dns1).constData(), + int_to_ip(dns2).constData(), + lease); + } + + // Updating dns values.. + property_set("net.dns1", int_to_ip(dns1).constData()); + property_set("net.dns2", int_to_ip(dns2).constData()); + + m_online = true; + onlineChanged(false); + + } else { + if (WIFI_DEBUG) + qDebug("QWifiManager::handleConnected: dhcp request failed..."); + + } +} diff --git a/wifi/qwifimanager.h b/wifi/qwifimanager.h new file mode 100644 index 0000000..a2fdb99 --- /dev/null +++ b/wifi/qwifimanager.h @@ -0,0 +1,79 @@ +#ifndef QWIFIMANAGER_H +#define QWIFIMANAGER_H + +#include +#include + +#include "qwifinetworklist.h" + +class QWifiManagerEventThread; + +class QWifiManager : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool ready READ isReady NOTIFY readyChanged) + Q_PROPERTY(bool online READ isOnline NOTIFY onlineChanged) + Q_PROPERTY(bool scanning READ scanning WRITE setScanning NOTIFY scanningChanged) + + Q_PROPERTY(QString connectedSSID READ connectedSSID NOTIFY connectedSSIDChanged) + Q_PROPERTY(QWifiNetworkList *networks READ networks CONSTANT) + +public: + enum InternalState { + IS_Uninitialized, + IS_StartBackend, + IS_ConnectToBackend, + IS_UpAndRunning + }; + + QWifiManager(); + + QWifiNetworkList *networks() { return &m_networks; } + + QString connectedSSID() const { return m_connectedSSID; } + + bool scanning() const { return m_scanning; } + void setScanning(bool scanning); + + bool isReady() const { return m_internalState == IS_UpAndRunning; } + bool isOnline() const { return m_online; } + + +public slots: + void start(); + + void connect(QWifiNetwork *network, const QString &passphrase); + +signals: + void scanningChanged(bool arg); + void readyChanged(bool ready); + void onlineChanged(bool online); + void connectedSSIDChanged(const QString &); + +protected: + bool event(QEvent *); + +private: + friend class QWifiManagerEventThread; + + void handleConnected(); + void parseScanResults(); + void connectToBackend(); + QByteArray call(const char *command); + + QString m_connectedSSID; + QWifiNetworkList m_networks; + + QWifiManagerEventThread *m_eventThread; + + int m_scanTimer; + + InternalState m_internalState; + + bool m_scanning; + bool m_online; + +}; + +#endif // QWIFIMANAGER_H diff --git a/wifi/qwifinetwork.cpp b/wifi/qwifinetwork.cpp new file mode 100644 index 0000000..a3fc038 --- /dev/null +++ b/wifi/qwifinetwork.cpp @@ -0,0 +1,13 @@ +#include "qwifinetwork.h" + +QWifiNetwork::QWifiNetwork() +{ +} + +void QWifiNetwork::setSignalStrength(int strenght) +{ + if (m_signalStrength == strenght) + return; + m_signalStrength = strenght; + emit signalStrengthChanged(m_signalStrength); +} diff --git a/wifi/qwifinetwork.h b/wifi/qwifinetwork.h new file mode 100644 index 0000000..7a28a58 --- /dev/null +++ b/wifi/qwifinetwork.h @@ -0,0 +1,51 @@ +#ifndef QWIFINETWORK_H +#define QWIFINETWORK_H + +#include +#include + +class QWifiManager; + +class QWifiNetwork : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QByteArray bssid READ bssid CONSTANT) + Q_PROPERTY(QByteArray ssid READ ssid CONSTANT) + Q_PROPERTY(int signalStrength READ signalStrength NOTIFY signalStrengthChanged) + Q_PROPERTY(bool supportsWPA2 READ supportsWPA2 CONSTANT) + Q_PROPERTY(bool supportsWPA READ supportsWPA CONSTANT) + Q_PROPERTY(bool supportsWEP READ supportsWEP CONSTANT) + Q_PROPERTY(bool supportsWPS READ supportsWPS CONSTANT) + +public: + QWifiNetwork(); + + QByteArray bssid() const { return m_bssid; } + void setBssid(const QByteArray &id) { m_bssid = id; } + + QByteArray ssid() const { return m_ssid; } + void setSsid(const QByteArray &id) { m_ssid = id; } + + int signalStrength() const { return m_signalStrength; } + void setSignalStrength(int strenght); + + QByteArray flags() const { return m_flags; } + void setFlags(const QByteArray &f) { m_flags = f; } + bool supportsWPA2() const { return m_flags.contains("WPA2"); } + bool supportsWPA() const { return m_flags.contains("WPA"); } + bool supportsWEP() const { return m_flags.contains("WEP"); } + bool supportsWPS() const { return m_flags.contains("WPS"); } + +signals: + void signalStrengthChanged(int arg); + +private: + QByteArray m_bssid; + QByteArray m_ssid; + int m_signalStrength; + + QByteArray m_flags; +}; + +#endif // QWIFINETWORK_H diff --git a/wifi/qwifinetworklist.cpp b/wifi/qwifinetworklist.cpp new file mode 100644 index 0000000..e7fa92d --- /dev/null +++ b/wifi/qwifinetworklist.cpp @@ -0,0 +1,106 @@ +#include "qwifinetworklist.h" + +#include + +const int ID_BSSID = (Qt::ItemDataRole) (Qt::UserRole + 1); +const int ID_SSID = (Qt::ItemDataRole) (Qt::UserRole + 2); +const int ID_SIGNAL = (Qt::ItemDataRole) (Qt::UserRole + 3); +const int ID_WPA2 = (Qt::ItemDataRole) (Qt::UserRole + 4); +const int ID_WPA = (Qt::ItemDataRole) (Qt::UserRole + 5); +const int ID_NETWORK = (Qt::ItemDataRole) (Qt::UserRole + 6); + +QWifiNetworkList::QWifiNetworkList(QWifiManager *manager) + : m_manager(manager) +{ +} + + +QHash QWifiNetworkList::roleNames() const +{ + QHash names; + names.insert(ID_BSSID, "bssid"); + names.insert(ID_SSID, "ssid"); + names.insert(ID_SIGNAL, "strength"); + names.insert(ID_WPA2, "wpa2"); + names.insert(ID_WPA, "wpa"); + names.insert(ID_NETWORK, "network"); + return names; +} + + + +QVariant QWifiNetworkList::data(const QModelIndex &index, int role) const +{ + QWifiNetwork *n = m_networks.at(index.row()); + + switch (role) { + case ID_BSSID: return n->bssid(); + case ID_SSID: return n->ssid(); + case ID_SIGNAL: return n->signalStrength(); + case ID_WPA2: return n->supportsWPA2(); + case ID_WPA: return n->supportsWPA(); + case ID_NETWORK: return QVariant::fromValue((QObject *) n); + } + + qDebug("QWifiNetworkList::data(), undefined role: %d\n", role); + + return QVariant(); +} + +QWifiNetwork *QWifiNetworkList::networkForBSSID(const QByteArray &bssid, int *pos) +{ + for (int i=0; ibssid() == bssid) { + if (pos) + *pos = i; + return m_networks.at(i); + } + } + return 0; +} + + +void QWifiNetworkList::parseScanResults(const QByteArray &results) +{ + QList lines = results.split('\n'); + + QSet bssids; + for (int i=1; i info = lines.at(i).split('\t'); + if (info.size() < 5 || info.at(4).isEmpty() || info.at(0).isEmpty()) + continue; + bssids.insert(info.at(0)); + int pos = 0; + QWifiNetwork *existing = networkForBSSID(info.at(0), &pos); + if (!existing) { + QWifiNetwork *network = new QWifiNetwork(); + network->setBssid(info.at(0)); + network->setFlags(info.at(3)); + network->setSignalStrength(info.at(2).toInt()); + network->setSsid(info.at(4)); + beginInsertRows(QModelIndex(), m_networks.size(), m_networks.size()); + m_networks << network; + endInsertRows(); + + } else { + existing->setSignalStrength(info.at(2).toInt()); + dataChanged(createIndex(pos, 0), createIndex(pos, 0)); + } + } + + for (int i=0; ibssid())) { + beginRemoveRows(QModelIndex(), i, i); + delete m_networks.takeAt(i); + endRemoveRows(); + } else { + ++i; + } + } + +// for (int i=0; ibssid() << m_networks.at(i)->ssid() << m_networks.at(i)->flags() << m_networks.at(i)->signalStrength(); +// } +} + + diff --git a/wifi/qwifinetworklist.h b/wifi/qwifinetworklist.h new file mode 100644 index 0000000..f6e134c --- /dev/null +++ b/wifi/qwifinetworklist.h @@ -0,0 +1,33 @@ +#ifndef QWIFINETWORKLIST_H +#define QWIFINETWORKLIST_H + +#include +#include + +#include "qwifinetwork.h" + +class QWifiManager; + +class QWifiNetworkList : public QAbstractListModel +{ + Q_OBJECT + +public: + + QWifiNetworkList(QWifiManager *manager); + + void parseScanResults(const QByteArray &data); + + QWifiNetwork *networkForBSSID(const QByteArray &bssid, int *pos); + + int rowCount(const QModelIndex &) const { return m_networks.size(); } + QVariant data(const QModelIndex &index, int role) const; + + QHash roleNames() const; + +private: + QWifiManager *m_manager; + QList m_networks; +}; + +#endif // QWIFINETWORKLIST_H diff --git a/wifi/wifitest.pro b/wifi/wifitest.pro new file mode 100644 index 0000000..a18afeb --- /dev/null +++ b/wifi/wifitest.pro @@ -0,0 +1,29 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2013-03-11T12:29:12 +# +#------------------------------------------------- + +QT = core gui qml quick + +TARGET = wifitest +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += \ + main.cpp \ + qwifimanager.cpp \ + qwifinetwork.cpp \ + qwifinetworklist.cpp + +HEADERS += \ + qwifimanager.h \ + qwifinetwork.h \ + qwifinetworklist.h + +LIBS += -lhardware_legacy -lcutils + +OTHER_FILES += \ + main.qml -- cgit v1.2.3