# Events MeshRadio uses an event-based system for asynchronous notifications. Subscribe to events to receive messages, advertisements, and status updates. ## Available Events ### Connected Fired when successfully connected to the device. ```csharp public event Action? Connected; ``` **Example:** ```csharp radio.Connected += (self) => { Console.WriteLine($"Connected to {self.Name}"); Console.WriteLine($"Public Key: {self.PublicKeyPrefix}..."); }; ``` ### Disconnected Fired when disconnected from the device. ```csharp public event Action? Disconnected; ``` **Example:** ```csharp radio.Disconnected += () => { Console.WriteLine("Disconnected from radio"); }; ``` ### ErrorOccurred Fired when an error occurs during communication. ```csharp public event Action? ErrorOccurred; ``` **Example:** ```csharp radio.ErrorOccurred += (error) => { Console.WriteLine($"Error: {error}"); // Consider reconnecting or alerting the user }; ``` ### DirectMessageReceived Fired when a direct message is received from a contact. ```csharp public event Action? DirectMessageReceived; ``` **Example:** ```csharp radio.DirectMessageReceived += (msg) => { Console.WriteLine($"From: {msg.SenderPrefixHex}"); Console.WriteLine($"Text: {msg.Text}"); Console.WriteLine($"Hops: {msg.PathLen}"); if (msg.IsV3) { Console.WriteLine($"Sender: {msg.SenderName}"); Console.WriteLine($"SNR: {msg.Snr} dB"); } }; ``` ### ChannelMessageReceived Fired when a message is received on a channel. ```csharp public event Action? ChannelMessageReceived; ``` **Example:** ```csharp radio.ChannelMessageReceived += (msg) => { Console.WriteLine($"Channel {msg.ChannelIndex}: {msg.Text}"); if (msg.IsV3 && !string.IsNullOrEmpty(msg.SenderName)) { Console.WriteLine($" From: {msg.SenderName}"); } }; ``` ### AdvertReceived Fired when an advertisement is received from the mesh. ```csharp public event Action? AdvertReceived; ``` **Example:** ```csharp radio.AdvertReceived += (advert) => { Console.WriteLine($"Advert from {advert.Name}"); Console.WriteLine($" Key: {advert.PublicKeyHex[..12]}..."); Console.WriteLine($" Hops: {advert.PathLen}, SNR: {advert.Snr} dB"); if (advert.Latitude != 0 || advert.Longitude != 0) { var lat = advert.Latitude / 1_000_000.0; var lon = advert.Longitude / 1_000_000.0; Console.WriteLine($" Location: {lat:F4}, {lon:F4}"); } }; ``` ### MessageWaiting Fired when the device signals that a message is waiting to be fetched. ```csharp public event Action? MessageWaiting; ``` **Example:** ```csharp radio.MessageWaiting += async () => { // Fetch waiting messages DirectMessage? msg; while ((msg = await radio.GetNextMessageAsync()) != null) { Console.WriteLine($"Fetched: {msg.Text}"); } }; ``` ### RawDataReceived Fired when raw data is received (PAYLOAD_TYPE_RAW_CUSTOM). ```csharp public event Action? RawDataReceived; ``` **Example:** ```csharp radio.RawDataReceived += (data) => { Console.WriteLine($"Raw data: {BitConverter.ToString(data)}"); }; ``` ### PacketReceived Fired for every packet received from the device. Useful for debugging and logging. ```csharp public event Action? PacketReceived; ``` **Example:** ```csharp radio.PacketReceived += (packet) => { var code = packet[0]; Console.WriteLine($"[RX] Code: 0x{code:X2}, Length: {packet.Length}"); }; ``` ### PacketSent Fired for every packet sent to the device. Useful for debugging and logging. ```csharp public event Action? PacketSent; ``` **Example:** ```csharp radio.PacketSent += (packet) => { var code = packet[0]; Console.WriteLine($"[TX] Code: 0x{code:X2}, Length: {packet.Length}"); }; ``` ## Complete Example Here's a complete example subscribing to all events: ```csharp using MeshCS; var radio = new MeshRadio("COM11"); // Lifecycle events radio.Connected += (self) => { Console.WriteLine($"✓ Connected: {self.Name}"); }; radio.Disconnected += () => { Console.WriteLine("✗ Disconnected"); }; radio.ErrorOccurred += (error) => { Console.WriteLine($"⚠ Error: {error}"); }; // Message events radio.DirectMessageReceived += (msg) => { var sender = msg.IsV3 && !string.IsNullOrEmpty(msg.SenderName) ? msg.SenderName : msg.SenderPrefixHex; Console.WriteLine($"[DM] {sender}: {msg.Text}"); }; radio.ChannelMessageReceived += (msg) => { var sender = msg.IsV3 && !string.IsNullOrEmpty(msg.SenderName) ? msg.SenderName : "Unknown"; Console.WriteLine($"[CH{msg.ChannelIndex}] {sender}: {msg.Text}"); }; radio.AdvertReceived += (advert) => { Console.WriteLine($"[AD] {advert.Name} seen ({advert.PathLen} hops)"); }; radio.MessageWaiting += () => { Console.WriteLine("[!] Message waiting"); }; // Debug events (optional) if (verbose) { radio.PacketReceived += (pkt) => Console.WriteLine($"[RX] 0x{pkt[0]:X2} ({pkt.Length} bytes)"); radio.PacketSent += (pkt) => Console.WriteLine($"[TX] 0x{pkt[0]:X2} ({pkt.Length} bytes)"); } // Connect and run await radio.ConnectAsync(); await Task.Delay(Timeout.Infinite); ``` ## Thread Safety Events are fired from a background reader thread. If you need to update UI or access shared state, marshal to the appropriate thread: ```csharp // WPF example radio.DirectMessageReceived += (msg) => { Dispatcher.Invoke(() => { MessagesList.Add(msg); }); }; // Generic .NET radio.DirectMessageReceived += (msg) => { lock (_messagesLock) { _messages.Add(msg); } }; ``` ## Unsubscribing To unsubscribe from events: ```csharp void OnMessage(DirectMessage msg) { Console.WriteLine(msg.Text); } // Subscribe radio.DirectMessageReceived += OnMessage; // Unsubscribe radio.DirectMessageReceived -= OnMessage; ```