switched back to ESP32 and UDP, but without OSC, because serial under windows is a bitch
This commit is contained in:
@@ -1,158 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
public class SerialManager : IDisposable
|
||||
{
|
||||
private SerialPort? port;
|
||||
private DateTime lastResponse = DateTime.UtcNow;
|
||||
|
||||
private const int BaudRate = 115200;
|
||||
private const int PingTimeoutMs = 300;
|
||||
private const int WatchdogTimeoutMs = 3000;
|
||||
|
||||
public bool IsConnected => port != null && port.IsOpen;
|
||||
|
||||
// ---------------- DEVICE DISCOVERY ----------------
|
||||
|
||||
public void DiscoverDevice()
|
||||
{
|
||||
DisposePort();
|
||||
|
||||
foreach (string com in SerialPort.GetPortNames().OrderBy(s => s))
|
||||
{
|
||||
string? response = null;
|
||||
|
||||
try
|
||||
{
|
||||
using (var testPort = CreatePort(com, PingTimeoutMs))
|
||||
{
|
||||
testPort.Open();
|
||||
Thread.Sleep(350); // RP2040 resets on open
|
||||
|
||||
testPort.DiscardInBuffer();
|
||||
testPort.DiscardOutBuffer();
|
||||
|
||||
testPort.Write("PING\n");
|
||||
|
||||
try
|
||||
{
|
||||
if (testPort.BytesToRead > 0)
|
||||
response = testPort.ReadLine();
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// No response — move to next port
|
||||
}
|
||||
}
|
||||
|
||||
if (response != null &&
|
||||
response.StartsWith("Analog_System_Monitor_"))
|
||||
{
|
||||
port = CreatePort(com, 500);
|
||||
port.Open();
|
||||
Thread.Sleep(350); // allow RP2040 reboot again
|
||||
|
||||
lastResponse = DateTime.UtcNow;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Silent fail — move to next COM port
|
||||
}
|
||||
}
|
||||
|
||||
port = null;
|
||||
}
|
||||
|
||||
// ---------------- PORT FACTORY ----------------
|
||||
|
||||
private SerialPort CreatePort(string com, int timeout)
|
||||
{
|
||||
return new SerialPort(com, BaudRate)
|
||||
{
|
||||
Parity = Parity.None,
|
||||
DataBits = 8,
|
||||
StopBits = StopBits.One,
|
||||
Handshake = Handshake.None,
|
||||
|
||||
NewLine = "\n",
|
||||
Encoding = System.Text.Encoding.ASCII,
|
||||
|
||||
ReadTimeout = timeout,
|
||||
WriteTimeout = timeout,
|
||||
|
||||
DtrEnable = true, // REQUIRED for RP2040 USB CDC
|
||||
RtsEnable = true
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------- WATCHDOG ----------------
|
||||
|
||||
public bool WatchdogExpired =>
|
||||
(DateTime.UtcNow - lastResponse).TotalMilliseconds > WatchdogTimeoutMs;
|
||||
|
||||
// ---------------- SEND COMMAND ----------------
|
||||
|
||||
public void SendSetAll(string cmd)
|
||||
{
|
||||
if (!IsConnected)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
port!.Write(cmd + "\n");
|
||||
|
||||
string? response = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (port.BytesToRead > 0)
|
||||
response = port.ReadLine();
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// No response this tick — totally fine
|
||||
}
|
||||
|
||||
if (response != null &&
|
||||
(response.StartsWith("OK") || response.StartsWith("ERROR")))
|
||||
{
|
||||
lastResponse = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Silent fail — watchdog will trigger reconnect
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- CLEANUP ----------------
|
||||
|
||||
private void DisposePort()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (port != null)
|
||||
{
|
||||
port.Close();
|
||||
port.Dispose();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
port = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposePort();
|
||||
}
|
||||
}
|
||||
@@ -9,15 +9,13 @@ public class Telemetry : IDisposable
|
||||
private const int UpdateRateDefaultMs = 1000;
|
||||
public int UpdateRateMs => UpdateRateDefaultMs;
|
||||
|
||||
private readonly SerialManager serial = new SerialManager();
|
||||
private readonly UdpSender udp = new UdpSender();
|
||||
private readonly Computer computer = new Computer();
|
||||
|
||||
// Cached hardware references
|
||||
private IHardware? cpuHw;
|
||||
private IHardware? gpuHw;
|
||||
private IHardware? memHw;
|
||||
|
||||
// Cached sensors
|
||||
private ISensor[] cpuLoadSensors = Array.Empty<ISensor>();
|
||||
private ISensor? cpuTempSensor;
|
||||
|
||||
@@ -33,22 +31,11 @@ public class Telemetry : IDisposable
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
serial.DiscoverDevice();
|
||||
|
||||
// Enable only what we need
|
||||
computer.IsCpuEnabled = true;
|
||||
computer.IsGpuEnabled = true;
|
||||
computer.IsMemoryEnabled = true;
|
||||
|
||||
computer.IsMotherboardEnabled = false;
|
||||
computer.IsControllerEnabled = false;
|
||||
computer.IsNetworkEnabled = false;
|
||||
computer.IsStorageEnabled = false;
|
||||
computer.IsBatteryEnabled = false;
|
||||
computer.IsPsuEnabled = false;
|
||||
|
||||
computer.Open();
|
||||
|
||||
CacheHardwareAndSensors();
|
||||
}
|
||||
|
||||
@@ -145,23 +132,8 @@ public class Telemetry : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private static string F(float v) => v.ToString("0.###", CI);
|
||||
|
||||
public void UpdateAndSend()
|
||||
{
|
||||
if (!serial.IsConnected)
|
||||
{
|
||||
serial.DiscoverDevice();
|
||||
return;
|
||||
}
|
||||
|
||||
if (serial.WatchdogExpired)
|
||||
{
|
||||
serial.DiscoverDevice();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update only the hardware we need
|
||||
cpuHw?.Update();
|
||||
gpuHw?.Update();
|
||||
memHw?.Update();
|
||||
@@ -173,14 +145,22 @@ public class Telemetry : IDisposable
|
||||
float gpuTemp = GetGpuTemperaturePercent();
|
||||
float vram = GetGpuVramPercent();
|
||||
|
||||
string cmd =
|
||||
$"SETALL: {F(cpu)},{F(cpuTemp)},{F(mem)},{F(gpu3d)},{F(gpuTemp)},{F(vram)},0,0";
|
||||
// Prepare 8 floats (future‑proof)
|
||||
float[] packet =
|
||||
{
|
||||
cpu,
|
||||
cpuTemp,
|
||||
mem,
|
||||
gpu3d,
|
||||
gpuTemp,
|
||||
vram,
|
||||
0f, // reserved for future use
|
||||
0f // reserved for future use
|
||||
};
|
||||
|
||||
serial.SendSetAll(cmd);
|
||||
udp.SendFloats(packet);
|
||||
}
|
||||
|
||||
// ---------------- METRICS ----------------
|
||||
|
||||
private float GetCpuLoadPercent()
|
||||
{
|
||||
if (cpuLoadSensors.Length == 0) return 0;
|
||||
@@ -236,7 +216,7 @@ public class Telemetry : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
serial.Dispose();
|
||||
udp.Dispose();
|
||||
computer.Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,13 @@ public class TrayApp : ApplicationContext
|
||||
{
|
||||
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath),
|
||||
Visible = true,
|
||||
Text = "Telemetry Running"
|
||||
Text = "Telemetry Running (UDP)"
|
||||
};
|
||||
|
||||
var menu = new ContextMenuStrip();
|
||||
menu.Items.Add("Exit", null, OnExit);
|
||||
trayIcon.ContextMenuStrip = menu;
|
||||
|
||||
// Start telemetry loop
|
||||
var timer = new System.Windows.Forms.Timer();
|
||||
timer.Interval = 1000;
|
||||
timer.Tick += (s, e) => telemetry.UpdateAndSend();
|
||||
|
||||
64
analog_system_monitor_dotnet/UdpSender.cs
Normal file
64
analog_system_monitor_dotnet/UdpSender.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.Json;
|
||||
|
||||
public class UdpSender : IDisposable
|
||||
{
|
||||
private readonly UdpClient client = new UdpClient();
|
||||
private IPEndPoint endpoint;
|
||||
|
||||
private const string DefaultIp = "192.168.1.50";
|
||||
private const int DefaultPort = 12345;
|
||||
|
||||
public UdpSender()
|
||||
{
|
||||
string exeDir = AppContext.BaseDirectory;
|
||||
string cfgPath = Path.Combine(exeDir, "config.json");
|
||||
|
||||
// Create default config if missing
|
||||
if (!File.Exists(cfgPath))
|
||||
{
|
||||
var defaultCfg = new UdpConfig
|
||||
{
|
||||
esp32_ip = DefaultIp,
|
||||
esp32_port = DefaultPort
|
||||
};
|
||||
|
||||
string json = JsonSerializer.Serialize(
|
||||
defaultCfg,
|
||||
new JsonSerializerOptions { WriteIndented = true }
|
||||
);
|
||||
|
||||
File.WriteAllText(cfgPath, json);
|
||||
}
|
||||
|
||||
// Load config
|
||||
var jsonText = File.ReadAllText(cfgPath);
|
||||
var cfg = JsonSerializer.Deserialize<UdpConfig>(jsonText)
|
||||
?? throw new Exception("Invalid config.json");
|
||||
|
||||
endpoint = new IPEndPoint(IPAddress.Parse(cfg.esp32_ip), cfg.esp32_port);
|
||||
}
|
||||
|
||||
public void SendFloats(float[] values)
|
||||
{
|
||||
string packet = string.Join(",", values);
|
||||
byte[] data = System.Text.Encoding.ASCII.GetBytes(packet);
|
||||
client.Send(data, data.Length, endpoint);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
client.Dispose();
|
||||
}
|
||||
|
||||
private class UdpConfig
|
||||
{
|
||||
public string esp32_ip { get; set; } = DefaultIp;
|
||||
public int esp32_port { get; set; } = DefaultPort;
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@
|
||||
<!-- No trimming (LHM + reflection will break) -->
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
|
||||
<!-- No compression (avoids startup delays + debugging issues) -->
|
||||
<EnableCompressionInSingleFile>false</EnableCompressionInSingleFile>
|
||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
|
||||
<!-- Keep debugging symbols optional -->
|
||||
<DebugType>none</DebugType>
|
||||
|
||||
Reference in New Issue
Block a user