Compare commits
4 Commits
4ae5c397fd
...
33e289d596
| Author | SHA1 | Date | |
|---|---|---|---|
| 33e289d596 | |||
| 325022d27c | |||
| 84eba7d094 | |||
| 612385af7f |
+109
@@ -0,0 +1,109 @@
|
|||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
|
||||||
|
namespace Substation;
|
||||||
|
|
||||||
|
public class HeatMap : Panel
|
||||||
|
{
|
||||||
|
record Tick(byte[] Freq, byte[] Intensity);
|
||||||
|
|
||||||
|
readonly List<Tick> _history = new();
|
||||||
|
readonly int _maxTicks;
|
||||||
|
|
||||||
|
public HeatMap(int maxTicks = 60)
|
||||||
|
{
|
||||||
|
_maxTicks = maxTicks;
|
||||||
|
DoubleBuffered = true;
|
||||||
|
BackColor = Color.FromArgb(20, 20, 22);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddTick(byte[] freq, byte[] intensity, bool active)
|
||||||
|
{
|
||||||
|
if (_history.Count >= _maxTicks)
|
||||||
|
_history.RemoveAt(0);
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
_history.Add(new Tick(freq, intensity));
|
||||||
|
else
|
||||||
|
_history.Add(new Tick(Array.Empty<byte>(), Array.Empty<byte>()));
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPaint(e);
|
||||||
|
var g = e.Graphics;
|
||||||
|
g.SmoothingMode = SmoothingMode.None;
|
||||||
|
|
||||||
|
int w = Width;
|
||||||
|
int h = Height;
|
||||||
|
int colW = Math.Max(1, w / _maxTicks);
|
||||||
|
|
||||||
|
// Draw axis labels
|
||||||
|
using var font = new Font(FontFamily.GenericMonospace, 7);
|
||||||
|
using var textBrush = new SolidBrush(Color.FromArgb(100, 100, 100));
|
||||||
|
g.DrawString("100Hz", font, textBrush, 2, 2);
|
||||||
|
g.DrawString("1Hz", font, textBrush, 2, h - 14);
|
||||||
|
|
||||||
|
int plotX = 36;
|
||||||
|
int plotW = w - plotX - 4;
|
||||||
|
int plotH = h - 4;
|
||||||
|
colW = Math.Max(1, plotW / _maxTicks);
|
||||||
|
|
||||||
|
for (int i = 0; i < _history.Count; i++)
|
||||||
|
{
|
||||||
|
var tick = _history[i];
|
||||||
|
int xPos = plotX + i * colW;
|
||||||
|
|
||||||
|
if (tick.Freq.Length == 0)
|
||||||
|
{
|
||||||
|
// Inactive — dark cell
|
||||||
|
using var dark = new SolidBrush(Color.FromArgb(25, 25, 28));
|
||||||
|
g.FillRectangle(dark, xPos, 2, colW, plotH);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4 sub-ticks side by side within the column
|
||||||
|
int subW = Math.Max(1, colW / 4);
|
||||||
|
for (int s = 0; s < 4; s++)
|
||||||
|
{
|
||||||
|
int freq = tick.Freq[s]; // 10-240
|
||||||
|
int inten = tick.Intensity[s]; // 0-100
|
||||||
|
if (inten > 100) inten = 0; // 101 sentinel = off
|
||||||
|
|
||||||
|
// Map freq byte (10-240) to Y position (top=high freq, bottom=low freq)
|
||||||
|
float normFreq = (freq - 10f) / (240f - 10f);
|
||||||
|
int y = (int)(2 + plotH * (1f - normFreq));
|
||||||
|
if (y < 2) y = 2;
|
||||||
|
if (y > plotH) y = plotH;
|
||||||
|
|
||||||
|
var color = HeatColor(inten);
|
||||||
|
using var brush = new SolidBrush(color);
|
||||||
|
g.FillRectangle(brush, xPos + s * subW, y, subW, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color HeatColor(int intensity)
|
||||||
|
{
|
||||||
|
// 0=black, 30=blue, 60=green, 80=gold, 100=red
|
||||||
|
if (intensity <= 0) return Color.FromArgb(20, 20, 22);
|
||||||
|
if (intensity < 30)
|
||||||
|
{
|
||||||
|
float t = intensity / 30f;
|
||||||
|
return Color.FromArgb(0, (int)(50 * t), (int)(80 + 80 * t));
|
||||||
|
}
|
||||||
|
if (intensity < 60)
|
||||||
|
{
|
||||||
|
float t = (intensity - 30) / 30f;
|
||||||
|
return Color.FromArgb((int)(60 * t), (int)(130 + 80 * t), (int)(160 - 100 * t));
|
||||||
|
}
|
||||||
|
if (intensity < 80)
|
||||||
|
{
|
||||||
|
float t = (intensity - 60) / 20f;
|
||||||
|
return Color.FromArgb((int)(60 + 180 * t), 210, (int)(60 - 30 * t));
|
||||||
|
}
|
||||||
|
float t2 = (intensity - 80) / 20f;
|
||||||
|
return Color.FromArgb(255, (int)(240 - 140 * t2), (int)(30 - 10 * t2));
|
||||||
|
}
|
||||||
|
}
|
||||||
+121
-61
@@ -14,7 +14,6 @@ public class MainForm : Form
|
|||||||
readonly NotifyIcon _tray;
|
readonly NotifyIcon _tray;
|
||||||
readonly Label _lblBle;
|
readonly Label _lblBle;
|
||||||
readonly Label _lblWs;
|
readonly Label _lblWs;
|
||||||
readonly Label _lblStrength;
|
|
||||||
readonly Label _lblDeviceName;
|
readonly Label _lblDeviceName;
|
||||||
readonly TextBox _txtDeviceName;
|
readonly TextBox _txtDeviceName;
|
||||||
readonly Button _btnConnect;
|
readonly Button _btnConnect;
|
||||||
@@ -25,13 +24,20 @@ public class MainForm : Form
|
|||||||
|
|
||||||
bool _closingFromTray;
|
bool _closingFromTray;
|
||||||
|
|
||||||
readonly ProgressBar _gaugeA;
|
readonly HeatMap _heatA;
|
||||||
readonly ProgressBar _gaugeB;
|
readonly HeatMap _heatB;
|
||||||
readonly Label _lblGaugeA;
|
readonly ProgressBar _gaugeRecvA;
|
||||||
readonly Label _lblGaugeB;
|
readonly ProgressBar _gaugeRecvB;
|
||||||
readonly TrackBar _limitBar;
|
readonly Label _lblSendA;
|
||||||
readonly Label _lblLimit;
|
readonly Label _lblSendB;
|
||||||
readonly CheckBox _chkScale;
|
readonly Label _lblRecvA;
|
||||||
|
readonly Label _lblRecvB;
|
||||||
|
readonly TrackBar _limitBarA;
|
||||||
|
readonly TrackBar _limitBarB;
|
||||||
|
readonly Label _lblLimitA;
|
||||||
|
readonly Label _lblLimitB;
|
||||||
|
readonly CheckBox _chkScaleA;
|
||||||
|
readonly CheckBox _chkScaleB;
|
||||||
|
|
||||||
readonly Icon _iconNeutral;
|
readonly Icon _iconNeutral;
|
||||||
readonly Icon _iconActive;
|
readonly Icon _iconActive;
|
||||||
@@ -51,8 +57,8 @@ public class MainForm : Form
|
|||||||
_server = server;
|
_server = server;
|
||||||
_loopCts = new CancellationTokenSource();
|
_loopCts = new CancellationTokenSource();
|
||||||
|
|
||||||
Text = "Substation";
|
Text = $"Substation {typeof(MainForm).Assembly.GetName().Version}";
|
||||||
ClientSize = new Size(360, 340);
|
ClientSize = new Size(420, 410);
|
||||||
FormBorderStyle = FormBorderStyle.FixedSingle;
|
FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||||
MaximizeBox = false;
|
MaximizeBox = false;
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
@@ -62,7 +68,7 @@ public class MainForm : Form
|
|||||||
{
|
{
|
||||||
Text = "BLE: searching...",
|
Text = "BLE: searching...",
|
||||||
Location = new Point(16, 16),
|
Location = new Point(16, 16),
|
||||||
Size = new Size(328, 20),
|
Size = new Size(388, 20),
|
||||||
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,34 +76,27 @@ public class MainForm : Form
|
|||||||
{
|
{
|
||||||
Text = "WS: idle",
|
Text = "WS: idle",
|
||||||
Location = new Point(16, 40),
|
Location = new Point(16, 40),
|
||||||
Size = new Size(328, 20),
|
Size = new Size(388, 20),
|
||||||
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
};
|
};
|
||||||
|
|
||||||
_lblStrength = new Label
|
|
||||||
{
|
|
||||||
Text = "Strength: A=0 B=0",
|
|
||||||
Location = new Point(16, 64),
|
|
||||||
Size = new Size(328, 20)
|
|
||||||
};
|
|
||||||
|
|
||||||
_lblDeviceName = new Label
|
_lblDeviceName = new Label
|
||||||
{
|
{
|
||||||
Text = "Device:",
|
Text = "Device:",
|
||||||
Location = new Point(16, 90),
|
Location = new Point(16, 66),
|
||||||
Size = new Size(48, 20)
|
Size = new Size(48, 20)
|
||||||
};
|
};
|
||||||
_txtDeviceName = new TextBox
|
_txtDeviceName = new TextBox
|
||||||
{
|
{
|
||||||
Text = "47L121000",
|
Text = "47L121000",
|
||||||
Location = new Point(68, 88),
|
Location = new Point(68, 64),
|
||||||
Size = new Size(160, 20)
|
Size = new Size(160, 20)
|
||||||
};
|
};
|
||||||
|
|
||||||
_btnConnect = new Button
|
_btnConnect = new Button
|
||||||
{
|
{
|
||||||
Text = "Connect",
|
Text = "Connect",
|
||||||
Location = new Point(236, 88),
|
Location = new Point(296, 64),
|
||||||
Size = new Size(108, 24)
|
Size = new Size(108, 24)
|
||||||
};
|
};
|
||||||
_btnConnect.Click += OnConnect;
|
_btnConnect.Click += OnConnect;
|
||||||
@@ -105,7 +104,7 @@ public class MainForm : Form
|
|||||||
_btnTest = new Button
|
_btnTest = new Button
|
||||||
{
|
{
|
||||||
Text = "Test",
|
Text = "Test",
|
||||||
Location = new Point(16, 120),
|
Location = new Point(16, 96),
|
||||||
Size = new Size(100, 32)
|
Size = new Size(100, 32)
|
||||||
};
|
};
|
||||||
_btnTest.Click += OnTest;
|
_btnTest.Click += OnTest;
|
||||||
@@ -113,7 +112,7 @@ public class MainForm : Form
|
|||||||
_btnMusic = new Button
|
_btnMusic = new Button
|
||||||
{
|
{
|
||||||
Text = "Music",
|
Text = "Music",
|
||||||
Location = new Point(130, 120),
|
Location = new Point(130, 96),
|
||||||
Size = new Size(100, 32)
|
Size = new Size(100, 32)
|
||||||
};
|
};
|
||||||
_btnMusic.Click += OnMusic;
|
_btnMusic.Click += OnMusic;
|
||||||
@@ -121,7 +120,7 @@ public class MainForm : Form
|
|||||||
_btnStop = new Button
|
_btnStop = new Button
|
||||||
{
|
{
|
||||||
Text = "Stop All",
|
Text = "Stop All",
|
||||||
Location = new Point(244, 120),
|
Location = new Point(244, 96),
|
||||||
Size = new Size(100, 32)
|
Size = new Size(100, 32)
|
||||||
};
|
};
|
||||||
_btnStop.Click += OnStop;
|
_btnStop.Click += OnStop;
|
||||||
@@ -129,70 +128,120 @@ public class MainForm : Form
|
|||||||
_lblTrack = new Label
|
_lblTrack = new Label
|
||||||
{
|
{
|
||||||
Text = "",
|
Text = "",
|
||||||
Location = new Point(16, 158),
|
Location = new Point(16, 134),
|
||||||
Size = new Size(328, 16),
|
Size = new Size(388, 16),
|
||||||
ForeColor = Color.DimGray
|
ForeColor = Color.DimGray
|
||||||
};
|
};
|
||||||
|
|
||||||
_lblGaugeA = new Label
|
_lblSendA = new Label
|
||||||
{
|
{
|
||||||
Text = "A",
|
Text = "Send A",
|
||||||
Location = new Point(16, 180),
|
Location = new Point(16, 160),
|
||||||
Size = new Size(16, 20),
|
Size = new Size(48, 20),
|
||||||
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
};
|
};
|
||||||
_gaugeA = new ProgressBar
|
_heatA = new HeatMap(60)
|
||||||
{
|
{
|
||||||
Location = new Point(40, 180),
|
Location = new Point(72, 158),
|
||||||
Size = new Size(304, 20),
|
Size = new Size(332, 22)
|
||||||
|
};
|
||||||
|
_lblSendB = new Label
|
||||||
|
{
|
||||||
|
Text = "Send B",
|
||||||
|
Location = new Point(16, 188),
|
||||||
|
Size = new Size(48, 20),
|
||||||
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
_heatB = new HeatMap(60)
|
||||||
|
{
|
||||||
|
Location = new Point(72, 186),
|
||||||
|
Size = new Size(332, 22)
|
||||||
|
};
|
||||||
|
_lblRecvA = new Label
|
||||||
|
{
|
||||||
|
Text = "Recv A",
|
||||||
|
Location = new Point(16, 216),
|
||||||
|
Size = new Size(48, 20),
|
||||||
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
_gaugeRecvA = new ProgressBar
|
||||||
|
{
|
||||||
|
Location = new Point(72, 216),
|
||||||
|
Size = new Size(332, 20),
|
||||||
Minimum = 0,
|
Minimum = 0,
|
||||||
Maximum = 200,
|
Maximum = 200,
|
||||||
Style = ProgressBarStyle.Continuous
|
Style = ProgressBarStyle.Continuous
|
||||||
};
|
};
|
||||||
_lblGaugeB = new Label
|
_lblRecvB = new Label
|
||||||
{
|
{
|
||||||
Text = "B",
|
Text = "Recv B",
|
||||||
Location = new Point(16, 208),
|
Location = new Point(16, 242),
|
||||||
Size = new Size(16, 20),
|
Size = new Size(48, 20),
|
||||||
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
};
|
};
|
||||||
_gaugeB = new ProgressBar
|
_gaugeRecvB = new ProgressBar
|
||||||
{
|
{
|
||||||
Location = new Point(40, 208),
|
Location = new Point(72, 242),
|
||||||
Size = new Size(304, 20),
|
Size = new Size(332, 20),
|
||||||
Minimum = 0,
|
Minimum = 0,
|
||||||
Maximum = 200,
|
Maximum = 200,
|
||||||
Style = ProgressBarStyle.Continuous
|
Style = ProgressBarStyle.Continuous
|
||||||
};
|
};
|
||||||
|
|
||||||
_lblLimit = new Label
|
_lblLimitA = new Label
|
||||||
{
|
{
|
||||||
Text = "Limit: 30",
|
Text = "Lim A: 30",
|
||||||
Location = new Point(16, 248),
|
Location = new Point(16, 274),
|
||||||
Size = new Size(64, 20),
|
Size = new Size(56, 20),
|
||||||
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
};
|
};
|
||||||
_limitBar = new TrackBar
|
_limitBarA = new TrackBar
|
||||||
{
|
{
|
||||||
Location = new Point(80, 244),
|
Location = new Point(72, 270),
|
||||||
Size = new Size(180, 45),
|
Size = new Size(250, 45),
|
||||||
Minimum = 0,
|
Minimum = 0,
|
||||||
Maximum = 200,
|
Maximum = 200,
|
||||||
TickFrequency = 50,
|
TickFrequency = 50,
|
||||||
Value = 30
|
Value = 30
|
||||||
};
|
};
|
||||||
_limitBar.ValueChanged += OnLimitChanged;
|
_limitBarA.ValueChanged += OnLimitChanged;
|
||||||
_chkScale = new CheckBox
|
_chkScaleA = new CheckBox
|
||||||
{
|
{
|
||||||
Text = "Scale",
|
Text = "Scale",
|
||||||
Location = new Point(268, 248),
|
Location = new Point(328, 274),
|
||||||
Size = new Size(76, 24),
|
Size = new Size(76, 24),
|
||||||
Checked = false
|
Checked = false
|
||||||
};
|
};
|
||||||
_chkScale.CheckedChanged += OnLimitChanged;
|
_chkScaleA.CheckedChanged += OnLimitChanged;
|
||||||
|
|
||||||
|
_lblLimitB = new Label
|
||||||
|
{
|
||||||
|
Text = "Lim B: 30",
|
||||||
|
Location = new Point(16, 312),
|
||||||
|
Size = new Size(56, 20),
|
||||||
|
Font = new Font(Font.FontFamily, 9, FontStyle.Bold)
|
||||||
|
};
|
||||||
|
_limitBarB = new TrackBar
|
||||||
|
{
|
||||||
|
Location = new Point(72, 308),
|
||||||
|
Size = new Size(250, 45),
|
||||||
|
Minimum = 0,
|
||||||
|
Maximum = 200,
|
||||||
|
TickFrequency = 50,
|
||||||
|
Value = 30
|
||||||
|
};
|
||||||
|
_limitBarB.ValueChanged += OnLimitChanged;
|
||||||
|
_chkScaleB = new CheckBox
|
||||||
|
{
|
||||||
|
Text = "Scale",
|
||||||
|
Location = new Point(328, 312),
|
||||||
|
Size = new Size(76, 24),
|
||||||
|
Checked = false
|
||||||
|
};
|
||||||
|
_chkScaleB.CheckedChanged += OnLimitChanged;
|
||||||
OnLimitChanged(null, EventArgs.Empty);
|
OnLimitChanged(null, EventArgs.Empty);
|
||||||
|
|
||||||
Controls.AddRange(new Control[] { _lblBle, _lblWs, _lblStrength, _lblDeviceName, _txtDeviceName, _btnConnect, _btnTest, _btnMusic, _btnStop, _lblTrack, _lblGaugeA, _gaugeA, _lblGaugeB, _gaugeB, _lblLimit, _limitBar, _chkScale });
|
Controls.AddRange(new Control[] { _lblBle, _lblWs, _lblDeviceName, _txtDeviceName, _btnConnect, _btnTest, _btnMusic, _btnStop, _lblTrack, _lblSendA, _heatA, _lblSendB, _heatB, _lblRecvA, _gaugeRecvA, _lblRecvB, _gaugeRecvB, _lblLimitA, _limitBarA, _chkScaleA, _lblLimitB, _limitBarB, _chkScaleB });
|
||||||
|
|
||||||
// Tray icon — three cached variants: neutral=gray, active=gold, hot=red-orange
|
// Tray icon — three cached variants: neutral=gray, active=gold, hot=red-orange
|
||||||
_iconNeutral = CreateVoltageIcon(Color.Gray);
|
_iconNeutral = CreateVoltageIcon(Color.Gray);
|
||||||
@@ -242,9 +291,9 @@ public class MainForm : Form
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var (modeA, valA, modeB, valB, freqA, intA, freqB, intB) = _state.ConsumeTick();
|
||||||
if (_device.IsConnected)
|
if (_device.IsConnected)
|
||||||
{
|
{
|
||||||
var (modeA, valA, modeB, valB, freqA, intA, freqB, intB) = _state.ConsumeTick();
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -331,9 +380,16 @@ public class MainForm : Form
|
|||||||
_lblBle.Text = _device.IsConnected
|
_lblBle.Text = _device.IsConnected
|
||||||
? $"BLE: connected ({_device.DeviceName})"
|
? $"BLE: connected ({_device.DeviceName})"
|
||||||
: "BLE: disconnected";
|
: "BLE: disconnected";
|
||||||
_lblStrength.Text = $"Strength: A={_device.StrengthA} B={_device.StrengthB}";
|
_heatA.AddTick(
|
||||||
_gaugeA.Value = Math.Clamp(_device.StrengthA, 0, 200);
|
_state.LastFreqA ?? Array.Empty<byte>(),
|
||||||
_gaugeB.Value = Math.Clamp(_device.StrengthB, 0, 200);
|
_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;
|
_btnTest.Enabled = !_server.HasClient && !IsTestRunning;
|
||||||
_btnMusic.Enabled = !_server.HasClient && !_isMusicRunning;
|
_btnMusic.Enabled = !_server.HasClient && !_isMusicRunning;
|
||||||
_btnStop.Enabled = true;
|
_btnStop.Enabled = true;
|
||||||
@@ -416,10 +472,14 @@ public class MainForm : Form
|
|||||||
|
|
||||||
void OnLimitChanged(object? sender, EventArgs e)
|
void OnLimitChanged(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var max = _limitBar.Value;
|
var maxA = _limitBarA.Value;
|
||||||
var mode = _chkScale.Checked ? LimitMode.Scale : LimitMode.Clamp;
|
var maxB = _limitBarB.Value;
|
||||||
_state.SetLimit(max, mode);
|
var modeA = _chkScaleA.Checked ? LimitMode.Scale : LimitMode.Clamp;
|
||||||
_lblLimit.Text = $"Limit: {max}";
|
var modeB = _chkScaleB.Checked ? LimitMode.Scale : LimitMode.Clamp;
|
||||||
|
_state.SetLimitA(maxA, modeA);
|
||||||
|
_state.SetLimitB(maxB, modeB);
|
||||||
|
_lblLimitA.Text = $"Lim A: {maxA}";
|
||||||
|
_lblLimitB.Text = $"Lim B: {maxB}";
|
||||||
}
|
}
|
||||||
|
|
||||||
string _musicFilePath = "";
|
string _musicFilePath = "";
|
||||||
|
|||||||
@@ -16,17 +16,32 @@ public class State
|
|||||||
public readonly ConcurrentQueue<WaveFrame> StreamB = new();
|
public readonly ConcurrentQueue<WaveFrame> StreamB = new();
|
||||||
|
|
||||||
public int ActualA, ActualB;
|
public int ActualA, ActualB;
|
||||||
|
public int LastSentA, LastSentB;
|
||||||
|
public int LastIntensityA, LastIntensityB;
|
||||||
|
public byte[]? LastFreqA, LastIntA, LastFreqB, LastIntB;
|
||||||
|
public bool LastActiveA, LastActiveB;
|
||||||
|
|
||||||
public int MaxStrength = 200;
|
public int MaxA = 200;
|
||||||
public LimitMode LimitMode = LimitMode.Clamp;
|
public int MaxB = 200;
|
||||||
|
public LimitMode LimitModeA = LimitMode.Clamp;
|
||||||
|
public LimitMode LimitModeB = LimitMode.Clamp;
|
||||||
|
|
||||||
public void SetLimit(int max, LimitMode mode)
|
public void SetLimitA(int max, LimitMode mode)
|
||||||
{
|
{
|
||||||
lock (Lock)
|
lock (Lock)
|
||||||
{
|
{
|
||||||
MaxStrength = Math.Clamp(max, 0, 200);
|
MaxA = Math.Clamp(max, 0, 200);
|
||||||
LimitMode = mode;
|
LimitModeA = mode;
|
||||||
DirtyA = true;
|
DirtyA = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLimitB(int max, LimitMode mode)
|
||||||
|
{
|
||||||
|
lock (Lock)
|
||||||
|
{
|
||||||
|
MaxB = Math.Clamp(max, 0, 200);
|
||||||
|
LimitModeB = mode;
|
||||||
DirtyB = true;
|
DirtyB = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,20 +106,29 @@ public class State
|
|||||||
var modeA = DirtyA ? StrengthMode.Abs : StrengthMode.None;
|
var modeA = DirtyA ? StrengthMode.Abs : StrengthMode.None;
|
||||||
var modeB = DirtyB ? StrengthMode.Abs : StrengthMode.None;
|
var modeB = DirtyB ? StrengthMode.Abs : StrengthMode.None;
|
||||||
|
|
||||||
var limit = MaxStrength;
|
byte ApplyLimit(int desired, int max, LimitMode mode) =>
|
||||||
var limMode = LimitMode;
|
mode == LimitMode.Scale
|
||||||
byte ApplyLimit(int desired) =>
|
? (byte)(desired * max / 200)
|
||||||
limMode == LimitMode.Scale
|
: (byte)Math.Clamp(desired, 0, max);
|
||||||
? (byte)(desired * limit / 200)
|
var valA = ApplyLimit(DesiredA, MaxA, LimitModeA);
|
||||||
: (byte)Math.Clamp(desired, 0, limit);
|
var valB = ApplyLimit(DesiredB, MaxB, LimitModeB);
|
||||||
var valA = ApplyLimit(DesiredA);
|
LastSentA = valA;
|
||||||
var valB = ApplyLimit(DesiredB);
|
LastSentB = valB;
|
||||||
DirtyA = false;
|
DirtyA = false;
|
||||||
DirtyB = false;
|
DirtyB = false;
|
||||||
|
|
||||||
|
bool hasA = !StreamA.IsEmpty || (LoopFreqA != null && LoopIntA != null);
|
||||||
|
bool hasB = !StreamB.IsEmpty || (LoopFreqB != null && LoopIntB != null);
|
||||||
var (freqA, intA) = PopWave(StreamA, LoopFreqA, LoopIntA);
|
var (freqA, intA) = PopWave(StreamA, LoopFreqA, LoopIntA);
|
||||||
var (freqB, intB) = PopWave(StreamB, LoopFreqB, LoopIntB);
|
var (freqB, intB) = PopWave(StreamB, LoopFreqB, LoopIntB);
|
||||||
|
|
||||||
|
LastActiveA = hasA;
|
||||||
|
LastActiveB = hasB;
|
||||||
|
LastFreqA = freqA; LastIntA = intA;
|
||||||
|
LastFreqB = freqB; LastIntB = intB;
|
||||||
|
LastIntensityA = hasA ? (intA[0] + intA[1] + intA[2] + intA[3]) / 4 : 0;
|
||||||
|
LastIntensityB = hasB ? (intB[0] + intB[1] + intB[2] + intB[3]) / 4 : 0;
|
||||||
|
|
||||||
return (modeA, valA, modeB, valB, freqA, intA, freqB, intB);
|
return (modeA, valA, modeB, valB, freqA, intA, freqB, intB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<AssemblyName>Substation</AssemblyName>
|
<AssemblyName>Substation</AssemblyName>
|
||||||
<RootNamespace>Substation</RootNamespace>
|
<RootNamespace>Substation</RootNamespace>
|
||||||
|
<Version>0.1.6</Version>
|
||||||
|
<AssemblyVersion>0.1.6</AssemblyVersion>
|
||||||
|
<FileVersion>0.1.6</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user