Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,59 @@ var success = WaitForValidIPAndDate(true, NetworkInterfaceType.Ethernet, cs.Toke
// if success is true then you are connected
```

### Retry and reconfiguration

#### Retry after timeout

Token-based methods (`ConnectDhcp`, `ScanAndConnectDhcp`, `ConnectFixAddress`) are retryable. If a connection attempt times out, call the method again:

```csharp
bool connected = false;
while (!connected)
{
CancellationTokenSource cs = new(30000);
connected = WifiNetworkHelper.ConnectDhcp(Ssid, Password, requiresDateTime: true, token: cs.Token);
if (!connected)
{
Debug.WriteLine($"Not ready, status: {WifiNetworkHelper.Status}");
Thread.Sleep(5000);
}
}
```

#### Switching networks or restarting

To switch to a different SSID or restart the event-based helper, call `Reset()` first:

```csharp
// Disconnect from current network if needed
WifiNetworkHelper.Disconnect();

// Reset the helper so it can be reconfigured
WifiNetworkHelper.Reset();

// Connect to a different SSID
CancellationTokenSource cs = new(30000);
WifiNetworkHelper.ConnectDhcp("NewSSID", "NewPassword", token: cs.Token);
```

The same applies to the event-based `SetupNetworkHelper`:

```csharp
WifiNetworkHelper.Reset();
WifiNetworkHelper.SetupNetworkHelper("NewSSID", "NewPassword");
```

#### `Reconnect()` vs. `ConnectDhcp()`

`Reconnect()` does **not** actively send join credentials. It only waits for the platform's automatic reconnection (configured via `WifiReconnectionKind.Automatic`) to produce a valid IP address. Use it only when credentials are already stored on the device and the platform is expected to reconnect automatically.

If you need an explicit reconnect with credentials, use `ConnectDhcp()` instead.

#### `NetworkReady` behaviour

When using `SetupNetworkHelper()`, `NetworkReady` is reset when the connection is lost and re-signaled when it is restored, accurately reflecting live network state. Code that previously assumed `NetworkReady` would remain set permanently after first connect should be updated to handle transient disconnects.

## Feedback and documentation

For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
Expand Down
232 changes: 141 additions & 91 deletions System.Device.Wifi/NetworkHelper/WifiNetworkHelper.cs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion System.Device.Wifi/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

////////////////////////////////////////////////////////////////
// update this whenever the native assembly signature changes //
[assembly: AssemblyNativeVersion("100.2.0.0")]
[assembly: AssemblyNativeVersion("100.2.0.1")]
////////////////////////////////////////////////////////////////

// Setting ComVisible to false makes the types in this assembly not visible
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void TestFixIPAddress_01()
Assert.IsNull(WifiNetworkHelper.HelperException);

// need to reset this internal flag to allow calling the NetworkHelper again
WifiNetworkHelper.ResetInstance();
WifiNetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -62,7 +62,7 @@ public void TestFixedIPAddress_02()
Assert.IsTrue(WifiNetworkHelper.NetworkReady.WaitOne(10000, true));

// need to reset this internal flag to allow calling the NetworkHelper again
WifiNetworkHelper.ResetInstance();
WifiNetworkHelper.Reset();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void TestNormalConnectionScanAndConnect()
Assert.IsNull(WifiNetworkHelper.HelperException);

// need to reset this internal flag to allow calling the NetworkHelper again
WifiNetworkHelper.ResetInstance();
WifiNetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -58,7 +58,7 @@ public void TestDhcp_01()
Assert.IsNull(WifiNetworkHelper.HelperException);

// need to reset this internal flag to allow calling the NetworkHelper again
WifiNetworkHelper.ResetInstance();
WifiNetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -70,7 +70,7 @@ public void TestDhcp_02()
Assert.IsTrue(WifiNetworkHelper.NetworkReady.WaitOne(10000, true));

// need to reset this internal flag to allow calling the NetworkHelper again
WifiNetworkHelper.ResetInstance();
WifiNetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -84,6 +84,9 @@ public void TestSingleUsage()
// call twice, it's a NO NO and should throw an exception
WifiNetworkHelper.SetupNetworkHelper();
});

// clear static state so this test doesn't affect later tests
WifiNetworkHelper.Reset();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,67 @@ public void TestNormalConnection()
Assert.IsTrue(success);
Assert.IsNull(WifiNetworkHelper.HelperException);

// need to reset this internal flag to allow calling the NetworkHelper again
WifiNetworkHelper.ResetInstance();
WifiNetworkHelper.Reset();
}

[TestMethod]
public void TestRetryAfterTimeout()
{
// First attempt: very short timeout so it expires
CancellationTokenSource cs1 = new(1000);
var firstResult = WifiNetworkHelper.ConnectDhcp(
Ssid,
Password,
token: cs1.Token);

Assert.IsFalse(firstResult, "First call should have timed out");

// Second attempt with a longer timeout — must not throw InvalidOperationException
CancellationTokenSource cs2 = new(15000);
var secondResult = WifiNetworkHelper.ConnectDhcp(
Ssid,
Password,
requiresDateTime: true,
token: cs2.Token);

DisplayLastError(secondResult);
Assert.IsTrue(secondResult, "Second attempt should succeed after retry");

WifiNetworkHelper.Reset();
}

[TestMethod]
public void TestResetAllowsEventBasedRestart()
{
// Use event-based helper once
WifiNetworkHelper.SetupNetworkHelper(Ssid, Password);

bool connected = WifiNetworkHelper.NetworkReady.WaitOne(15000, true);
Assert.IsTrue(connected, "Expected to connect on first event-based attempt");

// Reset and restart with same credentials
WifiNetworkHelper.Reset();
WifiNetworkHelper.SetupNetworkHelper(Ssid, Password);

connected = WifiNetworkHelper.NetworkReady.WaitOne(15000, true);
Assert.IsTrue(connected, "Expected to connect after Reset + SetupNetworkHelper restart");

WifiNetworkHelper.Reset();
}

[TestMethod]
public void TestSingleUsageEventBased()
{
Assert.ThrowsException(typeof(System.InvalidOperationException), () =>
{
// First call is OK
WifiNetworkHelper.SetupNetworkHelper(Ssid, Password);

// Second call without Reset must throw
WifiNetworkHelper.SetupNetworkHelper(Ssid, Password);
});

WifiNetworkHelper.Reset();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void TestReconnection()
Assert.IsNull(WifiNetworkHelper.HelperException);

// need to reset this internal flag to allow calling the NetworkHelper again
WifiNetworkHelper.ResetInstance();
WifiNetworkHelper.Reset();
}
}
}