Skip to content

Commit

Permalink
Improving WiFi AP sample (#349)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ellerbach authored Jan 29, 2024
1 parent ce92975 commit 4a66f23
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 83 deletions.
87 changes: 21 additions & 66 deletions samples/WiFiAP/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,84 +18,39 @@ namespace WifiAP
public class Program
{
// Start Simple WebServer
static WebServer server = new WebServer();
private static WebServer _server = new WebServer();
private static bool _wifiApMode = false;

// Connected Station count
static int connectedCount = 0;
private static int _connectedCount = 0;

// GPIO pin used to put device into AP set-up mode
const int SETUP_PIN = 5;
private const int SetupPin = 5;

public static void Main()
{
Debug.WriteLine("Welcome to WiFI Soft AP world!");

var gpioController = new GpioController();
GpioPin setupButton = gpioController.OpenPin(SETUP_PIN, PinMode.InputPullUp);
GpioPin setupButton = gpioController.OpenPin(SetupPin, PinMode.InputPullUp);

// If Wireless station is not enabled then start Soft AP to allow Wireless configuration
// or Button pressed
if (!Wireless80211.IsEnabled() || (setupButton.Read() == PinValue.High))
if (setupButton.Read() == PinValue.High)
{

Wireless80211.Disable();
if (WirelessAP.Setup() == false)
{
// Reboot device to Activate Access Point on restart
Debug.WriteLine($"Setup Soft AP, Rebooting device");
Power.RebootDevice();
}

var dhcpserver = new DhcpServer
{
CaptivePortalUrl = $"http://{WirelessAP.SoftApIP}"
};
var dhcpInitResult = dhcpserver.Start(IPAddress.Parse(WirelessAP.SoftApIP), new IPAddress(new byte[] { 255, 255, 255, 0 }));
if (!dhcpInitResult)
{
Debug.WriteLine($"Error initializing DHCP server.");
}

Debug.WriteLine($"Running Soft AP, waiting for client to connect");
Debug.WriteLine($"Soft AP IP address :{WirelessAP.GetIP()}");

// Link up Network event to show Stations connecting/disconnecting to Access point.
//NetworkChange.NetworkAPStationChanged += NetworkChange_NetworkAPStationChanged;
// Now that the normal Wifi is deactivated, that we have setup a static IP
// We can start the Web server
server.Start();
WirelessAP.SetWifiAp();
_wifiApMode = true;
}
else
{
Debug.WriteLine($"Running in normal mode, connecting to Access point");
var conf = Wireless80211.GetConfiguration();

bool success;

// For devices like STM32, the password can't be read
if (string.IsNullOrEmpty(conf.Password))
{
// In this case, we will let the automatic connection happen
success = WifiNetworkHelper.Reconnect(requiresDateTime: true, token: new CancellationTokenSource(60000).Token);
}
else
{
// If we have access to the password, we will force the reconnection
// This is mainly for ESP32 which will connect normaly like that.
success = WifiNetworkHelper.ConnectDhcp(conf.Ssid, conf.Password, requiresDateTime: true, token: new CancellationTokenSource(60000).Token);
}

if (success)
{
Debug.WriteLine($"Connection is {success}");
Debug.WriteLine($"We have a valid date: {DateTime.UtcNow}");
}
else
{
Debug.WriteLine($"Something wrong happened, can't connect at all");
}
_wifiApMode = Wireless80211.ConnectOrSetAp();
}

Console.WriteLine($"Connected with wifi credentials. IP Address: {(_wifiApMode ? WirelessAP.GetIP() : Wireless80211.GetCurrentIPAddress())}");
if( _wifiApMode )
{
_server.Start();
}

// Just wait for now
// Here you would have the reset of your program using the client WiFI link
Expand All @@ -120,26 +75,26 @@ private static void NetworkChange_NetworkAPStationChanged(int NetworkIndex, Netw
string macString = BitConverter.ToString(station.MacAddress);
Debug.WriteLine($"Station mac {macString} Rssi:{station.Rssi} PhyMode:{station.PhyModes} ");

connectedCount++;
_connectedCount++;

// Start web server when it connects otherwise the bind to network will fail as
// no connected network. Start web server when first station connects
if (connectedCount == 1)
if (_connectedCount == 1)
{
// Wait for Station to be fully connected before starting web server
// other you will get a Network error
Thread.Sleep(2000);
server.Start();
_server.Start();
}
}
else
{
// Station disconnected. When no more station connected then stop web server
if (connectedCount > 0)
if (_connectedCount > 0)
{
connectedCount--;
if (connectedCount == 0)
server.Stop();
_connectedCount--;
if (_connectedCount == 0)
_server.Stop();
}
}

Expand Down
6 changes: 6 additions & 0 deletions samples/WiFiAP/WebServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ private void ProcessRequest(HttpListenerContext context)

string message = "<p>New settings saved.</p><p>Rebooting device to put into normal mode</p>";

bool res = Wireless80211.Configure(ssid, password);
if (res)
{
message += $"<p>And your new IP address should be {Wireless80211.GetCurrentIPAddress()}.</p>";
}

responseString = CreateMainPage(message);

OutPutResponse(response, responseString);
Expand Down
10 changes: 4 additions & 6 deletions samples/WiFiAP/WiFiAP.nfproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,15 @@
<HintPath>packages\nanoFramework.System.Device.Gpio.1.1.38\lib\System.Device.Gpio.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Device.Wifi, Version=1.5.71.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>packages\nanoFramework.System.Device.Wifi.1.5.71\lib\System.Device.Wifi.dll</HintPath>
<Private>True</Private>
<Reference Include="System.Device.Wifi">
<HintPath>packages\nanoFramework.System.Device.Wifi.1.5.74\lib\System.Device.Wifi.dll</HintPath>
</Reference>
<Reference Include="System.IO.Streams, Version=1.1.52.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>packages\nanoFramework.System.IO.Streams.1.1.52\lib\System.IO.Streams.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net, Version=1.10.68.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>packages\nanoFramework.System.Net.1.10.68\lib\System.Net.dll</HintPath>
<Private>True</Private>
<Reference Include="System.Net">
<HintPath>packages\nanoFramework.System.Net.1.10.70\lib\System.Net.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http, Version=1.5.118.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
<HintPath>packages\nanoFramework.System.Net.Http.Server.1.5.118\lib\System.Net.Http.dll</HintPath>
Expand Down
81 changes: 75 additions & 6 deletions samples/WiFiAP/Wireless80211.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// See LICENSE file in the project root for full license information.
//

using System;
using System.Device.Wifi;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Threading;
Expand All @@ -12,19 +14,62 @@ namespace WifiAP
{
class Wireless80211
{
/// <summary>
/// Checks if the wireless 802.11 interface is enabled.
/// </summary>
/// <returns>
/// Returns true if the wireless 802.11 interface is enabled (i.e., the SSID is not null or empty),
/// otherwise returns false.
/// </returns>
public static bool IsEnabled()
{
Wireless80211Configuration wconf = GetConfiguration();
return !string.IsNullOrEmpty(wconf.Ssid);
}

/// <summary>
/// Get current IP address. Only valid if successfully provisioned and connected
/// </summary>
/// <returns>IP address string</returns>
public static string GetCurrentIPAddress()
{
NetworkInterface ni = NetworkInterface.GetAllNetworkInterfaces()[0];

// get first NI ( Wifi on ESP32 )
return ni.IPv4Address.ToString();
}

/// <summary>
/// Coonnects to the Wifi or sets the Access Point mode.
/// </summary>
/// <returns>True if access point is setup.</returns>
public static bool ConnectOrSetAp()
{
if (IsEnabled())
{
Debug.WriteLine("Wireless client activated");
if (!WifiNetworkHelper.Reconnect(true, token: new CancellationTokenSource(30_000).Token))
{
WirelessAP.SetWifiAp();
return true;
}
}
else
{
WirelessAP.SetWifiAp();
return true;
}

return false;
}

/// <summary>
/// Disable the Wireless station interface.
/// </summary>
public static void Disable()
{
Wireless80211Configuration wconf = GetConfiguration();
wconf.Options = Wireless80211Configuration.ConfigurationOptions.None;
wconf.Options = Wireless80211Configuration.ConfigurationOptions.None | Wireless80211Configuration.ConfigurationOptions.SmartConfig;
wconf.SaveConfiguration();
}

Expand All @@ -35,14 +80,38 @@ public static void Disable()
/// <param name="password"></param>
/// <returns></returns>
public static bool Configure(string ssid, string password)
{
// And we have to force connect once here even for a short time
var success = WifiNetworkHelper.ConnectDhcp(ssid, password, token: new CancellationTokenSource(10000).Token);
Debug.WriteLine($"Connection is {success}");
{
// Make sure we are disconnected before we start connecting otherwise
// ConnectDhcp will just return success instead of reconnecting.
WifiAdapter wa = WifiAdapter.FindAllAdapters()[0];
wa.Disconnect();

CancellationTokenSource cs = new(30_000);
Console.WriteLine("ConnectDHCP");
WifiNetworkHelper.Disconnect();

// Reconfigure properly the normal wifi
Wireless80211Configuration wconf = GetConfiguration();
wconf.Options = Wireless80211Configuration.ConfigurationOptions.AutoConnect | Wireless80211Configuration.ConfigurationOptions.Enable;
wconf.Ssid = ssid;
wconf.Password = password;
wconf.SaveConfiguration();
return true;

WifiNetworkHelper.Disconnect();
bool success;

success = WifiNetworkHelper.ConnectDhcp(ssid, password, WifiReconnectionKind.Automatic, true, token: cs.Token);

if (!success)
{
wa.Disconnect();
// Bug in network helper, we've most likely try to connect before, let's make it manual
var res = wa.Connect(ssid, WifiReconnectionKind.Automatic, password);
success = res.ConnectionStatus == WifiConnectionStatus.Success;
Console.WriteLine($"Connected: {res.ConnectionStatus}");
}

return success;
}

/// <summary>
Expand Down
54 changes: 51 additions & 3 deletions samples/WiFiAP/WirelessAP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,57 @@
// See LICENSE file in the project root for full license information.
//

using System;
using System.Net;
using System.Net.NetworkInformation;
using Iot.Device.DhcpServer;
using nanoFramework.Runtime.Native;

namespace WifiAP
{
/// <summary>
/// Provides methods and properties to manage a wireless access point.
/// </summary>
public static class WirelessAP
{
public const string SoftApIP = "192.168.4.1";
/// <summary>
/// Gets or sets the IP address of the Soft AP.
/// </summary>
public static string SoftApIP { get; set; } = "192.168.4.1";

/// <summary>
/// Gets or sets the SSID of the Soft AP.
/// </summary>
public static string SoftApSsid { get; set; } = "MySuperSSID";

/// <summary>
/// Sets the configuration for the wireless access point.
/// </summary>
public static void SetWifiAp()
{
Wireless80211.Disable();
if (Setup() == false)
{
// Reboot device to Activate Access Point on restart
Console.WriteLine($"Setup Soft AP, Rebooting device");
Power.RebootDevice();
}

var dhcpserver = new DhcpServer
{
CaptivePortalUrl = $"http://{SoftApIP}"
};
var dhcpInitResult = dhcpserver.Start(IPAddress.Parse(SoftApIP), new IPAddress(new byte[] { 255, 255, 255, 0 }));
if (!dhcpInitResult)
{
Console.WriteLine($"Error initializing DHCP server.");
// This happens after a very freshly flashed device
Power.RebootDevice();
}

Console.WriteLine($"Running Soft AP, waiting for client to connect");
Console.WriteLine($"Soft AP IP address :{GetIP()}");
}

/// <summary>
/// Disable the Soft AP for next restart.
Expand Down Expand Up @@ -51,13 +95,13 @@ public static bool Setup()
WirelessAPConfiguration.ConfigurationOptions.Enable;

// Set the SSID for Access Point. If not set will use default "nano_xxxxxx"
//wapconf.Ssid = "MySsid";
wapconf.Ssid = SoftApSsid;

// Maximum number of simultaneous connections, reserves memory for connections
wapconf.MaxConnections = 1;

// To set-up Access point with no Authentication
wapconf.Authentication = AuthenticationType.Open;
wapconf.Authentication = System.Net.NetworkInformation.AuthenticationType.Open;
wapconf.Password = "";

// To set up Access point with no Authentication. Password minimum 8 chars.
Expand All @@ -80,6 +124,10 @@ public static WirelessAPConfiguration GetConfiguration()
return WirelessAPConfiguration.GetAllWirelessAPConfigurations()[ni.SpecificConfigId];
}

/// <summary>
/// Gets the network interface for the wireless access point.
/// </summary>
/// <returns>The network interface for the wireless access point.</returns>
public static NetworkInterface GetInterface()
{
NetworkInterface[] Interfaces = NetworkInterface.GetAllNetworkInterfaces();
Expand Down
4 changes: 2 additions & 2 deletions samples/WiFiAP/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
<package id="nanoFramework.Runtime.Native" version="1.6.12" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Collections" version="1.5.31" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Device.Gpio" version="1.1.38" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Device.Wifi" version="1.5.71" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Device.Wifi" version="1.5.74" targetFramework="netnano1.0" />
<package id="nanoFramework.System.IO.Streams" version="1.1.52" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Net" version="1.10.68" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Net" version="1.10.70" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Net.Http.Server" version="1.5.118" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Text" version="1.2.54" targetFramework="netnano1.0" />
<package id="nanoFramework.System.Threading" version="1.1.32" targetFramework="netnano1.0" />
Expand Down

0 comments on commit 4a66f23

Please sign in to comment.