using System.Text.Json.Serialization; namespace Substation; public static class Freq { public static byte Compress(int ms) { if (ms is >= 10 and <= 100) return (byte)ms; if (ms is > 100 and <= 600) return (byte)((ms - 100) / 5 + 100); if (ms is > 600 and <= 1000) return (byte)((ms - 600) / 10 + 200); return 10; } public static byte[] Compress4(int[] ms) { if (ms.Length != 4) throw new ArgumentException("freq must have exactly 4 values", nameof(ms)); return new byte[] { Compress(ms[0]), Compress(ms[1]), Compress(ms[2]), Compress(ms[3]) }; } } public static class Intensity { public static byte Clamp(int v) => (byte)Math.Clamp(v, 0, 100); public static byte[] Clamp4(int[] v) { if (v.Length != 4) throw new ArgumentException("intensity must have exactly 4 values", nameof(v)); return new byte[] { Clamp(v[0]), Clamp(v[1]), Clamp(v[2]), Clamp(v[3]) }; } } public enum StrengthMode : byte { None = 0b00, Add = 0b01, Sub = 0b10, Abs = 0b11 } public enum LimitMode { Clamp = 0, Scale = 1 } public static class B0 { public static byte PackModes(StrengthMode a, StrengthMode b) => (byte)(((int)a << 2) | (int)b); public static byte[] Build( byte seq, StrengthMode modeA, StrengthMode modeB, byte strengthA, byte strengthB, byte[] freqA, byte[] intA, byte[] freqB, byte[] intB) { if (freqA.Length != 4 || intA.Length != 4 || freqB.Length != 4 || intB.Length != 4) throw new ArgumentException("wave arrays must be 4 bytes each"); var f = new byte[20]; f[0] = 0xB0; f[1] = (byte)((seq << 4) | (PackModes(modeA, modeB) & 0x0F)); f[2] = strengthA; f[3] = strengthB; Buffer.BlockCopy(freqA, 0, f, 4, 4); Buffer.BlockCopy(intA, 0, f, 8, 4); Buffer.BlockCopy(freqB, 0, f, 12, 4); Buffer.BlockCopy(intB, 0, f, 16, 4); return f; } public static readonly byte[] ChannelOff = { 0, 0, 0, 0 }; public static readonly byte[] IntensityOff = { 0, 0, 0, 101 }; } public static class BF { public static byte[] Build( byte capA, byte capB, byte freqBalA, byte freqBalB, byte intBalA, byte intBalB) { return new byte[] { 0xBF, capA, capB, freqBalA, freqBalB, intBalA, intBalB }; } } public record WaveFrame(byte[] Freq, byte[] Intensity); public class Command { [JsonPropertyName("op")] public string Op { get; set; } = ""; [JsonPropertyName("channel")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Channel { get; set; } [JsonPropertyName("mode")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Mode { get; set; } [JsonPropertyName("value")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? Value { get; set; } [JsonPropertyName("freq")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int[]? Freq { get; set; } [JsonPropertyName("intensity")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int[]? Intensity { get; set; } [JsonPropertyName("frames")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public FrameDto[]? Frames { get; set; } [JsonPropertyName("softcapA")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? SoftCapA { get; set; } [JsonPropertyName("softcapB")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? SoftCapB { get; set; } [JsonPropertyName("freqBalA")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? FreqBalA { get; set; } [JsonPropertyName("freqBalB")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? FreqBalB { get; set; } [JsonPropertyName("intBalA")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? IntBalA { get; set; } [JsonPropertyName("intBalB")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public int? IntBalB { get; set; } } public class FrameDto { [JsonPropertyName("freq")] public int[]? Freq { get; set; } [JsonPropertyName("intensity")] public int[]? Intensity { get; set; } } public class OkResponse { [JsonPropertyName("ok")] public bool Ok => true; [JsonPropertyName("msg")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Msg { get; set; } } public class ErrResponse { [JsonPropertyName("ok")] public bool Ok => false; [JsonPropertyName("error")] public string Error { get; set; } = ""; } public class StatusResponse { [JsonPropertyName("ok")] public bool Ok => true; [JsonPropertyName("event")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Event { get; set; } [JsonPropertyName("connected")] public bool Connected { get; set; } [JsonPropertyName("strengthA")] public int StrengthA { get; set; } [JsonPropertyName("strengthB")] public int StrengthB { get; set; } }