Skip to content

Commit

Permalink
Add first sample for OpenThread (#371)
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianSoundy authored Jul 17, 2024
1 parent 4a069cc commit f7f6280
Show file tree
Hide file tree
Showing 14 changed files with 995 additions and 0 deletions.
59 changes: 59 additions & 0 deletions samples/OpenThread/Display.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

using nanoFramework.Networking.Thread;
using System;
using System.Text;

namespace Samples
{
internal class Display
{
public static string LH
{
get { return DateTime.UtcNow.ToString("HH:mm:ss") + "-"; }
}

public static void Log(string str)
{
Console.WriteLine($"{LH} {str}");
}

public static void Log(string[] strings)
{
foreach (string line in strings)
{
Log(line);
}
}

public static void Role(ThreadDeviceRole role)
{
switch (role)
{
case ThreadDeviceRole.Child: Log("Role = Child"); break;
case ThreadDeviceRole.Router: Log("Role = Router"); break;
case ThreadDeviceRole.Leader: Log("Role = Leader"); break;
case ThreadDeviceRole.Detached: Log("Role = Detached"); break;
case ThreadDeviceRole.Disabled: Log("Role = Disabled"); break;
default:
Log($"Role is {role}");
break;
}
}

public static void LogMemoryStats(string info)
{
uint manMem = nanoFramework.Runtime.Native.GC.Run(true);

uint total;
uint free;
uint largest;

nanoFramework.Hardware.Esp32.NativeMemory.GetMemoryInfo(nanoFramework.Hardware.Esp32.NativeMemory.MemoryType.All, out total, out free, out largest);
Console.WriteLine($"{LH} Memory All ({info}) Managed:{manMem} Native total:{total}/Free:{free}/Largest:{largest}");
}
}
}
90 changes: 90 additions & 0 deletions samples/OpenThread/Led.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

using System;
using System.Drawing;
using System.Threading;
using nanoFramework.Runtime.Native;
using CCSWE.nanoFramework.NeoPixel;
using CCSWE.nanoFramework.NeoPixel.Drivers;
using nanoFramework.Networking.Thread;

namespace Samples
{
public class Led
{
private NeoPixelStrip _led;
private ThreadDeviceRole _role;

/// <summary>
/// Open _led for inbuilt Neopixel
/// </summary>
public Led()
{
if (SystemInfo.TargetName.Contains("ESP32_H2") || SystemInfo.TargetName.Contains("ESP32_C6"))
{
var driver = new Ws2812B(CCSWE.nanoFramework.NeoPixel.ColorOrder.GRB);
_led = new NeoPixelStrip(8, 1, driver);
}
else
{
_led = null;
}
}

public void SetRxTX()
{
Set(_role, 0.2f);
Thread.Sleep(50);
Set(_role, 0.1f);
}

public void Set(ThreadDeviceRole role)
{
Set(role, 0.1f);
}

private void Set(ThreadDeviceRole role, float brightness)
{
Color col;

if (_led == null)
{
return;
}

// Save it for RXTX
_role = role;

switch (role)
{
case ThreadDeviceRole.Detached:
col = Color.White;
break;

case ThreadDeviceRole.Child:
col = Color.Green;
break;

case ThreadDeviceRole.Router:
col = Color.Blue;
break;

case ThreadDeviceRole.Leader:
col = Color.Red;
break;

case ThreadDeviceRole.Disabled:
default:
col = Color.Black;
brightness = 0;
break;
}

_led.SetLed(0, col, brightness);
_led.Update();
}
}
}
76 changes: 76 additions & 0 deletions samples/OpenThread/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# 🌶️🌶️ - OpenTHread Networking sample pack

Shows how to use OpenThread Networking API.

## Samples

- [🌶️🌶️🌶️ - UPD OpenThread Client using sockets](UdpThreadClient/)
- [🌶️🌶️🌶️ - UPD OpenThread Server using sockets](UdpThreadServer/)

Shows how to use various APIs related to OpenThread.

## Hardware requirements

These project are for the ESP32_C6 and ESP32_H2 Espressif devkit boards with a Ws2812B Neopixel on pin 8.
This can be easily disabled or Ws2812B added to pin 8 for other boards.

## Sample description

### Upd socket samples

These 2 sample work together to create a client / server communications over OpenThread.
They use UPD sockets over the IPV6 networking of the OpenThread stack.

The neopixel shows the current role of the node.

- White -> Detached from network
- Green -> Child
- Blue -> Router
- Red -> Leader

The led will flash when message is transmitted or received.

The samples use the CCSWE.nanoFramework.Neopixel for driving the neopixels.

There is currently a problem driving the RMT on the ESP32_H2 devices as the core frequency for RMT is
32Mhz instead of 80Mhz. This will be fixed shortly.

#### UdpThreadClient

This sample will send a broadcast message every 5 seconds using the built-in mesh broadcast address "ff03::1" and port 12324.
Any UdpThreadServer running on the same mesh network will receive message and respond back to sender.
Any received messages are logged on console.

#### UdpThreadServer

Sample opens sockets and waits for any messages on port 1234. If any message is received to is echoed back to sending address.

## Related topics

### Reference

- [nanoFramework.Networking.Thread](http://docs.nanoframework.net/api/nanoFramework.Networking.Thread)

## Build the sample

1. Start Microsoft Visual Studio 2022 or Visual Studio 2019 (Visual Studio 2017 should be OK too) and select `File > Open > Project/Solution`.
1. Starting in the folder where you unzipped the samples/cloned the repository, go to the subfolder for this specific sample. Double-click the Visual Studio Solution (.sln) file.
1. Press `Ctrl+Shift+B`, or select `Build > Build Solution`.

## Run the sample

The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it.

### Deploying the sample

- Select `Build > Deploy Solution`.

### Deploying and running the sample

- To debug the sample and then run it, press F5 or select `Debug > Start Debugging`.

> [!NOTE]
>
> **Important**: Before deploying or running the sample, please make sure your device is visible in the Device Explorer.
>
> **Tip**: To display the Device Explorer, go to Visual Studio menus: `View > Other Windows > Device Explorer`.
105 changes: 105 additions & 0 deletions samples/OpenThread/SocketUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

using System;
using System.Net.Sockets;
using System.Net;
using System.Text;

namespace Samples
{
internal class NetUtils
{
private static Socket socket;

/// <summary>
/// Open a new UDP socket
/// </summary>
/// <param name="remoteAdr"></param>
/// <param name="port"></param>
public static void OpenUdpSocket(String remoteAdr, int port, IPAddress endpoint)
{
socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);

// Interface / port to receive on
IPEndPoint ep = new IPEndPoint(endpoint, port);
socket.Bind(ep);

if (remoteAdr.Length > 0)
{
// Set remote address
var address = IPAddress.Parse(remoteAdr);
IPEndPoint rep = new IPEndPoint(address, port);
socket.Connect(rep);
}
}

/// <summary>
/// Close open socket
/// </summary>
public static void CloseUdpSocket()
{
socket.Close();
socket = null;
}

/// <summary>
/// Send message to specific target / port
/// </summary>
/// <param name="port">Port number to send to</param>
/// <param name="targetAdr">Target IP address</param>
/// <param name="message">MEssage to send</param>
public static void SendMessageSocketTo(int port, string targetAdr, string message)
{
var data = Encoding.UTF8.GetBytes(message);

var address = IPAddress.Parse(targetAdr);
IPEndPoint ep = new IPEndPoint(address, port);

socket.SendTo(data, ep);
}

/// <summary>
/// Send message to connected target, target specified in Open
/// </summary>
/// <param name="message"></param>
public static void SendMessage(string message)
{
var data = Encoding.UTF8.GetBytes(message);
socket.Send(data);
}

/// <summary>
/// Method for receiving and displaying messages from UDP socket.
/// If respond param true will respond with generic message (like a server)
/// </summary>
/// <param name="respond"></param>
public static void ReceiveUdpMessages(bool respond = false)
{
Display.Log($"Receive thread for UDP messages started");

while (true)
{
byte[] data = new byte[256];
EndPoint remoteEp = new IPEndPoint(0, 0);

int length = socket.ReceiveFrom(data, ref remoteEp);

var message = Encoding.UTF8.GetString(data, 0, length);

Display.Log($"UDP message(sock) >{message}< received from {remoteEp}");

Program._led.SetRxTX();

if (respond)
{
IPEndPoint rp = remoteEp as IPEndPoint;
SendMessageSocketTo(rp.Port, rp.Address.ToString(), $"Server response {DateTime.UtcNow}");
Display.Log($"UDP message(sock) >{message}< respond to {rp.Address} {rp.Port}");
}
}
}
}
}
Loading

0 comments on commit f7f6280

Please sign in to comment.