Make UI event-driven, heat maps at 10Hz from tick loop

- Heat maps fed from tick loop via BeginInvoke (10Hz, one column per tick)
- BLE label updates on ConnectionChanged event (was 4Hz poll)
- Recv gauges update on StrengthChanged event (B1 notifications)
- Button states refreshed via RefreshButtonStates on all state changes
- Status timer reduced from 250ms to 1s — only music label + tray icon
- Eliminates 4Hz choppy polling
This commit is contained in:
2026-08-08 11:38:05 +00:00
parent 33e289d596
commit 8b51ff19a8
+45 -23
View File
@@ -260,7 +260,7 @@ public class MainForm : Form
_tray.ContextMenuStrip.Items.Add("Exit", null, (_, _) => ExitFromTray()); _tray.ContextMenuStrip.Items.Add("Exit", null, (_, _) => ExitFromTray());
_tray.DoubleClick += (_, _) => ShowFromTray(); _tray.DoubleClick += (_, _) => ShowFromTray();
_statusTimer = new System.Windows.Forms.Timer { Interval = 250 }; _statusTimer = new System.Windows.Forms.Timer { Interval = 1000 };
_statusTimer.Tick += OnStatusTick; _statusTimer.Tick += OnStatusTick;
_statusTimer.Start(); _statusTimer.Start();
@@ -269,6 +269,8 @@ public class MainForm : Form
Resize += OnResize; Resize += OnResize;
_server.ClientChanged += OnWsClientChanged; _server.ClientChanged += OnWsClientChanged;
_device.ConnectionChanged += OnDeviceConnectionChanged;
_device.StrengthChanged += OnDeviceStrengthChanged;
} }
async void OnLoad(object? sender, EventArgs e) async void OnLoad(object? sender, EventArgs e)
@@ -297,6 +299,14 @@ public class MainForm : Form
var frame = B0.Build(0, modeA, modeB, valA, valB, freqA, intA, freqB, intB); var frame = B0.Build(0, modeA, modeB, valA, valB, freqA, intA, freqB, intB);
await _device.SendB0(frame); await _device.SendB0(frame);
} }
if (!IsDisposed)
{
BeginInvoke(() =>
{
_heatA.AddTick(freqA, intA, _state.LastActiveA);
_heatB.AddTick(freqB, intB, _state.LastActiveB);
});
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -368,31 +378,44 @@ public class MainForm : Form
BeginInvoke(() => BeginInvoke(() =>
{ {
_lblWs.Text = connected ? "WS: client connected" : "WS: idle"; _lblWs.Text = connected ? "WS: client connected" : "WS: idle";
_btnTest.Enabled = !connected && !IsTestRunning; RefreshButtonStates();
_btnMusic.Enabled = !connected && !_isMusicRunning;
UpdateTrayIcon(); UpdateTrayIcon();
}); });
} }
void OnDeviceConnectionChanged(bool connected)
{
if (IsDisposed) return;
BeginInvoke(() =>
{
_lblBle.Text = connected
? $"BLE: connected ({_device.DeviceName})"
: "BLE: disconnected";
_btnConnect.Enabled = !connected;
RefreshButtonStates();
});
}
void OnDeviceStrengthChanged(int a, int b)
{
if (IsDisposed) return;
BeginInvoke(() =>
{
_gaugeRecvA.Value = Math.Clamp(a, 0, 200);
_gaugeRecvB.Value = Math.Clamp(b, 0, 200);
});
}
void RefreshButtonStates()
{
_btnTest.Enabled = !_server.HasClient && !IsTestRunning;
_btnMusic.Enabled = !_server.HasClient && !_isMusicRunning;
_btnStop.Enabled = true;
}
void OnStatusTick(object? sender, EventArgs e) void OnStatusTick(object? sender, EventArgs e)
{ {
if (IsDisposed) return; if (IsDisposed) return;
_lblBle.Text = _device.IsConnected
? $"BLE: connected ({_device.DeviceName})"
: "BLE: disconnected";
_heatA.AddTick(
_state.LastFreqA ?? Array.Empty<byte>(),
_state.LastIntA ?? Array.Empty<byte>(),
_state.LastActiveA);
_heatB.AddTick(
_state.LastFreqB ?? Array.Empty<byte>(),
_state.LastIntB ?? Array.Empty<byte>(),
_state.LastActiveB);
_gaugeRecvA.Value = Math.Clamp(_device.StrengthA, 0, 200);
_gaugeRecvB.Value = Math.Clamp(_device.StrengthB, 0, 200);
_btnTest.Enabled = !_server.HasClient && !IsTestRunning;
_btnMusic.Enabled = !_server.HasClient && !_isMusicRunning;
_btnStop.Enabled = true;
if (_isMusicRunning && _musicStopwatch != null) if (_isMusicRunning && _musicStopwatch != null)
{ {
@@ -457,7 +480,7 @@ public class MainForm : Form
BeginInvoke(() => BeginInvoke(() =>
{ {
IsTestRunning = false; IsTestRunning = false;
_btnTest.Enabled = !_server.HasClient; RefreshButtonStates();
}); });
} }
@@ -525,8 +548,7 @@ public class MainForm : Form
{ {
_lblTrack.Text = $"Analysis failed: {ex.Message}"; _lblTrack.Text = $"Analysis failed: {ex.Message}";
_isMusicRunning = false; _isMusicRunning = false;
_btnMusic.Enabled = !_server.HasClient; RefreshButtonStates();
_btnTest.Enabled = !_server.HasClient && !IsTestRunning;
}); });
return; return;
} }
@@ -578,7 +600,7 @@ public class MainForm : Form
if (!IsDisposed) if (!IsDisposed)
{ {
_lblTrack.Text = ""; _lblTrack.Text = "";
_btnMusic.Enabled = !_server.HasClient; RefreshButtonStates();
} }
} }
} }