mkjeff / secs4net

SECS-II/HSMS-SS/GEM implementation on .NET
https://mkjeff.github.io/secs4net/
MIT License
443 stars 195 forks source link

Is it possible to support Linux ARMv7 32bits for doubles and floats #97

Open RexHung opened 9 months ago

RexHung commented 9 months ago

When I use float on Linux ARMv7 32, I get a System.DataMisalignedException exception. Is it possible to support Linux ARMv7 32bits for doubles and floats? Or is there a workaround?

  System.DataMisalignedException: A datatype misalignment was detected in a load or store instruction.
     at Secs4Net.Item.MemoryItem`1.EncodeTo(IBufferWriter`1 buffer) in /src/secs4net-2.4.3/src/Secs4Net/Item.Memory.cs:line 66
     at Secs4Net.Item.ListItem.EncodeTo(IBufferWriter`1 buffer) in /src/secs4net-2.4.3/src/Secs4Net/Item.List.cs:line 46
     at Secs4Net.SecsGem.SendDataMessageAsync(SecsMessage message, Int32 id, CancellationToken cancellation) in /src/secs4net-2.4.3/src/Secs4Net/SecsGem.cs:line 90
     at Secs4Net.PrimaryMessageWrapper.TryReplyAsync(SecsMessage replyMessage, CancellationToken cancellation) in /src/secs4net-2.4.3/src/Secs4Net/PrimaryMessageWrapper.cs:line 70
     at TestSecsWebApp.DeviceWorker.ExecuteAsync(CancellationToken stoppingToken) in /src/TestSecsWebApp/DeviceWorker.cs:line 133
mkjeff commented 9 months ago

I have a Raspberry Pi 2 Model B, maybe I can try it when I have time (no guarantee)

RexHung commented 9 months ago

I made a workaround which is using an unsigned long integer for casting double values and an unsigned integer for casting float values.

Besides the workaround of float and double, the backlog of the socket instance should be changed from 0 to 1 (it seems Linux-Arm uses the waiting queue differently.).

        if (typeof(T) == typeof(float))
        {
            ref var iValue = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(bufferByteSpan));
            var span = MemoryMarshal.CreateSpan<uint>(ref iValue, bufferByteSpan.Length / sizeof(float));
            ref var rStart = ref MemoryMarshal.GetReference(span);
            ref var rEnd = ref Unsafe.Add(ref rStart, span.Length);
            while (Unsafe.IsAddressLessThan(ref rStart, ref rEnd))
            {
                rStart = BitConverter.SingleToUInt32Bits(BinaryPrimitives.ReadSingleBigEndian(rStart.AsReadOnlyBytes()));
                rStart = ref Unsafe.Add(ref rStart, 1u);
            }
        }
        if (typeof(T) == typeof(double))
        {
            ref var lValue = ref Unsafe.As<byte, ulong>(ref MemoryMarshal.GetReference(bufferByteSpan));
            var span = MemoryMarshal.CreateSpan<ulong>(ref lValue, bufferByteSpan.Length / sizeof(double));
            ref var rStart = ref MemoryMarshal.GetReference(span);
            ref var rEnd = ref Unsafe.Add(ref rStart, span.Length);
            while (Unsafe.IsAddressLessThan(ref rStart, ref rEnd))
            {
                rStart = BitConverter.DoubleToUInt64Bits(BinaryPrimitives.ReadDoubleBigEndian(rStart.AsReadOnlyBytes()));
                rStart = ref Unsafe.Add(ref rStart, 1u);
            }
        }
        if (typeof(T) != typeof(float) && typeof(T) != typeof(double))
        {
            ReverseEndiannessHelper<T>.Reverse(Cast(bufferByteSpan));
        }

image