Skip to content

Commit

Permalink
Add Wi-Fi network scan functionality (#59)
Browse files Browse the repository at this point in the history
[nrfconnect] matter-wifi: add Wi-Fi network scan functionality

Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no>
  • Loading branch information
Damian-Nordic authored Aug 9, 2022
1 parent 29ad3b4 commit 2042a6c
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 8 deletions.
55 changes: 55 additions & 0 deletions src/platform/Zephyr/WiFiManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
extern "C" {
#include <wpa_supplicant/config.h>
#include <wpa_supplicant/scan.h>
#include <zephyr_fmac_main.h>
}

extern struct wpa_supplicant * wpa_s_0;
Expand All @@ -51,6 +52,29 @@ in6_addr ToZephyrAddr(const Inet::IPAddress & address)
return zephyrAddr;
}

NetworkCommissioning::WiFiScanResponse ToScanResponse(wifi_scan_result * result)
{
NetworkCommissioning::WiFiScanResponse response = {};

if (result != nullptr)
{
static_assert(sizeof(response.ssid) == sizeof(result->ssid), "SSID length mismatch");
static_assert(sizeof(response.bssid) == sizeof(result->mac), "BSSID length mismatch");

// TODO: Distinguish WPA versions
response.security.Set(result->security == WIFI_SECURITY_TYPE_PSK ? NetworkCommissioning::WiFiSecurity::kWpaPersonal
: NetworkCommissioning::WiFiSecurity::kUnencrypted);
response.channel = result->channel;
response.rssi = result->rssi;
response.ssidLen = result->ssid_length;
memcpy(response.ssid, result->ssid, result->ssid_length);
// TODO: MAC/BSSID is not filled by the Wi-Fi driver
memcpy(response.bssid, result->mac, result->mac_length);
}

return response;
}

