diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDatagramTestsBase.cs b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDatagramTestsBase.cs
new file mode 100644
index 00000000..4acb78bc
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDatagramTestsBase.cs
@@ -0,0 +1,37 @@
+using BrickController2.DeviceManagement;
+using BrickController2.DeviceManagement.JieStar;
+using BrickController2.PlatformServices.BluetoothLE;
+using Moq;
+
+namespace BrickController2.Tests.DeviceManagement.JieStar;
+
+public abstract class JieStarDatagramTestsBase
+{
+ protected const byte AppIdentifier1 = 0x61; // This is the first byte of an randomly choosen AppIdentifier for UnitTesting
+ protected const byte AppIdentifier2 = 0x62; // This is the second byte of an randomly choosen AppIdentifier for UnitTesting
+
+ protected static readonly byte[] AppIdentifier = [AppIdentifier1, AppIdentifier2];
+
+ ///
+ /// This class is a test implementation of the IJieStarPlatformService interface that simulates the behavior of the TryGetRfPayload method for testing purposes.
+ /// It always returns true and sets the rfPayload to the rawData provided.
+ ///
+ protected class TestJieStarPlatformService : IJieStarPlatformService
+ {
+ public bool TryGetRfPayload(byte ctxValue2, byte[] rawData, out byte[] rfPayload)
+ {
+ rfPayload = rawData;
+ return true; // Simulate success
+ }
+ }
+
+ protected readonly Mock _bluetoothLEService = new(MockBehavior.Strict);
+ protected readonly Mock _manager = new(MockBehavior.Strict);
+ protected readonly TestJieStarPlatformService _jieStarPlatformService = new();
+ internal readonly Mock _deviceRepository = new(MockBehavior.Strict);
+
+ protected JieStarDatagramTestsBase()
+ {
+ _manager.Setup(x => x.GetAppId()).Returns(AppIdentifier);
+ }
+}
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDeviceManagerTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDeviceManagerTests.cs
index abc90ace..5ceee076 100644
--- a/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDeviceManagerTests.cs
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarDeviceManagerTests.cs
@@ -9,7 +9,7 @@ namespace BrickController2.Tests.DeviceManagement.JieStar;
public class JieStarDeviceManagerTests
{
- private readonly JieStarDeviceManager _manager;
+ private readonly IJieStarDeviceManager _manager;
private readonly Mock _preferencesService = new(MockBehavior.Strict);
public JieStarDeviceManagerTests()
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarSCM4DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarSCM4DatagramTests.cs
new file mode 100644
index 00000000..8e36c35f
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarSCM4DatagramTests.cs
@@ -0,0 +1,186 @@
+using BrickController2.DeviceManagement.JieStar;
+using FluentAssertions;
+using System;
+using Xunit;
+
+namespace BrickController2.Tests.DeviceManagement.JieStar;
+
+public sealed class JieStarSCM4DatagramTests : JieStarDatagramTestsBase
+{
+ private const byte PayloadIdentifierConnect1 = 0xa4;
+ private const byte PayloadIdentifierConnect2 = 0x5b;
+ private const byte PayloadIdentifierCommand1 = 0x40;
+ private const byte PayloadIdentifierCommand2 = 0xbf;
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM4.Device1)]
+ [InlineData(JieStarSCM4.Device2)]
+ [InlineData(JieStarSCM4.Device3)]
+ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(string deviceAddress)
+ {
+ JieStarSCM4 device = new JieStarSCM4("JieStarSCM4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierConnect1);
+ payload[7].Should().Be(PayloadIdentifierConnect2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM4.Device1)]
+ [InlineData(JieStarSCM4.Device2)]
+ [InlineData(JieStarSCM4.Device3)]
+ public void TryGetTelegram_ConnectDatagram_AppIdentifier(string deviceAddress)
+ {
+ JieStarSCM4 device = new JieStarSCM4("JieStarSCM4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the command datagram for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM4.Device1)]
+ [InlineData(JieStarSCM4.Device2)]
+ [InlineData(JieStarSCM4.Device3)]
+ public void TryGetTelegram_CommandDatagram_PayloadIdentifier(string deviceAddress)
+ {
+ JieStarSCM4 device = new JieStarSCM4("JieStarSCM4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierCommand1);
+ payload[7].Should().Be(PayloadIdentifierCommand2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the command datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM4.Device1)]
+ [InlineData(JieStarSCM4.Device2)]
+ [InlineData(JieStarSCM4.Device3)]
+ public void TryGetTelegram_CommandDatagram_AppIdentifier(string deviceAddress)
+ {
+ JieStarSCM4 device = new JieStarSCM4("JieStarSCM4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address.
+ ///
+ /// The address of the device to test.
+ /// The set values for each channel.
+ /// The expected payload for the command datagram.
+ [Theory]
+ [InlineData(JieStarSCM4.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xf0, 0x00, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 1 maximum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 0.0f, 1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x0f, 0x00, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 2 maximum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 0.0f, 0.0f, 1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0xf0, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 3 maximum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x0f, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 4 maximum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { -1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x70, 0x00, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 1 minimum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 0.0f, -1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x07, 0x00, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 2 minimum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 0.0f, 0.0f, -1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x70, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 3 minimum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 0.0f, 0.0f, 0.0f, -1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x07, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 4 minimum, others neutral
+ [InlineData(JieStarSCM4.Device1, new float[] { 9.0f, 9.0f, 9.0f, 9.0f, }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(JieStarSCM4.Device1, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x77, 0x77, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(JieStarSCM4.Device2, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(JieStarSCM4.Device2, new float[] { 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(JieStarSCM4.Device2, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x77, 0x77, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(JieStarSCM4.Device3, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(JieStarSCM4.Device3, new float[] { 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(JieStarSCM4.Device3, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x77, 0x77, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+ public void TryGetTelegram_CommandDatagram_Payload(string deviceAddress, float[] setValues, byte[] expectedPayload)
+ {
+ JieStarSCM4 device = new JieStarSCM4("JieStarSCM4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues.Length; i++)
+ {
+ device.SetOutput(i, setValues[i]);
+ }
+
+ // Get the command datagram payload
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload.Length; i++)
+ {
+ payload[i].Should().Be(expectedPayload[i]);
+ }
+ }
+
+ ///
+ /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM4.Device1)]
+ [InlineData(JieStarSCM4.Device2)]
+ [InlineData(JieStarSCM4.Device3)]
+ public void TryGetTelegram_CommandDatagram_SetIllegalChannel(string deviceAddress)
+ {
+ JieStarSCM4 device = new JieStarSCM4("JieStarSCM4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ Action action = () => device.SetOutput(device.NumberOfChannels, 0);
+
+ action.Should().Throw();
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for multiple devices, ensuring that each device's payload is independent of the others.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_InstanceInteraction()
+ {
+ float[] setValues_1 = [1.0f, 1.0f, 1.0f, 1.0f];
+ byte[] expectedPayload_1 = [PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x80, 0x80, PayloadIdentifierCommand2];
+
+ float[] setValues_2 = [0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_2 = [PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x80, 0x80, PayloadIdentifierCommand2];
+
+ float[] setValues_3 = [0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_3 = [PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x80, 0x80, PayloadIdentifierCommand2];
+
+ JieStarSCM4 device1 = new JieStarSCM4("JieStarSCM4", JieStarSCM4.Device1, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+ JieStarSCM4 device2 = new JieStarSCM4("JieStarSCM4", JieStarSCM4.Device2, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+ JieStarSCM4 device3 = new JieStarSCM4("JieStarSCM4", JieStarSCM4.Device3, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues_1.Length; i++)
+ {
+ device1.SetOutput(i, setValues_1[i]);
+ device2.SetOutput(i, setValues_2[i]);
+ device3.SetOutput(i, setValues_3[i]);
+ }
+
+ // Get the command datagram payload
+ device1.TryGetTelegram(false, out byte[] payload1).Should().BeTrue();
+ device2.TryGetTelegram(false, out byte[] payload2).Should().BeTrue();
+ device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload_1.Length; i++)
+ {
+ payload1[i].Should().Be(expectedPayload_1[i]);
+ payload2[i].Should().Be(expectedPayload_2[i]);
+ payload3[i].Should().Be(expectedPayload_3[i]);
+ }
+ }
+}
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarSCM8DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarSCM8DatagramTests.cs
new file mode 100644
index 00000000..aea33bc8
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/JieStar/JieStarSCM8DatagramTests.cs
@@ -0,0 +1,192 @@
+using BrickController2.DeviceManagement.JieStar;
+using FluentAssertions;
+using System;
+using Xunit;
+
+namespace BrickController2.Tests.DeviceManagement.JieStar;
+
+public sealed class JieStarSCM8DatagramTests : JieStarDatagramTestsBase
+{
+ private const byte PayloadIdentifierConnect1 = 0xa4;
+ private const byte PayloadIdentifierConnect2 = 0x5b;
+ private const byte PayloadIdentifierCommand1_1 = 0x41;
+ private const byte PayloadIdentifierCommand1_2 = 0xbf;
+ private const byte PayloadIdentifierCommand2_1 = 0x42;
+ private const byte PayloadIdentifierCommand2_2 = 0xbe;
+ private const byte PayloadIdentifierCommand3_1 = 0x43;
+ private const byte PayloadIdentifierCommand3_2 = 0xbd;
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM8.Device1)]
+ [InlineData(JieStarSCM8.Device2)]
+ [InlineData(JieStarSCM8.Device3)]
+ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(string deviceAddress)
+ {
+ JieStarSCM8 device = new JieStarSCM8("JieStarSCM8", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierConnect1);
+ payload[7].Should().Be(PayloadIdentifierConnect2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM8.Device1)]
+ [InlineData(JieStarSCM8.Device2)]
+ [InlineData(JieStarSCM8.Device3)]
+ public void TryGetTelegram_ConnectDatagram_AppIdentifier(string deviceAddress)
+ {
+ JieStarSCM8 device = new JieStarSCM8("JieStarSCM8", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the command datagram for each device address.
+ ///
+ /// The address of the device to test.
+ /// The expected first payload identifier.
+ /// The expected second payload identifier.
+ [Theory]
+ [InlineData(JieStarSCM8.Device1, PayloadIdentifierCommand1_1, PayloadIdentifierCommand1_2)]
+ [InlineData(JieStarSCM8.Device2, PayloadIdentifierCommand2_1, PayloadIdentifierCommand2_2)]
+ [InlineData(JieStarSCM8.Device3, PayloadIdentifierCommand3_1, PayloadIdentifierCommand3_2)]
+ public void TryGetTelegram_CommandDatagram_PayloadIdentifier(string deviceAddress, byte expectedPayloadIdentifier1, byte expectedPayloadIdentifier2)
+ {
+ JieStarSCM8 device = new JieStarSCM8("JieStarSCM8", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(expectedPayloadIdentifier1);
+ payload[7].Should().Be(expectedPayloadIdentifier2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the command datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM8.Device1)]
+ [InlineData(JieStarSCM8.Device2)]
+ [InlineData(JieStarSCM8.Device3)]
+ public void TryGetTelegram_CommandDatagram_AppIdentifier(string deviceAddress)
+ {
+ JieStarSCM8 device = new JieStarSCM8("JieStarSCM8", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address.
+ ///
+ /// The address of the device to test.
+ /// The set values for each channel.
+ /// The expected payload for the command datagram.
+ [Theory]
+ [InlineData(JieStarSCM8.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // all channels neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0xf0, 0x00, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 1 maximum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 0.0f, 1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x0f, 0x00, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 2 maximum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 0.0f, 0.0f, 1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x00, 0xf0, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 3 maximum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x00, 0x0f, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 4 maximum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { -1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x70, 0x00, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 1 minimum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 0.0f, -1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x07, 0x00, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 2 minimum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 0.0f, 0.0f, -1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x00, 0x70, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 3 minimum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 0.0f, 0.0f, 0.0f, -1.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x00, 0x07, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // channel 4 minimum, others neutral
+ [InlineData(JieStarSCM8.Device1, new float[] { 9.0f, 9.0f, 9.0f, 9.0f, }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(JieStarSCM8.Device1, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x77, 0x77, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(JieStarSCM8.Device2, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand2_2 })] // all channels neutral
+ [InlineData(JieStarSCM8.Device2, new float[] { 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x00, 0x00, PayloadIdentifierCommand2_2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(JieStarSCM8.Device2, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0x77, 0x77, 0x00, 0x00, PayloadIdentifierCommand2_2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(JieStarSCM8.Device3, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand3_2 })] // all channels neutral
+ [InlineData(JieStarSCM8.Device3, new float[] { 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x00, 0x00, PayloadIdentifierCommand3_2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(JieStarSCM8.Device3, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0x77, 0x77, 0x00, 0x00, PayloadIdentifierCommand3_2 })] // all channels below minimum, should be clamped to minimum
+ public void TryGetTelegram_CommandDatagram_Payload(string deviceAddress, float[] setValues, byte[] expectedPayload)
+ {
+ JieStarSCM8 device = new JieStarSCM8("JieStarSCM8", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues.Length; i++)
+ {
+ device.SetOutput(i, setValues[i]);
+ }
+
+ // Get the command datagram payload
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload.Length; i++)
+ {
+ payload[i].Should().Be(expectedPayload[i]);
+ }
+ }
+
+ ///
+ /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(JieStarSCM8.Device1)]
+ [InlineData(JieStarSCM8.Device2)]
+ [InlineData(JieStarSCM8.Device3)]
+ public void TryGetTelegram_CommandDatagram_SetIllegalChannel(string deviceAddress)
+ {
+ JieStarSCM8 device = new JieStarSCM8("JieStarSCM8", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ Action action = () => device.SetOutput(device.NumberOfChannels, 0);
+
+ action.Should().Throw();
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for multiple devices, ensuring that each device's payload is independent of the others.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_InstanceInteraction()
+ {
+ float[] setValues_1 = [1.0f, 1.0f, 1.0f, 1.0f];
+ byte[] expectedPayload_1 = [PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x00, 0x00, PayloadIdentifierCommand1_2];
+
+ float[] setValues_2 = [0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_2 = [PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand2_2];
+
+ float[] setValues_3 = [0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_3 = [PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand3_2];
+
+ JieStarSCM8 device1 = new JieStarSCM8("JieStarSCM8", JieStarSCM8.Device1, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+ JieStarSCM8 device2 = new JieStarSCM8("JieStarSCM8", JieStarSCM8.Device2, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+ JieStarSCM8 device3 = new JieStarSCM8("JieStarSCM8", JieStarSCM8.Device3, [], _deviceRepository.Object, _bluetoothLEService.Object, _jieStarPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues_1.Length; i++)
+ {
+ device1.SetOutput(i, setValues_1[i]);
+ device2.SetOutput(i, setValues_2[i]);
+ device3.SetOutput(i, setValues_3[i]);
+ }
+
+ // Get the command datagram payload
+ device1.TryGetTelegram(false, out byte[] payload1).Should().BeTrue();
+ device2.TryGetTelegram(false, out byte[] payload2).Should().BeTrue();
+ device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload_1.Length; i++)
+ {
+ payload1[i].Should().Be(expectedPayload_1[i]);
+ payload2[i].Should().Be(expectedPayload_2[i]);
+ payload3[i].Should().Be(expectedPayload_3[i]);
+ }
+ }
+}
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingDatagramTestsBase.cs b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingDatagramTestsBase.cs
new file mode 100644
index 00000000..2bbbecb8
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingDatagramTestsBase.cs
@@ -0,0 +1,37 @@
+using BrickController2.DeviceManagement;
+using BrickController2.DeviceManagement.MouldKing;
+using BrickController2.PlatformServices.BluetoothLE;
+using Moq;
+
+namespace BrickController2.Tests.DeviceManagement.MouldKing;
+
+public abstract class MouldKingDatagramTestsBase
+{
+ protected const byte AppIdentifier1 = 0x61; // This is the first byte of an randomly choosen AppIdentifier for UnitTesting
+ protected const byte AppIdentifier2 = 0x62; // This is the second byte of an randomly choosen AppIdentifier for UnitTesting
+
+ protected static readonly byte[] AppIdentifier = [AppIdentifier1, AppIdentifier2];
+
+ ///
+ /// This class is a test implementation of the IMKPlatformService interface that simulates the behavior of the TryGetRfPayload method for testing purposes.
+ /// It always returns true and sets the rfPayload to the rawData provided.
+ ///
+ protected class TestMKPlatformService : IMKPlatformService
+ {
+ public bool TryGetRfPayload(byte[] rawData, out byte[] rfPayload)
+ {
+ rfPayload = rawData;
+ return true; // Simulate success
+ }
+ }
+
+ protected readonly Mock _bluetoothLEService = new(MockBehavior.Strict);
+ protected readonly Mock _manager = new(MockBehavior.Strict);
+ protected readonly TestMKPlatformService _mkPlatformService = new();
+ internal readonly Mock _deviceRepository = new(MockBehavior.Strict);
+
+ protected MouldKingDatagramTestsBase()
+ {
+ _manager.Setup(x => x.GetAppId()).Returns(AppIdentifier);
+ }
+}
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK3_8DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK3_8DatagramTests.cs
new file mode 100644
index 00000000..d7be6656
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK3_8DatagramTests.cs
@@ -0,0 +1,119 @@
+using BrickController2.DeviceManagement.MouldKing;
+using FluentAssertions;
+using System;
+using Xunit;
+
+namespace BrickController2.Tests.DeviceManagement.MouldKing;
+
+public sealed class MouldKingMK3_8DatagramTests : MouldKingDatagramTestsBase
+{
+ private const byte PayloadIdentifierConnect1 = 0xb1;
+ private const byte PayloadIdentifierConnect2 = 0xc1;
+ private const byte PayloadIdentifierCommand1 = 0x81;
+ private const byte PayloadIdentifierCommand2 = 0xc2;
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address.
+ ///
+ [Fact]
+ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier()
+ {
+ MK3_8 device = new MK3_8("MK3_8", MK3_8.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierConnect1);
+ payload[7].Should().Be(PayloadIdentifierConnect2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Fact]
+ public void TryGetTelegram_ConnectDatagram_AppIdentifier()
+ {
+ MK3_8 device = new MK3_8("MK3_8", MK3_8.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(0x00); // This is an exception - the second byte of the AppIdentifier is used as setvalue for channel 5
+ }
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the command datagram for each device address.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_PayloadIdentifier()
+ {
+ MK3_8 device = new MK3_8("MK3_8", MK3_8.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierCommand1);
+ payload[9].Should().Be(PayloadIdentifierCommand2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the command datagram payload for each device address.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_AppIdentifier()
+ {
+ MK3_8 device = new MK3_8("MK3_8", MK3_8.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(0x00); // This is an exception - the second byte of the AppIdentifier is used as setvalue for channel 5
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address.
+ ///
+ /// The set values for each channel.
+ /// The expected payload for the command datagram.
+ [Theory]
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0xf9, 0x99, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 1 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x9f, 0x99, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 2 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x99, 0xf9, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 3 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x99, 0x9f, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 4 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x2, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 5 maximum, others neutral
+ [InlineData(new float[] { -1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x79, 0x99, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 1 minimum, others neutral
+ [InlineData(new float[] { 0.0f, -1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x97, 0x99, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 2 minimum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x99, 0x79, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 3 minimum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, -1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x0, 0x99, 0x97, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 4 minimum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, -1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // channel 5 minimum, others neutral
+ [InlineData(new float[] { 9.0f, 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, 0x2, 0xff, 0xff, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(new float[] { -9.0f, -9.0f, -9.0f, -9.0f, -9.0f }, new byte[]{ PayloadIdentifierCommand1, AppIdentifier1, 0x1, 0x77, 0x77, 0x99, 0x99, 0x99, 0x99, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+ public void TryGetTelegram_CommandDatagram_Payload(float[] setValues, byte[] expectedPayload)
+ {
+ MK3_8 device = new MK3_8("MK3_8", MK3_8.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues.Length; i++)
+ {
+ device.SetOutput(i, setValues[i]);
+ }
+
+ // Get the command datagram payload
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload.Length; i++)
+ {
+ payload[i].Should().Be(expectedPayload[i]);
+ }
+ }
+
+ ///
+ /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_SetIllegalChannel()
+ {
+ MK3_8 device = new MK3_8("MK3_8", MK3_8.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ Action action = () => device.SetOutput(device.NumberOfChannels, 0);
+
+ action.Should().Throw();
+ }
+}
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK4DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK4DatagramTests.cs
new file mode 100644
index 00000000..4990d730
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK4DatagramTests.cs
@@ -0,0 +1,188 @@
+using BrickController2.DeviceManagement.MouldKing;
+using FluentAssertions;
+using System;
+using Xunit;
+
+namespace BrickController2.Tests.DeviceManagement.MouldKing;
+
+public sealed class MouldKingMK4DatagramTests : MouldKingDatagramTestsBase
+{
+ private const byte PayloadIdentifierConnect1 = 0xad;
+ private const byte PayloadIdentifierConnect2 = 0x52;
+ private const byte PayloadIdentifierCommand1 = 0x7d;
+ private const byte PayloadIdentifierCommand2 = 0x82;
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK4.Device1)]
+ [InlineData(MK4.Device2)]
+ [InlineData(MK4.Device3)]
+ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(string deviceAddress)
+ {
+ MK4 device = new MK4("MK4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierConnect1);
+ payload[7].Should().Be(PayloadIdentifierConnect2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK4.Device1)]
+ [InlineData(MK4.Device2)]
+ [InlineData(MK4.Device3)]
+ public void TryGetTelegram_ConnectDatagram_AppIdentifier(string deviceAddress)
+ {
+ MK4 device = new MK4("MK4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the command datagram for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK4.Device1)]
+ [InlineData(MK4.Device2)]
+ [InlineData(MK4.Device3)]
+ public void TryGetTelegram_CommandDatagram_PayloadIdentifier(string deviceAddress)
+ {
+ MK4 device = new MK4("MK4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierCommand1);
+ payload[9].Should().Be(PayloadIdentifierCommand2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the command datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK4.Device1)]
+ [InlineData(MK4.Device2)]
+ [InlineData(MK4.Device3)]
+ public void TryGetTelegram_CommandDatagram_AppIdentifier(string deviceAddress)
+ {
+ MK4 device = new MK4("MK4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address.
+ ///
+ /// The address of the device to test.
+ /// The set values for each channel.
+ /// The expected payload for the command datagram.
+ [Theory]
+ [InlineData(MK4.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(MK4.Device1, new float[] { 1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xf8, 0x88, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 1 maximum, others neutral
+ [InlineData(MK4.Device1, new float[] { 0.0f, 1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x8f, 0x88, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 2 maximum, others neutral
+ [InlineData(MK4.Device1, new float[] { 0.0f, 0.0f, 1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0xf8, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 3 maximum, others neutral
+ [InlineData(MK4.Device1, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x8f, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 4 maximum, others neutral
+ [InlineData(MK4.Device1, new float[] { -1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 1 minimum, others neutral
+ [InlineData(MK4.Device1, new float[] { 0.0f, -1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 2 minimum, others neutral
+ [InlineData(MK4.Device1, new float[] { 0.0f, 0.0f, -1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x78, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 3 minimum, others neutral
+ [InlineData(MK4.Device1, new float[] { 0.0f, 0.0f, 0.0f, -1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x87, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // channel 4 minimum, others neutral
+ [InlineData(MK4.Device1, new float[] { 9.0f, 9.0f, 9.0f, 9.0f, }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(MK4.Device1, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(MK4.Device2, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(MK4.Device2, new float[] { 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x88, 0xff, 0xff, 0x88, 0x88, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(MK4.Device2, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x88, 0x77, 0x77, 0x88, 0x88, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(MK4.Device3, new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(MK4.Device3, new float[] { 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x88, 0x88, 0x88, 0xff, 0xff, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(MK4.Device3, new float[] { -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x88, 0x88, 0x88, 0x88, 0x77, 0x77, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+ public void TryGetTelegram_CommandDatagram_Payload(string deviceAddress, float[] setValues, byte[] expectedPayload)
+ {
+ MK4 device = new MK4("MK4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues.Length; i++)
+ {
+ device.SetOutput(i, setValues[i]);
+ }
+
+ // Get the command datagram payload
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload.Length; i++)
+ {
+ payload[i].Should().Be(expectedPayload[i]);
+ }
+ }
+
+ ///
+ /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK4.Device1)]
+ [InlineData(MK4.Device2)]
+ [InlineData(MK4.Device3)]
+ public void TryGetTelegram_CommandDatagram_SetIllegalChannel(string deviceAddress)
+ {
+ MK4 device = new MK4("MK4", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ Action action = () => device.SetOutput(device.NumberOfChannels, 0);
+
+ action.Should().Throw();
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for multiple devices, ensuring that each device's payload is independent of the others.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_InstanceInteraction()
+ {
+ // Attention! - the MK4 devices static base telegram is interacted by all instances!
+
+ float[] setValues_1 = [1.0f, 1.0f, 1.0f, 1.0f];
+ byte[] expectedPayload_1 = [PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2];
+
+ float[] setValues_2 = [0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_2 = [PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2];
+
+ float[] setValues_3 = [0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_3 = [PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0x88, 0x88, 0x88, 0x88, PayloadIdentifierCommand2];
+
+ MK4 device1 = new MK4("MK4", MK4.Device1, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+ MK4 device2 = new MK4("MK4", MK4.Device2, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+ MK4 device3 = new MK4("MK4", MK4.Device3, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues_1.Length; i++)
+ {
+ device1.SetOutput(i, setValues_1[i]);
+ device2.SetOutput(i, setValues_2[i]);
+ device3.SetOutput(i, setValues_3[i]);
+ }
+
+ // Get the command datagram payload
+ device1.TryGetTelegram(false, out byte[] payload1).Should().BeTrue();
+ device2.TryGetTelegram(false, out byte[] payload2).Should().BeTrue();
+ device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload_1.Length; i++)
+ {
+ payload1[i].Should().Be(expectedPayload_1[i]);
+ payload2[i].Should().Be(expectedPayload_2[i]);
+ payload3[i].Should().Be(expectedPayload_3[i]);
+ }
+ }
+}
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK5DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK5DatagramTests.cs
new file mode 100644
index 00000000..105dce4a
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK5DatagramTests.cs
@@ -0,0 +1,118 @@
+using BrickController2.DeviceManagement.MouldKing;
+using FluentAssertions;
+using System;
+using Xunit;
+
+namespace BrickController2.Tests.DeviceManagement.MouldKing;
+
+public sealed class MouldKingMK5DatagramTests : MouldKingDatagramTestsBase
+{
+ private const byte PayloadIdentifierConnect1 = 0xad;
+ private const byte PayloadIdentifierConnect2 = 0x52;
+ private const byte PayloadIdentifierCommand1 = 0x7d;
+ private const byte PayloadIdentifierCommand2 = 0x82;
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address.
+ ///
+ [Fact]
+ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier()
+ {
+ MK5 device = new MK5("MK5", MK5.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierConnect1);
+ payload[7].Should().Be(PayloadIdentifierConnect2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address.
+ ///
+ [Fact]
+ public void TryGetTelegram_ConnectDatagram_AppIdentifier()
+ {
+ MK5 device = new MK5("MK5", MK5.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the command datagram for each device address.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_PayloadIdentifier()
+ {
+ MK5 device = new MK5("MK5", MK5.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierCommand1);
+ payload[9].Should().Be(PayloadIdentifierCommand2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the command datagram payload for each device address.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_AppIdentifier()
+ {
+ MK5 device = new MK5("MK5", MK5.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address.
+ ///
+ /// The set values for each channel.
+ /// The expected payload for the command datagram.
+ [Theory]
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels neutral
+ [InlineData(new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xf0, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 1 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x07, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 2 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0xf0, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 3 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x0f, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 4 maximum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x02, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 5 maximum, others neutral
+ [InlineData(new float[] { -1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x70, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 1 minimum, others neutral
+ [InlineData(new float[] { 0.0f, -1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x0f, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 2 minimum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0xf0, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 3 minimum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, -1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x00, 0x07, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 4 minimum, others neutral
+ [InlineData(new float[] { 0.0f, 0.0f, 0.0f, 0.0f, -1.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x02, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // channel 5 minimum, others neutral
+ [InlineData(new float[] { 9.0f, 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0xf7, 0xff, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(new float[] { -9.0f, -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1, AppIdentifier1, AppIdentifier2, 0x7f, 0xf7, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2 })] // all channels below minimum, should be clamped to minimum
+ public void TryGetTelegram_CommandDatagram_Payload(float[] setValues, byte[] expectedPayload)
+ {
+ MK5 device = new MK5("MK5", MK5.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues.Length; i++)
+ {
+ device.SetOutput(i, setValues[i]);
+ }
+
+ // Get the command datagram payload
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload.Length; i++)
+ {
+ payload[i].Should().Be(expectedPayload[i]);
+ }
+ }
+
+ ///
+ /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_SetIllegalChannel()
+ {
+ MK5 device = new MK5("MK5", MK5.Device, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ Action action = () => device.SetOutput(device.NumberOfChannels, 0);
+
+ action.Should().Throw();
+ }
+}
diff --git a/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK6DatagramTests.cs b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK6DatagramTests.cs
new file mode 100644
index 00000000..5d0bbcd5
--- /dev/null
+++ b/BrickController2/BrickController2.Tests/DeviceManagement/MouldKing/MouldKingMK6DatagramTests.cs
@@ -0,0 +1,197 @@
+using BrickController2.DeviceManagement.JieStar;
+using BrickController2.DeviceManagement.MouldKing;
+using FluentAssertions;
+using System;
+using Xunit;
+
+namespace BrickController2.Tests.DeviceManagement.MouldKing;
+
+public sealed class MouldKingMK6DatagramTests : MouldKingDatagramTestsBase
+{
+ private const byte PayloadIdentifierConnect1 = 0x6d;
+ private const byte PayloadIdentifierConnect2 = 0x92;
+ private const byte PayloadIdentifierCommand1_1 = 0x61;
+ private const byte PayloadIdentifierCommand1_2 = 0x9e;
+ private const byte PayloadIdentifierCommand2_1 = 0x62;
+ private const byte PayloadIdentifierCommand2_2 = 0x9d;
+ private const byte PayloadIdentifierCommand3_1 = 0x63;
+ private const byte PayloadIdentifierCommand3_2 = 0x9c;
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the connect datagram for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK6.Device1)]
+ [InlineData(MK6.Device2)]
+ [InlineData(MK6.Device3)]
+ public void TryGetTelegram_ConnectDatagram_PayloadIdentifier(string deviceAddress)
+ {
+ MK6 device = new MK6("MK6", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(PayloadIdentifierConnect1);
+ payload[7].Should().Be(PayloadIdentifierConnect2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the connect datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK6.Device1)]
+ [InlineData(MK6.Device2)]
+ [InlineData(MK6.Device3)]
+ public void TryGetTelegram_ConnectDatagram_AppIdentifier(string deviceAddress)
+ {
+ MK6 device = new MK6("MK6", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(true, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the payload identifiers are correctly set in the command datagram for each device address.
+ ///
+ /// The address of the device to test.
+ /// The expected first payload identifier.
+ /// The expected second payload identifier.
+ [Theory]
+ [InlineData(MK6.Device1, PayloadIdentifierCommand1_1, PayloadIdentifierCommand1_2)]
+ [InlineData(MK6.Device2, PayloadIdentifierCommand2_1, PayloadIdentifierCommand2_2)]
+ [InlineData(MK6.Device3, PayloadIdentifierCommand3_1, PayloadIdentifierCommand3_2)]
+ public void TryGetTelegram_CommandDatagram_PayloadIdentifier(string deviceAddress, byte expectedPayloadIdentifier1, byte expectedPayloadIdentifier2)
+ {
+ MK6 device = new MK6("MK6", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[0].Should().Be(expectedPayloadIdentifier1);
+ payload[9].Should().Be(expectedPayloadIdentifier2);
+ }
+
+ ///
+ /// This test checks that the AppIdentifier is correctly included in the command datagram payload for each device address.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK6.Device1)]
+ [InlineData(MK6.Device2)]
+ [InlineData(MK6.Device3)]
+ public void TryGetTelegram_CommandDatagram_AppIdentifier(string deviceAddress)
+ {
+ MK6 device = new MK6("MK6", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+ payload[1].Should().Be(AppIdentifier1);
+ payload[2].Should().Be(AppIdentifier2);
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for each device address.
+ ///
+ /// The address of the device to test.
+ /// The set values for each channel.
+ /// The expected payload for the command datagram.
+ [Theory]
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // all channels neutral
+ [InlineData(MK6.Device1, new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 1 maximum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0xff, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 2 maximum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 3 maximum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 4 maximum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0xff, 0x80, PayloadIdentifierCommand1_2 })] // channel 5 maximum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff, PayloadIdentifierCommand1_2 })] // channel 6 maximum, others neutral
+ [InlineData(MK6.Device1, new float[] { -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 1 minimum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 2 minimum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 3 minimum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, PayloadIdentifierCommand1_2 })] // channel 4 minimum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, PayloadIdentifierCommand1_2 })] // channel 5 minimum, others neutral
+ [InlineData(MK6.Device1, new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, PayloadIdentifierCommand1_2 })] // channel 6 minimum, others neutral
+ [InlineData(MK6.Device1, new float[] { 9.0f, 9.0f, 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, PayloadIdentifierCommand1_2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(MK6.Device1, new float[] { -9.0f, -9.0f, -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand1_2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(MK6.Device2, new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2_2 })] // all channels neutral
+ [InlineData(MK6.Device2, new float[] { 9.0f, 9.0f, 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, PayloadIdentifierCommand2_2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(MK6.Device2, new float[] { -9.0f, -9.0f, -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand2_2 })] // all channels below minimum, should be clamped to minimum
+
+ [InlineData(MK6.Device3, new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }, new byte[] { PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand3_2 })] // all channels neutral
+ [InlineData(MK6.Device3, new float[] { 9.0f, 9.0f, 9.0f, 9.0f, 9.0f, 9.0f }, new byte[] { PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, PayloadIdentifierCommand3_2 })] // all channels above maximum, should be clamped to maximum
+ [InlineData(MK6.Device3, new float[] { -9.0f, -9.0f, -9.0f, -9.0f, -9.0f, -9.0f }, new byte[] { PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, PayloadIdentifierCommand3_2 })] // all channels below minimum, should be clamped to minimum
+ public void TryGetTelegram_CommandDatagram_Payload(string deviceAddress, float[] setValues, byte[] expectedPayload)
+ {
+ MK6 device = new MK6("MK6", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues.Length; i++)
+ {
+ device.SetOutput(i, setValues[i]);
+ }
+
+ // Get the command datagram payload
+ device.TryGetTelegram(false, out byte[] payload).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload.Length; i++)
+ {
+ payload[i].Should().Be(expectedPayload[i]);
+ }
+ }
+
+ ///
+ /// Tests that setting an illegal channel index throws an ArgumentOutOfRangeException.
+ ///
+ /// The address of the device to test.
+ [Theory]
+ [InlineData(MK6.Device1)]
+ [InlineData(MK6.Device2)]
+ [InlineData(MK6.Device3)]
+ public void TryGetTelegram_CommandDatagram_SetIllegalChannel(string deviceAddress)
+ {
+ MK6 device = new MK6("MK6", deviceAddress, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ Action action = () => device.SetOutput(device.NumberOfChannels, 0);
+
+ action.Should().Throw();
+ }
+
+ ///
+ /// This test checks that the command datagram payload is correctly constructed based on the set output values for multiple devices, ensuring that each device's payload is independent of the others.
+ ///
+ [Fact]
+ public void TryGetTelegram_CommandDatagram_InstanceInteraction()
+ {
+ float[] setValues_1 = [1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f];
+ byte[] expectedPayload_1 = [PayloadIdentifierCommand1_1, AppIdentifier1, AppIdentifier2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, PayloadIdentifierCommand1_2];
+
+ float[] setValues_2 = [0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_2 = [PayloadIdentifierCommand2_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand2_2];
+
+ float[] setValues_3 = [0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f];
+ byte[] expectedPayload_3 = [PayloadIdentifierCommand3_1, AppIdentifier1, AppIdentifier2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, PayloadIdentifierCommand3_2];
+
+ MK6 device1 = new MK6("MK6", MK6.Device1, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+ MK6 device2 = new MK6("MK6", MK6.Device2, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+ MK6 device3 = new MK6("MK6", MK6.Device3, [], _deviceRepository.Object, _bluetoothLEService.Object, _mkPlatformService, _manager.Object);
+
+ // Set the output values for the device
+ for (int i = 0; i < setValues_1.Length; i++)
+ {
+ device1.SetOutput(i, setValues_1[i]);
+ device2.SetOutput(i, setValues_2[i]);
+ device3.SetOutput(i, setValues_3[i]);
+ }
+
+ // Get the command datagram payload
+ device1.TryGetTelegram(false, out byte[] payload1).Should().BeTrue();
+ device2.TryGetTelegram(false, out byte[] payload2).Should().BeTrue();
+ device3.TryGetTelegram(false, out byte[] payload3).Should().BeTrue();
+
+ // Check that the payload matches the expected values
+ for (int i = 0; i < expectedPayload_1.Length; i++)
+ {
+ payload1[i].Should().Be(expectedPayload_1[i]);
+ payload2[i].Should().Be(expectedPayload_2[i]);
+ payload3[i].Should().Be(expectedPayload_3[i]);
+ }
+ }
+}
diff --git a/BrickController2/BrickController2/DeviceManagement/JieStar/IJieStarDeviceManager.cs b/BrickController2/BrickController2/DeviceManagement/JieStar/IJieStarDeviceManager.cs
new file mode 100644
index 00000000..5068e256
--- /dev/null
+++ b/BrickController2/BrickController2/DeviceManagement/JieStar/IJieStarDeviceManager.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace BrickController2.DeviceManagement.JieStar;
+
+///
+/// Interface for JieStarDeviceManager.
+///
+public interface IJieStarDeviceManager
+{
+ ReadOnlyMemory GetAppId();
+}
diff --git a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStar.cs b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStar.cs
index e1722700..fc35b371 100644
--- a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStar.cs
+++ b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStar.cs
@@ -15,6 +15,7 @@ protected override void Register(VendorBuilder builder)
{
// device manager
builder.ContainerBuilder.RegisterType()
+ .As()
.SingleInstance();
// manually added devices
diff --git a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarBase.cs b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarBase.cs
index f9b359b7..40efa73f 100644
--- a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarBase.cs
+++ b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarBase.cs
@@ -39,7 +39,7 @@ internal abstract class JieStarBase : BluetoothAdvertisingDevice
///
protected readonly float[] _storedValues;
- protected JieStarBase(string name, string address, byte[] deviceData, IDeviceRepository deviceRepository, IBluetoothLEService bleService, IJieStarPlatformService jieStarPlatformService, JieStarDeviceManager jieStarDeviceManager, byte[] telegram_Connect, byte[] telegram_Base, byte ctxValue2)
+ protected JieStarBase(string name, string address, byte[] deviceData, IDeviceRepository deviceRepository, IBluetoothLEService bleService, IJieStarPlatformService jieStarPlatformService, IJieStarDeviceManager jieStarDeviceManager, byte[] telegram_Connect, byte[] telegram_Base, byte ctxValue2)
: base(name, address, deviceData, deviceRepository, bleService)
{
_telegram_Connect = telegram_Connect;
@@ -55,6 +55,10 @@ protected JieStarBase(string name, string address, byte[] deviceData, IDeviceRep
_telegram_Base[1] = appId[0];
_telegram_Base[2] = appId[1];
+
+
+ // initialize all channels in _telegram_Base and _storedValues to zero value
+ InitDevice();
}
///
@@ -227,7 +231,7 @@ protected bool SetChannelOutput(int channelNo, float value)
/// When this method returns, contains the RF payload as a byte array if the operation succeeds; otherwise, .
/// if the RF payload was successfully retrieved; otherwise, .
- protected bool TryGetTelegram(bool getConnectTelegram, out byte[] payload)
+ protected internal bool TryGetTelegram(bool getConnectTelegram, out byte[] payload)
{
if (getConnectTelegram)
{
diff --git a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarDeviceManager.cs b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarDeviceManager.cs
index 26ce1701..95d11559 100644
--- a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarDeviceManager.cs
+++ b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarDeviceManager.cs
@@ -6,7 +6,7 @@ namespace BrickController2.DeviceManagement.JieStar;
///
/// Manager for JIESTAR devices
///
-public class JieStarDeviceManager
+public class JieStarDeviceManager : IJieStarDeviceManager
{
private const int AppIdentifierLength = 2; // JIESTAR protocol defines 2 bytes for the app identifier
diff --git a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM4.cs b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM4.cs
index 7727a37b..e93c0bc7 100644
--- a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM4.cs
+++ b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM4.cs
@@ -20,17 +20,27 @@ internal class JieStarSCM4 : JieStarBase, IDeviceType
private static readonly byte[] Telegram_Connect_Device = [0xa4, 0x1d, 0x74, 0x80, 0x80, 0x80, 0x80, 0x5b];
///
- /// Base Telegram for SCM4 devices
+ /// Base Telegram for SCM4 device 1
///
- private static readonly byte[] Telegram_Base_Device = [0x40, 0x1d, 0x74, 0x80, 0x80, 0x80, 0x80, 0xbf];
+ private static readonly byte[] Telegram_Base_Device_1 = [0x40, 0x1d, 0x74, 0x80, 0x80, 0x80, 0x80, 0xbf];
+
+ ///
+ /// Base Telegram for SCM4 device 2
+ ///
+ private static readonly byte[] Telegram_Base_Device_2 = [0x40, 0x1d, 0x74, 0x80, 0x80, 0x80, 0x80, 0xbf];
+
+ ///
+ /// Base Telegram for SCM4 device 3
+ ///
+ private static readonly byte[] Telegram_Base_Device_3 = [0x40, 0x1d, 0x74, 0x80, 0x80, 0x80, 0x80, 0xbf];
///
/// after this timespan and all channel's values equal to zero the connect telegram is sent
///
private static readonly TimeSpan ReconnectTimeSpan = TimeSpan.FromSeconds(3);
- public JieStarSCM4(string name, string address, byte[] deviceData, IDeviceRepository deviceRepository, IBluetoothLEService bleService, IJieStarPlatformService jieStarPlatformService, JieStarDeviceManager jieStarDeviceManager)
- : base(name, address, deviceData, deviceRepository, bleService, jieStarPlatformService, jieStarDeviceManager, Telegram_Connect_Device, Telegram_Base_Device, GetCTXValue2(address))
+ public JieStarSCM4(string name, string address, byte[] deviceData, IDeviceRepository deviceRepository, IBluetoothLEService bleService, IJieStarPlatformService jieStarPlatformService, IJieStarDeviceManager jieStarDeviceManager)
+ : base(name, address, deviceData, deviceRepository, bleService, jieStarPlatformService, jieStarDeviceManager, Telegram_Connect_Device, GetTelegramBase(address), GetCTXValue2(address))
{
}
@@ -81,6 +91,22 @@ protected override BluetoothAdvertisingDeviceHandler GetBluetoothAdvertisingDevi
///
/// address
/// reference to Base-Telegram
+ private static byte[] GetTelegramBase(string address)
+ {
+ return address switch
+ {
+ JieStarSCM4.Device1 => Telegram_Base_Device_1,
+ JieStarSCM4.Device2 => Telegram_Base_Device_2,
+ JieStarSCM4.Device3 => Telegram_Base_Device_3,
+ _ => throw new ArgumentException("Illegal Argument", nameof(address))
+ };
+ }
+
+ ///
+ /// Get CTXValue2 for the given address
+ ///
+ /// address
+ /// CTXValue2
private static byte GetCTXValue2(string address)
{
return address switch
diff --git a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM8.cs b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM8.cs
index 9b0fe6ac..8a71cbca 100644
--- a/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM8.cs
+++ b/BrickController2/BrickController2/DeviceManagement/JieStar/JieStarSCM8.cs
@@ -39,7 +39,7 @@ internal class JieStarSCM8 : JieStarBase, IDeviceType
///
private static readonly TimeSpan ReconnectTimeSpan = TimeSpan.FromSeconds(3);
- public JieStarSCM8(string name, string address, byte[] deviceData, IDeviceRepository deviceRepository, IBluetoothLEService bleService, IJieStarPlatformService jieStarPlatformService, JieStarDeviceManager jieStarDeviceManager)
+ public JieStarSCM8(string name, string address, byte[] deviceData, IDeviceRepository deviceRepository, IBluetoothLEService bleService, IJieStarPlatformService jieStarPlatformService, IJieStarDeviceManager jieStarDeviceManager)
: base(name, address, deviceData, deviceRepository, bleService, jieStarPlatformService, jieStarDeviceManager, JieStarSCM8.Telegram_Connect, GetTelegramBase(address), JieStarProtocol.CTXValue2)
{
}
diff --git a/BrickController2/BrickController2/DeviceManagement/MouldKing/MK3_8.cs b/BrickController2/BrickController2/DeviceManagement/MouldKing/MK3_8.cs
index cdd5dc72..2354bd4e 100644
--- a/BrickController2/BrickController2/DeviceManagement/MouldKing/MK3_8.cs
+++ b/BrickController2/BrickController2/DeviceManagement/MouldKing/MK3_8.cs
@@ -36,6 +36,9 @@ internal class MK3_8 : MKBaseNibble, IDeviceType
public MK3_8(string name, string address, byte[] deviceData, IDeviceRepository deviceRepository, IBluetoothLEService bleService, IMKPlatformService mkPlatformService, IMouldKingDeviceManager mkDeviceManager)
: base(name, address, deviceData, deviceRepository, bleService, mkPlatformService, mkDeviceManager, 0, Telegram_Connect, Telegram_Base)
{
+ // This is an exception - the second byte of the AppIdentifier is used as setvalue for channel 5
+ _telegram_Connect[2] = 0x00;
+ _telegram_Base[2] = 0x00;
}
public override DeviceType DeviceType => Type;
diff --git a/BrickController2/BrickController2/DeviceManagement/MouldKing/MK4.cs b/BrickController2/BrickController2/DeviceManagement/MouldKing/MK4.cs
index fd062dbd..d7597529 100644
--- a/BrickController2/BrickController2/DeviceManagement/MouldKing/MK4.cs
+++ b/BrickController2/BrickController2/DeviceManagement/MouldKing/MK4.cs
@@ -17,7 +17,7 @@ internal class MK4 : MKBaseNibble, IDeviceType
/// Telegram to connect to the MK4.0 device(s)
/// This telegram is sent on init and on reconnect conditions matching
///
- private static readonly byte[] Telegram_Connect = new byte[] { 0xAD, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x4F, 0x52 };
+ private static readonly byte[] Telegram_Connect = [0xAD, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x4F, 0x52];
///
/// Base Telegram for MK4.0
@@ -26,7 +26,7 @@ internal class MK4 : MKBaseNibble, IDeviceType
/// * channels 0..3 for Device2 start at offset 5 and are analog channels
/// * channels 0..3 for Device3 start at offset 7 and are analog channels
///
- private static readonly byte[] Telegram_Base = new byte[] { 0x7D, 0x7B, 0xA7, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x82 };
+ private static readonly byte[] Telegram_Base = [0x7D, 0x7B, 0xA7, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x82];
///
/// after this timespan and all channel's values equal to zero the connect telegram is sent
@@ -62,6 +62,22 @@ public MK4(string name, string address, byte[] deviceData, IDeviceRepository dev
///
protected override ushort ManufacturerId => MKProtocol.ManufacturerID;
+ ///
+ /// This method sets the device to initial state before advertising starts
+ /// All channels are initialized with zeroValue.
+ ///
+ protected override void InitDevice()
+ {
+ base.InitDevice();
+
+ // Reset the base telegram to its initial state for all channels and all instances to the default value of 0x88.
+ // Because the 3 instances of the MK4.0 device are using the same static Telegram_Base, we need to reset the values for all channels of all instances.
+ for (int index = 3; index <= 8; index++)
+ {
+ Telegram_Base[index] = 0x88;
+ }
+ }
+
///
/// Get or create BluetoothAdvertisingDeviceHandler
///
diff --git a/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseByte.cs b/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseByte.cs
index 2726e213..221879a8 100644
--- a/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseByte.cs
+++ b/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseByte.cs
@@ -45,6 +45,9 @@ protected MKBaseByte(string name, string address, byte[] deviceData, IDeviceRepo
_telegram_Base[1] = appId[0];
_telegram_Base[2] = appId[1];
+
+ // initialize all channels in _telegram_Base and _storedValues to zero value
+ InitDevice();
}
///
@@ -120,7 +123,7 @@ public override void SetOutput(int channelNo, float value)
/// When this method returns, contains the RF payload as a byte array if the operation succeeds; otherwise, .
/// if the RF payload was successfully retrieved; otherwise, .
- protected bool TryGetTelegram(bool getConnectTelegram, out byte[] payload)
+ protected internal bool TryGetTelegram(bool getConnectTelegram, out byte[] payload)
{
if (getConnectTelegram)
{
diff --git a/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseNibble.cs b/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseNibble.cs
index 2505c8f3..eed6f755 100644
--- a/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseNibble.cs
+++ b/BrickController2/BrickController2/DeviceManagement/MouldKing/MKBaseNibble.cs
@@ -62,6 +62,9 @@ protected MKBaseNibble(string name, string address, byte[] deviceData, IDeviceRe
_telegram_Base[2] = appId[1];
_storedValues = new float[NumberOfChannels]; // initialize output values for all channels
+
+ // initialize all channels in _telegram_Base and _storedValues to zero value
+ InitDevice();
}
///
@@ -206,7 +209,7 @@ protected bool SetChannelOutput(int channelNo, float value)
/// When this method returns, contains the RF payload as a byte array if the operation succeeds; otherwise, .
/// if the RF payload was successfully retrieved; otherwise, .
- protected bool TryGetTelegram(bool getConnectTelegram, out byte[] payload)
+ protected internal bool TryGetTelegram(bool getConnectTelegram, out byte[] payload)
{
if (getConnectTelegram)
{