using System; using System.Runtime.InteropServices; using NvAPIWrapper.Native.Attributes; using NvAPIWrapper.Native.General.Structures; using NvAPIWrapper.Native.Helpers; using NvAPIWrapper.Native.Helpers.Structures; using NvAPIWrapper.Native.Interfaces; using NvAPIWrapper.Native.Interfaces.GPU; namespace NvAPIWrapper.Native.GPU.Structures { /// [StructLayout(LayoutKind.Sequential, Pack = 8)] [StructureVersion(2)] public struct I2CInfoV2 : IInitializable, IDisposable, II2CInfo { // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly StructureVersion _Version; private readonly OutputId _OutputMask; private readonly byte _UseDDCPort; private readonly byte _I2CDeviceAddress; private ValueTypeArray _I2CRegisterAddress; private readonly uint _I2CRegisterAddressLength; private ValueTypeArray _Data; private readonly uint _DataLength; // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly uint _I2CSpeed; private readonly I2CSpeed _I2CSpeedInKHz; /// // ReSharper disable once ConvertToAutoProperty public OutputId OutputMask { get => _OutputMask; } /// public bool UseDDCPort { get => _UseDDCPort > 0; } /// // ReSharper disable once ConvertToAutoProperty public I2CSpeed Speed { get => _I2CSpeedInKHz; } /// public bool IsReadOperation { get => (_I2CDeviceAddress & 1) == 1; } /// public byte DeviceAddress { get => (byte) (_I2CDeviceAddress >> 1); } /// public byte[] Data { get { if (_Data.IsNull || _DataLength == 0) { return new byte[0]; } return _Data.ToArray((int) _DataLength); } } /// public byte[] RegisterAddress { get { if (_I2CRegisterAddress.IsNull || _I2CRegisterAddressLength == 0) { return new byte[0]; } return _I2CRegisterAddress.ToArray((int) _I2CRegisterAddressLength); } } /// public byte? PortId { get => null; } /// /// Creates an instance of for write operations. /// /// The target display output mask /// A boolean value indicating that the DDC port should be used instead of the communication port /// The device I2C slave address /// The target I2C register address /// The payload data /// The target speed of the transaction in kHz public I2CInfoV2( OutputId outputMask, bool useDDCPort, byte deviceAddress, byte[] registerAddress, byte[] data, I2CSpeed speed = I2CSpeed.Default ) : this(outputMask, useDDCPort, deviceAddress, false, registerAddress, data, speed) { } /// /// Creates an instance of for read operations. /// /// The target display output mask /// A boolean value indicating that the DDC port should be used instead of the communication port /// The device I2C slave address /// The target I2C register address /// The length of the buffer to allocate for the read operation. /// The target speed of the transaction in kHz public I2CInfoV2( OutputId outputMask, bool useDDCPort, byte deviceAddress, byte[] registerAddress, uint readDataLength, I2CSpeed speed = I2CSpeed.Default ) : this(outputMask, useDDCPort, deviceAddress, true, registerAddress, new byte[readDataLength], speed) { } private I2CInfoV2( OutputId outputMask, bool useDDCPort, byte deviceAddress, bool isRead, byte[] registerAddress, byte[] data, I2CSpeed speed = I2CSpeed.Default ) { this = typeof(I2CInfoV2).Instantiate(); _UseDDCPort = useDDCPort ? (byte) 1 : (byte) 0; _OutputMask = outputMask; _I2CDeviceAddress = (byte) (deviceAddress << 1); _I2CSpeed = 0xFFFF; // Deprecated _I2CSpeedInKHz = speed; if (isRead) { _I2CDeviceAddress |= 1; } if (registerAddress?.Length > 0) { _I2CRegisterAddress = ValueTypeArray.FromArray(registerAddress); _I2CRegisterAddressLength = (uint) registerAddress.Length; } else { _I2CRegisterAddress = ValueTypeArray.Null; _I2CRegisterAddressLength = 0; } if (data?.Length > 0) { _Data = ValueTypeArray.FromArray(data); _DataLength = (uint) data.Length; } else { _Data = ValueTypeArray.Null; _DataLength = 0; } } /// /// Calculates and fills the last byte of data to the checksum value required by the DDCCI protocol /// /// The target device address. /// The target register address. /// The data to be sent and store the checksum. public static void FillDDCCIChecksum(byte deviceAddress, byte[] registerAddress, byte[] data) { var checksum = deviceAddress; if (data == null) { throw new ArgumentNullException(nameof(data)); } if (data.Length == 0) { throw new ArgumentException("Checksum needs at least one free byte.", nameof(data)); } if (registerAddress == null) { throw new ArgumentNullException(nameof(registerAddress)); } // ReSharper disable once ForCanBeConvertedToForeach // ReSharper disable once LoopCanBeConvertedToQuery for (var i = 0; i < registerAddress.Length; i++) { checksum ^= registerAddress[i]; } // ReSharper disable once ForCanBeConvertedToForeach // ReSharper disable once LoopCanBeConvertedToQuery for (var i = 0; i < data.Length - 1; i++) { checksum ^= data[i]; } data[data.Length - 1] = checksum; } /// public void Dispose() { if (!_I2CRegisterAddress.IsNull) { _I2CRegisterAddress.Dispose(); } if (!_Data.IsNull) { _Data.Dispose(); } } } }