switched back to ESP32 and UDP, but without OSC, because serial under windows is a bitch

This commit is contained in:
2026-01-18 05:41:51 +01:00
parent 2311647885
commit a9957bc695
6 changed files with 202 additions and 285 deletions

View File

@@ -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();
}
}

View File

@@ -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 (futureproof)
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();
}
}

View File

@@ -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();

View 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;
}
}

View File

@@ -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>