Skip to content

Examples

Max Litruv Boonzaayer edited this page Feb 15, 2026 · 3 revisions

Examples

Practical code examples for common MeshCS use cases.

Basic Chat Application

A simple console chat application:

using MeshCS;

Console.WriteLine("MeshCS Chat");
Console.WriteLine("===========");

// Connect to device
var radio = await MeshRadio.ConnectFirstAsync(verbose: true);
if (radio == null)
{
    Console.WriteLine("No device found!");
    return;
}

Console.WriteLine($"Connected as: {radio.Self?.Name}");
Console.WriteLine();

// Subscribe to messages
radio.DirectMessageReceived += (msg) =>
{
    var sender = msg.IsV3 && !string.IsNullOrEmpty(msg.SenderName)
        ? msg.SenderName
        : msg.SenderPrefixHex[..8];
    Console.WriteLine($"\n[{sender}]: {msg.Text}");
    Console.Write("> ");
};

radio.ChannelMessageReceived += (msg) =>
{
    var sender = msg.IsV3 && !string.IsNullOrEmpty(msg.SenderName)
        ? msg.SenderName
        : "???";
    Console.WriteLine($"\n[CH{msg.ChannelIndex}|{sender}]: {msg.Text}");
    Console.Write("> ");
};

// Get contacts
var contacts = await radio.GetContactsAsync();
Console.WriteLine($"Contacts: {contacts.Count}");
foreach (var c in contacts)
{
    Console.WriteLine($"  {c.Name} ({c.PublicKeyPrefix})");
}
Console.WriteLine();

// Chat loop
Console.WriteLine("Commands: /list, /ch <n> <msg>, /quit");
Console.WriteLine("Or type a message to send to first contact");
Console.WriteLine();

while (true)
{
    Console.Write("> ");
    var input = Console.ReadLine();
    if (string.IsNullOrWhiteSpace(input)) continue;

    if (input == "/quit") break;
    
    if (input == "/list")
    {
        contacts = await radio.GetContactsAsync();
        foreach (var c in contacts)
            Console.WriteLine($"  {c.Name} ({c.PublicKeyPrefix})");
        continue;
    }

    if (input.StartsWith("/ch "))
    {
        var parts = input[4..].Split(' ', 2);
        if (parts.Length == 2 && byte.TryParse(parts[0], out var ch))
        {
            await radio.SendChannelMessageAsync(ch, parts[1]);
            Console.WriteLine($"Sent to channel {ch}");
        }
        continue;
    }

    // Send to first contact
    if (contacts.Count > 0)
    {
        await radio.SendMessageAsync(contacts[0].PublicKey[..6], input);
        Console.WriteLine("Sent!");
    }
    else
    {
        Console.WriteLine("No contacts to send to");
    }
}

radio.Dispose();

BBS Server

A simple BBS server that responds to commands:

using MeshCS;

Console.WriteLine("MeshCS BBS Server");

var radio = await MeshRadio.ConnectFirstAsync(verbose: true);
if (radio == null) return;

var helpText = @"
Commands:
  HELP - Show this help
  INFO - Server info
  TIME - Current time
  PING - Test connection
";

radio.ChannelMessageReceived += async (msg) =>
{
    var text = msg.Text.Trim().ToUpperInvariant();
    string? response = null;

    switch (text)
    {
        case "HELP":
            response = helpText;
            break;
        case "INFO":
            response = $"MeshCS BBS v1.0\nNode: {radio.Self?.Name}";
            break;
        case "TIME":
            response = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC");
            break;
        case "PING":
            response = "PONG";
            break;
    }

    if (response != null)
    {
        await radio.SendChannelMessageAsync(msg.ChannelIndex, response);
    }
};

Console.WriteLine("Listening... Press Enter to exit.");
Console.ReadLine();

Device Monitor

Monitor device status and mesh activity:

using MeshCS;

var radio = await MeshRadio.ConnectFirstAsync(verbose: true);
if (radio == null) return;

// Get initial info
var device = await radio.DeviceQueryAsync();
var battery = await radio.GetBatteryAsync();

Console.WriteLine($"Device: {device?.Model}");
Console.WriteLine($"Firmware: {device?.FirmwareVersion}");
Console.WriteLine($"Battery: {battery?.Percentage}%");
Console.WriteLine();

var seenNodes = new Dictionary<string, (string Name, DateTime LastSeen)>();

radio.AdvertReceived += (advert) =>
{
    var key = advert.PublicKeyHex[..12];
    seenNodes[key] = (advert.Name, DateTime.UtcNow);
    
    Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] AD: {advert.Name,-16} " +
                      $"Hops:{advert.PathLen} SNR:{advert.Snr,3}dB");
};

radio.DirectMessageReceived += (msg) =>
{
    Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] DM: {msg.SenderPrefixHex} " +
                      $"Hops:{msg.PathLen} SNR:{msg.Snr,3}dB");
};

radio.ChannelMessageReceived += (msg) =>
{
    Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] CH{msg.ChannelIndex}: " +
                      $"Hops:{msg.PathLen} SNR:{msg.Snr,3}dB");
};

// Status update loop
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) => { e.Cancel = true; cts.Cancel(); };

while (!cts.IsCancellationRequested)
{
    await Task.Delay(60000, cts.Token);
    
    battery = await radio.GetBatteryAsync();
    Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] Battery: {battery?.Percentage}% " +
                      $"Nodes seen: {seenNodes.Count}");
}

Port Scanner

Find all MeshCore devices on the system:

using MeshCS;

