using FxpConvert.Common; using log4net.Appender; using MessagePack.Formatters; using System.Buffers.Binary; using System.Reflection; using System.Runtime.CompilerServices; namespace NIFPGA { public sealed class FPGAArrayFXPWriteProperty : FPGABaseProperty { Interop.NiFpgaDll_ReadArrayU8 Read; Interop.NiFpgaDll_WriteArrayU8 Write; private object _Locker = new object(); private NiFpga_FxpTypeInfo _TypeInfo; private IFxpConvert _Convert; private uint bytescount = 0; private ulong[] tempbuffer = new ulong[0]; private double[] doubles = new double[0]; private ulong[] tempvalue = new ulong[0]; internal FPGAArrayFXPWriteProperty(FPGASession session, uint indicator, uint count,NiFpga_FxpTypeInfo typeInfo, IFxpConvert convert) : base(session, indicator,false) { _Convert = convert; Count = count; doubles = new double[count]; tempvalue = new ulong[count]; _TypeInfo = typeInfo; tempbuffer = new ulong[(int)Math.Ceiling(typeInfo.wordLength * count / 64.0)]; bytescount = (uint)Math.Ceiling(typeInfo.wordLength * count / 8.0); Read = _Session.GetDelegate(); Write = _Session.GetDelegate(); } private double[] GetData() { lock (_Locker) { _Session.CheckResult(Read(_Session.Session, Indicator, ref Unsafe.As (ref tempbuffer[0]), bytescount)); for(int i = 0; i < tempbuffer.Length;i++) { tempbuffer[i] = BinaryPrimitives.ReverseEndianness(tempbuffer[i]); } int tempdatalen = Unsafe.SizeOf() * 8; ulong mask = (1ul << _TypeInfo.wordLength) - 1; for (int i = 0; i < Count; i++) { int index = i * _TypeInfo.wordLength / tempdatalen; int bitindex =tempdatalen - (i * _TypeInfo.wordLength % tempdatalen); if (bitindex >= _TypeInfo.wordLength) { tempvalue[i] = (tempbuffer[index] >> (bitindex-_TypeInfo.wordLength)) & mask; } else { tempvalue[i] = (((tempbuffer[index] & ((1ul << bitindex) - 1)) << (_TypeInfo.wordLength - bitindex)) | (tempbuffer[index + 1] >> (tempdatalen - (_TypeInfo.wordLength - bitindex)))); } } _Convert.FxpConvertToDouble(ref tempvalue[0], _TypeInfo, ref doubles[0], Count); return doubles; } } private void SetData(double[] values) { lock (_Locker) { if (values.Length != Count || Count == 0) return; _Convert.DoubleConvertToDxp(ref values[0], _TypeInfo, ref tempvalue[0], Count); int tempdatalen = Unsafe.SizeOf() * 8; tempbuffer = new ulong[tempbuffer.Length]; for (int i = 0; i < Count; i++) { int index = i * _TypeInfo.wordLength / tempdatalen; int bitindex = tempdatalen - (i * _TypeInfo.wordLength % tempdatalen); var b = (tempvalue[i] & ((1ul << _TypeInfo.wordLength) - 1)); if (bitindex >= _TypeInfo.wordLength) { tempbuffer[index] |= (b << (bitindex - _TypeInfo.wordLength)); } else { tempbuffer[index] |= (b >> (_TypeInfo.wordLength - bitindex)); tempbuffer[index + 1] |= ((b & ((1ul << (_TypeInfo.wordLength - bitindex)) - 1)) << (tempdatalen - (_TypeInfo.wordLength - bitindex))); } } ulong[] oldvalues = new ulong[tempbuffer.Length]; _Session.CheckResult(Read(_Session.Session, Indicator, ref Unsafe.As(ref oldvalues[0]), bytescount)); for (int i = 0; i < tempbuffer.Length; i++) { tempbuffer[i] = BinaryPrimitives.ReverseEndianness(tempbuffer[i]); } bool changed = Enumerable.Range(0, oldvalues.Length).Any(x => oldvalues[x] != tempbuffer[x]); if (!changed) return; _Session.CheckResult(Write(_Session.Session, Indicator, ref Unsafe.As(ref tempbuffer[0]), bytescount)); } } public uint Count { get; } public double[] Value { get => GetData(); set => SetData(value); } } }