3

I'm relatively new to lua and programming in general (self taught), so please be gentle!

Anyway, I wrote a lua script to read a UDP message from a game. The structure of the message is:

DATAxXXXXaaaaBBBBccccDDDDeeeeFFFFggggHHHH
DATAx = 4 letter ID and x = control character
XXXX = integer shows the group of the data (groups are known)
aaaa...HHHHH = 8 single-precision floating point numbers

The last ones is those numbers I need to decode.

If I print the message as received, it's something like:

DATA*{V???A?A?...etc.

Using string.byte(), I'm getting a stream of bytes like this (I have "formatted" the bytes to reflect the structure above.

68 65 84 65/42/20 0 0 0/237 222 28 66/189 59 182 65/107 42 41 65/33 173 79 63/0 0 128 63/146 41 41 65/0 0 30 66/0 0 184 65

The first 5 bytes are of course the DATA*. The next 4 are the 20th group of data. The next bytes, the ones I need to decode, and are equal to those values:

237 222 28 66 = 39.218
189 59 182 65 = 22.779
107 42 41 65 = 10.573
33 173 79 63 = 0.8114
0 0 128 63 = 1.0000
146 41 41 65 = 10.573
0 0 30 66 = 39.500
0 0 184 65 = 23.000

I've found C# code that does the decode with BitConverter.ToSingle(), but I haven't found any like this for Lua. Any idea?

Egor Skriptunoff
  • 23,359
  • 2
  • 34
  • 64
  • Can you give an example of a *full* message that you receive, before using `string.byte()`? – brianolive Sep 08 '18 at 19:56
  • Here is an example using print(). _DATA*{V???A?A??:?y?g(???%A???:_ Not the above but something similar. – Ilias Tselios Sep 08 '18 at 20:13
  • How did you determine the values of the byte arrays above (e.g., `0 0 128 63 = 1.0000`? – brianolive Sep 08 '18 at 20:33
  • The game is X-Plane flight simulator and those values can be displayed in the game. Here is an [capture from the game](https://i.imgur.com/azJ2LfZ.png). They are aircraft's position (coordinates, altitude, etc.) – Ilias Tselios Sep 08 '18 at 20:44

2 Answers2

3

What Lua version do you have?
This code works in Lua 5.3

local str = "DATA*\20\0\0\0\237\222\28\66\189\59\182\65..."
-- Read two float values starting from position 10 in the string
print(string.unpack("<ff", str, 10))  -->  39.217700958252  22.779169082642 18
-- 18 (third returned value) is the next position in the string

For Lua 5.1 you have to write special function (or steal it from François Perrad's git repo )

local function binary_to_float(str, pos)
   local b1, b2, b3, b4 = str:byte(pos, pos+3)
   local sign = b4 > 0x7F and -1 or 1
   local expo = (b4 % 0x80) * 2 + math.floor(b3 / 0x80)
   local mant = ((b3 % 0x80) * 0x100 + b2) * 0x100 + b1
   local n
   if mant + expo == 0 then
      n = sign * 0.0
   elseif expo == 0xFF then
      n = (mant == 0 and sign or 0) / 0
   else
      n = sign * (1 + mant / 0x800000) * 2.0^(expo - 0x7F)
   end
   return n
end


local str = "DATA*\20\0\0\0\237\222\28\66\189\59\182\65..."
print(binary_to_float(str, 10))  --> 39.217700958252
print(binary_to_float(str, 14))  --> 22.779169082642
Egor Skriptunoff
  • 23,359
  • 2
  • 34
  • 64
  • Thanks @Egor a lot! Unpacking directly the received message, works fine with Lua 5.3. [Here is the output](https://imgur.com/2Yu7LAj). But, I'm planning to use it for a mobile app using Corona SDK, which uses Lua 5.1.3. I'll see what I can do. – Ilias Tselios Sep 09 '18 at 09:29
  • Thanks a lot @Egor! I owe you a beer! – Ilias Tselios Sep 09 '18 at 11:07
  • Thanks as well @Egor - I’m glad that I was wrong below! It forced me to dig into the `string.unpack` documentation. I would add to your answer an explanation of the first argument, the string format, where `<` will mark the string as little-endian and `ff` is what gets you back two floats. There are other options as well for the string format covered [here](https://www.lua.org/manual/5.3/manual.html#6.4.2) – brianolive Sep 09 '18 at 14:33
1

It’s little-endian byte-order of IEEE-754 single-precision binary:

E.g., 0 0 128 63 is:

00111111 10000000 00000000 00000000 (63) (128) (0) (0)

Why that equals 1 requires that you understand the very basics of IEEE-754 representation, namely its use of an exponent and mantissa. See here to start.

See @Egor‘s answer above for how to use string.unpack() in Lua 5.3 and one possible implementation you could use in earlier versions.

brianolive
  • 1,573
  • 2
  • 9
  • 19
  • 1
    Thanks a lot @Brian . Just what I needed, a direction to go. I understood that i need to write some code for that, but that is fine. – Ilias Tselios Sep 08 '18 at 21:00