public void TestSdkDecoding()
        {
            AtemMockServerWrapper.Each(_output, _pool, null, DeviceTestCases.CameraControl, helper =>
            {
                helper.Helper.StateSettings.IgnoreUnknownCameraControlProperties = true;
                IBMDSwitcherCameraControl camera = helper.SdkClient.SdkSwitcher as IBMDSwitcherCameraControl;
                Assert.NotNull(camera);

                using var watcher = new CameraControlReceiver(helper);

                for (int i = 0; i < 20; i++)
                {
                    AtemState stateBefore = helper.Helper.BuildLibState();

                    // Generate and send some data
                    CameraControlGetCommand cmd = new CameraControlGetCommand();
                    FillRandomData(cmd);

                    if (!stateBefore.CameraControl.Cameras.ContainsKey((long)cmd.Input))
                    {
                        stateBefore.CameraControl.Cameras[(long)cmd.Input] = new CameraControlState.CameraState();
                    }
                    helper.SendFromServerAndWaitForChange(stateBefore, cmd);

                    // Check libatem encoding
                    CameraControlGetCommand libCmd = watcher.LastCommand;
                    Assert.NotNull(libCmd);
                    AreEqual(cmd, libCmd);

                    // Pull the value out of the sdk, and ensure it is the same
                    CameraControlGetCommand sdkCmd =
                        CameraControlBuilder.BuildCommand(camera, (uint)cmd.Input, cmd.Category, cmd.Parameter);

                    AreEqual(cmd, sdkCmd);
                }
            });
        }
        public void TestSdkRelativeEncoding()
        {
            AtemMockServerWrapper.Each(_output, _pool, CameraCommandHandler, DeviceTestCases.CameraControl, helper =>
            {
                helper.Helper.StateSettings.IgnoreUnknownCameraControlProperties = true;
                IBMDSwitcherCameraControl camera = helper.SdkClient.SdkSwitcher as IBMDSwitcherCameraControl;
                Assert.NotNull(camera);

                using var watcher = new CameraControlReceiver(helper);

                for (int i = 0; i < 20; i++)
                {
                    AtemState stateBefore = helper.Helper.BuildLibState();

                    // Generate and send some data
                    CameraControlGetCommand refCmd = new CameraControlGetCommand();
                    FillRandomData(refCmd, CameraControlDataType.String);

                    if (!stateBefore.CameraControl.Cameras.ContainsKey((long)refCmd.Input))
                    {
                        stateBefore.CameraControl.Cameras[(long)refCmd.Input] = new CameraControlState.CameraState();
                    }

                    helper.SendFromServerAndWaitForChange(stateBefore, refCmd);
                    _prevCmd = refCmd;

                    {
                        // Pull the value out of the sdk, and ensure it is the same
                        CameraControlGetCommand sdkCmd =
                            CameraControlBuilder.BuildCommand(camera, (uint)refCmd.Input, refCmd.Category, refCmd.Parameter);

                        AreEqual(refCmd, sdkCmd);
                    }

                    CameraControlGetCommand cmd = CopyCommand(refCmd);
                    FillRandomOffsetData(cmd);

                    // Now do the sdk offset
                    helper.SendAndWaitForChange(stateBefore, () =>
                    {
                        switch (cmd.Type)
                        {
                        case CameraControlDataType.Bool:
                            {
                                IntPtr data = Randomiser.BuildSdkArray(sizeof(sbyte),
                                                                       cmd.BoolData.Select(v => v ? 1 : 0).ToArray());
                                unsafe
                                {
                                    var ptr = (int *)data.ToPointer();
                                    camera.ToggleFlags((uint)cmd.Input, cmd.Category, cmd.Parameter,
                                                       (uint)cmd.BoolData.Length, ref *ptr);
                                }
                                break;
                            }

                        case CameraControlDataType.SInt8:
                            {
                                IntPtr data = Randomiser.BuildSdkArray(sizeof(sbyte), cmd.IntData);
                                unsafe
                                {
                                    var ptr = (sbyte *)data.ToPointer();
                                    camera.OffsetInt8s((uint)cmd.Input, cmd.Category, cmd.Parameter,
                                                       (uint)cmd.IntData.Length, ref *ptr);
                                }
                                break;
                            }

                        case CameraControlDataType.SInt16:
                            {
                                IntPtr data = Randomiser.BuildSdkArray(sizeof(short), cmd.IntData);
                                unsafe
                                {
                                    var ptr = (short *)data.ToPointer();
                                    camera.OffsetInt16s((uint)cmd.Input, cmd.Category, cmd.Parameter,
                                                        (uint)cmd.IntData.Length, ref *ptr);
                                }
                                break;
                            }

                        case CameraControlDataType.SInt32:
                            {
                                IntPtr data = Randomiser.BuildSdkArray(sizeof(int), cmd.IntData);
                                unsafe
                                {
                                    var ptr = (int *)data.ToPointer();
                                    camera.OffsetInt32s((uint)cmd.Input, cmd.Category, cmd.Parameter,
                                                        (uint)cmd.IntData.Length, ref *ptr);
                                }
                                break;
                            }

                        case CameraControlDataType.SInt64:
                            {
                                IntPtr data = Randomiser.BuildSdkArray(cmd.LongData);
                                unsafe
                                {
                                    var ptr = (long *)data.ToPointer();
                                    camera.OffsetInt64s((uint)cmd.Input, cmd.Category, cmd.Parameter,
                                                        (uint)cmd.LongData.Length, ref *ptr);
                                }
                                break;
                            }

                        case CameraControlDataType.Float:
                            {
                                IntPtr data = Randomiser.BuildSdkArray(cmd.FloatData);
                                unsafe
                                {
                                    var ptr = (double *)data.ToPointer();
                                    camera.OffsetFloats((uint)cmd.Input, cmd.Category, cmd.Parameter,
                                                        (uint)cmd.FloatData.Length, ref *ptr);
                                }
                                break;
                            }

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    });

                    var completeCmd = CopyCommand(refCmd);
                    ApplyOffsets(completeCmd, cmd);

                    // Check libatem encoding
                    CameraControlGetCommand libCmd = watcher.LastCommand;
                    Assert.NotNull(libCmd);
                    AreEqual(completeCmd, libCmd);

                    {
                        // Pull the value out of the sdk, and ensure it is the same
                        CameraControlGetCommand sdkCmd =
                            CameraControlBuilder.BuildCommand(camera, (uint)refCmd.Input, refCmd.Category, refCmd.Parameter);

                        AreEqual(completeCmd, sdkCmd);
                    }
                }
            });
        }