Console.WriteLine("Scanning for MeshCore devices...\n");

var results = await MeshRadio.ScanAllPortsAsync(
    timeoutMs: 3000,
    verbose: true
);

Console.WriteLine("\n=== Results ===");
foreach (var result in results)
{
    if (result.Found)
    {
        Console.WriteLine($"✓ {result.PortName}: {result.Self?.Name}");
        Console.WriteLine($"    Key: {result.Self?.PublicKeyPrefix}...");
    }
    else if (result.Error != null)
    {
        Console.WriteLine($"✗ {result.PortName}: {result.Error}");
    }
    else
    {
        Console.WriteLine($"- {result.PortName}: No response");
    }
}

var found = results.Where(r => r.Found).ToList();
Console.WriteLine($"\nFound {found.Count} device(s)");

Channel Configuration

Configure and monitor channels:

using MeshCS;

var radio = await MeshRadio.ConnectFirstAsync();
if (radio == null) return;

// Read all channel configurations
Console.WriteLine("Current Channels:");
for (byte i = 0; i < 8; i++)
{
    var ch = await radio.GetChannelAsync(i);
    if (ch != null && !string.IsNullOrEmpty(ch.Name))
    {
        Console.WriteLine($"  [{i}] {ch.Name}");
        Console.WriteLine($"      Secret: {ch.SecretHex[..8]}...");
        Console.WriteLine($"      Forward: {ch.ForwardEnabled}");
    }
}

// Configure a new channel
Console.WriteLine("\nConfiguring channel 1...");
var secret = new byte[16];
Random.Shared.NextBytes(secret);
await radio.SetChannelAsync(1, "MyChannel", secret);

// Verify
var newCh = await radio.GetChannelAsync(1);
Console.WriteLine($"Channel 1 is now: {newCh?.Name}");

Message Logger

Log all messages to a file:

using MeshCS;

var radio = await MeshRadio.ConnectFirstAsync();
if (radio == null) return;

using var logFile = new StreamWriter("mesh_log.txt", append: true);

void Log(string message)
{
    var line = $"[{DateTime.UtcNow:O}] {message}";
    Console.WriteLine(line);
    logFile.WriteLine(line);
    logFile.Flush();
}

Log($"Started logging for {radio.Self?.Name}");

radio.DirectMessageReceived += (msg) =>
{
    Log($"DM from {msg.SenderPrefixHex}: {msg.Text}");
};

radio.ChannelMessageReceived += (msg) =>
{
    Log($"CH{msg.ChannelIndex}: {msg.Text}");
};

radio.AdvertReceived += (advert) =>
{
    Log($"AD: {advert.Name} at {advert.PathLen} hops");
};

radio.ErrorOccurred += (error) =>
{
    Log($"ERROR: {error}");
};

Console.WriteLine("Logging... Press Enter to stop.");
Console.ReadLine();
Log("Logging stopped");

Low-Level Packet Access

For advanced use cases, access packets directly:

using MeshCS;

// Build a custom packet
var packet = PacketBuilder.SendMsg(
    recipientPubKeyPrefix: new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 },
    text: "Hello!",
    textType: TextType.Plain,
    timestamp: (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds()
);

Console.WriteLine($"Packet: {BitConverter.ToString(packet)}");

// Parse a response manually
var response = new byte[] { 0x05, /* ... SelfInfo data ... */ };
var selfInfo = PacketParser.ParseSelfInfo(response);

if (selfInfo != null)
{
    Console.WriteLine($"Parsed: {selfInfo.Name}");
}

// Use debug events to monitor all traffic
var radio = await MeshRadio.ConnectFirstAsync();

radio.PacketSent += (pkt) =>
{
    Console.WriteLine($"TX: {BitConverter.ToString(pkt)}");
};

radio.PacketReceived += (pkt) =>
{
    var code = pkt[0];
    var isPush = (code & 0x80) != 0;
    Console.WriteLine($"RX: 0x{code:X2} ({(isPush ? "PUSH" : "RSP")}) " +
                      $"{pkt.Length} bytes");
};

Contact Management

Full contact management example:

using MeshCS;

var radio = await MeshRadio.ConnectFirstAsync();
if (radio == null) return;

// List all contacts
var contacts = await radio.GetContactsAsync();
Console.WriteLine($"Total contacts: {contacts.Count}");

foreach (var contact in contacts)
{
    var lastSeen = DateTimeOffset.FromUnixTimeSeconds(contact.LastSeen);
    var ago = DateTime.UtcNow - lastSeen.UtcDateTime;
    
    Console.WriteLine($"\n{contact.Name}");
    Console.WriteLine($"  Key: {contact.PublicKeyPrefix}");
    Console.WriteLine($"  Type: {contact.Type}");
    Console.WriteLine($"  Hops: {contact.PathLen}");
    Console.WriteLine($"  Last seen: {ago.TotalMinutes:F0} minutes ago");
}

// Add a contact from a public key (hex string)
var pubKeyHex = "0102030405060708091011121314151617181920212223242526272829303132";
var pubKey = Convert.FromHexString(pubKeyHex);

await radio.AddContactAsync(pubKey, "NewContact", ContactType.Chat);
Console.WriteLine("Contact added!");

// Remove a contact
var toRemove = contacts.FirstOrDefault(c => c.Name == "OldContact");
if (toRemove != null)
{
    await radio.RemoveContactAsync(toRemove.PublicKey[..6]);
    Console.WriteLine("Contact removed!");
}

Clone this wiki locally