0

I have a Power Meter that communicates via Modbus TCP/IP. I'm using Kepware to retrieve the data and store it in a Microsoft SQL database. The Holding Register I'm pulling contains 32-bit float values, which currently appear in an unreadable format (e.g., -1.820742E+35).

When using a software called Modbus Doctor, I noticed that enabling the Swap Words function correctly converts the value to its actual reading (e.g., 409.9535V).

I’d like to achieve the same transformation directly within Microsoft SQL. Is there a way to mimic the Swap Words function in SQL, perhaps by creating a function that allows me to query the correct values?

Looking forward to your insights.

Thanks

1 Answer 1

1

You can convert the original value to BINARY(4) and then use the SUBSTRING() function to extract and swap the first-two and last-two bytes - SUBSTRING(BinaryValue, 3, 2) + SUBSTRING(BinaryValue, 1, 2).

The trick is converting back to a REAL (32-bit floating point) value. SQL Server has no built-in capability to convert BINARY to REAL. Luckily, that need has arisen before in the question Convert float to varbinary and back to float, and we have a function for that.

CREATE FUNCTION ConvertBinaryToReal(@Binary VARBINARY(MAX)) RETURNS REAL
AS
BEGIN
    -- IEEE 754 Single Precision binary to float
    -- Layout:
    --   32 bits total
    --   1 bit sign
    --   8 bits exponent (excess 127)
    --   23 bits fractional mantissa  (with implicit leading 1) = 1.xxxxx
    -- Does not support IEEE NaN, +Inf, or -Inf values. 

    IF (@Binary IS NULL OR DATALENGTH(@Binary) <> 4) RETURN NULL
    IF (@Binary = 0x00000000) RETURN 0
    IF (@Binary = 0x80000000) RETURN -0e0 -- IEEE Negative 0

    DECLARE @Int32 INT = CAST(@Binary AS INT)
    DECLARE @One REAL = 1
    DECLARE @Two REAL = 2
    DECLARE @Mantissa REAL = @One + (@Int32 & 0x007FFFFF) * POWER(@Two, -23)
    DECLARE @Exponent INT = (@Int32 & 0x7f800000) / 0x00800000 - 127

    IF (@Exponent = 128) RETURN NULL -- Unsupported special: Inf, -Inf, NaN

    RETURN SIGN(@Int32) * @Mantissa * POWER(@Two, @Exponent)
END

Using your sample value 409.9535, the binary representation is 0x43CCFA0C, and the swapped binary representation is 0xFA0C43CC.

The following will swap the bytes and convert the result to a REAL value.

SELECT *
FROM (
    VALUES (0xFA0C43CC)
) SB(SwappedBinary)
CROSS APPLY (
    SELECT SUBSTRING(SB.SwappedBinary, 3, 2)
           + SUBSTRING(SB.SwappedBinary, 1, 2)
           AS OriginalBinary
) OB
CROSS APPLY (
    SELECT dbo.ConvertBinaryToReal(OB.OriginalBinary) AS OriginalValue
) OV

Results:

SwappedBinary OriginalBinary OriginalValue
0xFA0C43CC 0x43CCFA0C 409.9535

See this db<>fiddle for a demo.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.