net_if * GetInterface(Inet::InterfaceId ifaceId = Inet::InterfaceId::Null())
{
return ifaceId.IsPresent() ? net_if_get_by_index(ifaceId.GetPlatformInterface()) : net_if_get_default();
Expand Down Expand Up @@ -152,6 +176,37 @@ CHIP_ERROR WiFiManager::AddNetwork(const ByteSpan & ssid, const ByteSpan & crede
return CHIP_ERROR_INTERNAL;
}

CHIP_ERROR WiFiManager::Scan(const ByteSpan & ssid, ScanCallback callback)
{
const StationStatus stationStatus = GetStationStatus();
VerifyOrReturnError(stationStatus != StationStatus::DISABLED && stationStatus != StationStatus::SCANNING &&
stationStatus != StationStatus::CONNECTING,
CHIP_ERROR_INCORRECT_STATE);

net_if * const iface = GetInterface();
VerifyOrReturnError(iface != nullptr, CHIP_ERROR_INTERNAL);

const device * dev = net_if_get_device(iface);
VerifyOrReturnError(dev != nullptr, CHIP_ERROR_INTERNAL);

const wifi_nrf_dev_ops * ops = static_cast<const wifi_nrf_dev_ops *>(dev->api);
VerifyOrReturnError(ops != nullptr, CHIP_ERROR_INTERNAL);

mScanCallback = callback;

// TODO: Use saner API once such exists.
// TODO: Take 'ssid' into account.
VerifyOrReturnError(ops->off_api.disp_scan(dev,
[](net_if *, int status, wifi_scan_result * result) {
VerifyOrReturn(Instance().mScanCallback != nullptr);
NetworkCommissioning::WiFiScanResponse response = ToScanResponse(result);
Instance().mScanCallback(status, result != nullptr ? &response : nullptr);
}) == 0,
CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

CHIP_ERROR WiFiManager::Connect(const ByteSpan & ssid, const ByteSpan & credentials, const ConnectionHandling & handling)
{
ChipLogDetail(DeviceLayer, "Connecting to WiFi network");
Expand Down
5 changes: 5 additions & 0 deletions src/platform/Zephyr/WiFiManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <lib/core/CHIPError.h>
#include <lib/support/Span.h>
#include <platform/NetworkCommissioning.h>
#include <system/SystemLayer.h>

#include <net/net_if.h>
Expand Down Expand Up @@ -84,6 +85,8 @@ class WiFiManager
return sInstance;
}

using ScanCallback = void (*)(int /* status */, NetworkCommissioning::WiFiScanResponse *);

struct ConnectionHandling
{
ConnectionCallback mOnConnectionSuccess{};
Expand All @@ -92,6 +95,7 @@ class WiFiManager
};

CHIP_ERROR Init();
CHIP_ERROR Scan(const ByteSpan & ssid, ScanCallback callback);
CHIP_ERROR Connect(const ByteSpan & ssid, const ByteSpan & credentials, const ConnectionHandling & handling);
CHIP_ERROR GetMACAddress(uint8_t * buf);
StationStatus GetStationStatus();
Expand All @@ -112,6 +116,7 @@ class WiFiManager
ConnectionCallback mConnectionSuccessClbk;
ConnectionCallback mConnectionFailedClbk;
System::Clock::Timeout mConnectionTimeoutMs;
ScanCallback mScanCallback{ nullptr };
};

} // namespace DeviceLayer
Expand Down
59 changes: 58 additions & 1 deletion src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,34 @@ namespace chip {
namespace DeviceLayer {
namespace NetworkCommissioning {

bool NrfWiFiScanResponseIterator::Next(WiFiScanResponse & item)
{
if (mResultId < mResultCount)
{
item = mResults[mResultId++];
return true;
}
return false;
}

void NrfWiFiScanResponseIterator::Release()
{
mResultId = mResultCount = 0;
Platform::MemoryFree(mResults);
mResults = nullptr;
}

void NrfWiFiScanResponseIterator::Add(const WiFiScanResponse & result)
{
void * newResults = Platform::MemoryRealloc(mResults, (mResultCount + 1) * sizeof(WiFiScanResponse));

if (newResults)
{
mResults = static_cast<WiFiScanResponse *>(newResults);
mResults[mResultCount++] = result;
}
}

CHIP_ERROR NrfWiFiDriver::Init(NetworkStatusChangeCallback * networkStatusChangeCallback)
{
mpNetworkStatusChangeCallback = networkStatusChangeCallback;
Expand Down Expand Up @@ -177,7 +205,36 @@ void NrfWiFiDriver::OnConnectWiFiNetworkFailed()
}
}

void NrfWiFiDriver::ScanNetworks(ByteSpan ssid, WiFiDriver::ScanCallback * callback) {}
void NrfWiFiDriver::ScanNetworks(ByteSpan ssid, WiFiDriver::ScanCallback * callback)
{
mScanCallback = callback;
CHIP_ERROR error = WiFiManager::Instance().Scan(
ssid, [](int status, WiFiScanResponse * response) { Instance().OnScanWiFiNetworkDone(status, response); });

if (error != CHIP_NO_ERROR)
{
mScanCallback = nullptr;
callback->OnFinished(Status::kUnknownError, CharSpan(), nullptr);
}
}

void NrfWiFiDriver::OnScanWiFiNetworkDone(int status, WiFiScanResponse * response)
{
if (response != nullptr)
{
StackLock lock;
VerifyOrReturn(mScanCallback != nullptr);
mScanResponseIterator.Add(*response);
return;
}

// Scan complete
DeviceLayer::SystemLayer().ScheduleLambda([this, status]() {
VerifyOrReturn(mScanCallback != nullptr);
mScanCallback->OnFinished(status == 0 ? Status::kSuccess : Status::kUnknownError, CharSpan(), &mScanResponseIterator);
mScanCallback = nullptr;
});
}

void NrfWiFiDriver::LoadFromStorage()
{
Expand Down
21 changes: 14 additions & 7 deletions src/platform/nrfconnect/wifi/NrfWiFiDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@
namespace chip {
namespace DeviceLayer {
namespace NetworkCommissioning {
namespace {

constexpr uint8_t kMaxWiFiNetworks = 1;
constexpr uint8_t kWiFiScanNetworksTimeOutSeconds = 10;
constexpr uint8_t kWiFiConnectNetworkTimeoutSeconds = 120;
} // namespace

class NrfScanResponseIterator : public Iterator<WiFiScanResponse>
class NrfWiFiScanResponseIterator : public Iterator<WiFiScanResponse>
{
public:
virtual ~NrfScanResponseIterator() = default;
size_t Count() override { return 0; }
bool Next(WiFiScanResponse & item) override { return true; }
void Release() override {}
size_t Count() override { return mResultCount; }
bool Next(WiFiScanResponse & item) override;
void Release() override;
void Add(const WiFiScanResponse & result);

private:
size_t mResultId = 0;
size_t mResultCount = 0;
WiFiScanResponse * mResults = nullptr;
};

class NrfWiFiDriver final : public WiFiDriver
Expand Down Expand Up @@ -101,13 +105,16 @@ class NrfWiFiDriver final : public WiFiDriver
void OnConnectWiFiNetwork();
void OnConnectWiFiNetworkFailed();
void OnNetworkStatusChanged(Status status);
void OnScanWiFiNetworkDone(int status, WiFiScanResponse * result);

private:
void LoadFromStorage();

ConnectCallback * mpConnectCallback{ nullptr };
NetworkStatusChangeCallback * mpNetworkStatusChangeCallback{ nullptr };
WiFiNetwork mStagingNetwork;
NrfWiFiScanResponseIterator mScanResponseIterator;
ScanCallback * mScanCallback{ nullptr };
};

} // namespace NetworkCommissioning
Expand Down

0 comments on commit 2042a6c

Please sign in to comment.