using BmsMonitor.App.Can; using BmsMonitor.App.Protocol; namespace BmsMonitor.Tests; public sealed class BmsProtocolParserTests { private readonly BmsProtocolParser _parser = new(); [Fact] public void StatusFrame_DecodesValuesFaultsAndState() { var frame = Frame(BmsProtocolParser.StatusFrameId, 0x0F, 0xA0, 0x10, 0xD1, 80, 0x12, 0x04, 3); Assert.True(_parser.TryApply(frame, new BmsSnapshot(), out var result)); Assert.Equal(400.0, result.PackVoltage); Assert.Equal(-69.5, result.PackCurrent); Assert.Equal(100, result.Soc); Assert.Equal("高压", result.State); Assert.Contains("单体过压", result.Faults!); Assert.Contains("单体过温", result.Faults!); Assert.Contains("预充失败", result.Faults!); } [Fact] public void ExtremesFrame_DecodesBigEndianAndOffsets() { var frame = Frame(BmsProtocolParser.ExtremesFrameId, 0x10, 0x04, 0x0C, 0xE4, 63, 23, 0x00, 0x7B); Assert.True(_parser.TryApply(frame, new BmsSnapshot(), out var result)); Assert.Equal(4.1, result.MaximumCellVoltage); Assert.Equal(3.3, result.MinimumCellVoltage); Assert.Equal(23, result.MaximumTemperature); Assert.Equal(-17, result.MinimumTemperature); Assert.Equal(12.3, result.LowVoltageBattery); } [Fact] public void ActualStandardStatusFrame_DecodesUsingDocumentLayout() { var frame = new CanFrame(BmsProtocolParser.ActualStatusFrameId, false, new byte[] { 0x02, 0x21, 0x13, 0x88, 100, 0x48, 0x01, 5 }, DateTime.Now); Assert.True(_parser.TryApply(frame, new BmsSnapshot(), out var result)); Assert.Equal(54.5, result.PackVoltage); Assert.Equal(0, result.PackCurrent); Assert.Equal(80, result.Soc); Assert.Equal("故障", result.State); } [Fact] public void ActualCellFrames_DecodeSixteenBitValuesAndMissingChannels() { var frame = new CanFrame(0x150, false, new byte[] { 0x98, 0xF3, 0x98, 0xF1, 0xFF, 0xFE, 0x99, 0x13 }, DateTime.Now); Assert.True(_parser.TryApply(frame, new BmsSnapshot(), out var result)); Assert.Equal(3.9155, result.CellVoltages![0]); Assert.Equal(3.9153, result.CellVoltages[1]); Assert.Null(result.CellVoltages[2]); Assert.Equal(3.9187, result.CellVoltages[3]); Assert.Equal(3.9187, result.MaximumCellVoltage); Assert.Equal(3.9153, result.MinimumCellVoltage); } [Fact] public void TemperatureFrame_AddsOffsetsToThirdAndEighthInputs() { var frame = new CanFrame(BmsProtocolParser.TemperatureFrameId, false, new byte[] { 0x42, 0xFF, 0x43, 0x43, 0x42, 0x42, 0x43, 0x43 }, DateTime.Now); Assert.True(_parser.TryApply(frame, new BmsSnapshot(), out var result)); Assert.Equal(26, result.Temperatures![0]); Assert.Null(result.Temperatures[1]); Assert.Equal(27.3, result.Temperatures[8]); Assert.Equal(27.5, result.Temperatures[9]); Assert.Equal(27, result.MaximumTemperature); Assert.Equal(26, result.MinimumTemperature); } private static CanFrame Frame(uint id, params byte[] data) => new(id, true, data, DateTime.Now); }