Jump to content
The simFlight Network Forums

trying to extract numbers from string


Recommended Posts

Hi folks,

I am trying to extract numbers from a string. The string corresponds to the full FCU message, for example SPD240 or MACH 0,78. Let's call the offset where the string can be found 0xABCD. The result shall be written to offset 066C1. As the MACH number is not an integer, I think I should be working with floats. As SPD and MACH have different lengths, I cannot extract from specific positions of the string.

spdstate = ipc.readSTR(0xABCD)
local speed = string.match(spdstate, "%d+")
ipc.writeFLT(0x66C1, speed)

end

I would like to show the resulting value in a window in FSX, I think I shoud use U32 as a type for logging.

But I only receive a 0.

Any input is much appreciated. I am reluctant to use the tonumber function as I am afraid I will mess up.

Best regards

-shorthauler

Link to comment
Share on other sites

string.match will return a string, not a number, so you need to convert the results to a number (using tonumber). Also, the match will stop after the first non-digit character is found (after a digit), so "Mach 0,78" will return 0 (due to the comma).

If you want to extract decimals, see https://stackoverflow.com/questions/38140434/lua-how-to-retrieve-a-decimal-number-from-string.
Otherwise, maybe take a look here: https://stackoverflow.com/questions/46794989/extracting-number-from-string-using-lua

But it would be better to just read the offsets holding the values you want to extract. For example, if its the mach speed, that will be in offset 0x11C6 (or 0x35A0 or maybe 0x07E8 for AP mach value).

 

Link to comment
Share on other sites

11 hours ago, shorthauler said:

It was essential to define the lenght of the string (the ", 9" in the first line).

Yes, sorry, missed that...

11 hours ago, shorthauler said:

This now works:

spdstate = ipc.readSTR(0xABCD, 9)
speed = string.match(spdstate, "%d+")
ipc.writeSW(0x66C1, speed)

That surprises me though, for the reasons previously mentioned...

Link to comment
Share on other sites

Yes, I was also surprised, but it only works in SPD mode, not in MACH. SPD is an integer, MACH a rational number < 1. For MACH I only get a zero. This may be the zero in front of the decimal, and the value after the decimal is cut off. I have tried to make use of the tonumber function - did I do this correctly?

For the value after the decimal, I tried this "[%d.,]". But it does not do the trick.

I have used "ipc.writeSW" (signed word value).

 

-- dashes C2, dot C3

spdstate = ipc.readSTR(0xABCD, 9)

if (string.find(spdstate, "---") and string.find(spdstate, "*")) then
      ipc.writeUB(0x66C2,1)
      ipc.writeUB(0x66C3,1)
elseif (string.find(spdstate, "---") and not string.find(spdstate, "*")) then
      ipc.writeUB(0x66C2,1)
      ipc.writeUB(0x66C3,0)
elseif (string.find(spdstate, "*") and not string.find(spdstate, "---")) then
      ipc.writeUB(0x66C2,0)
      ipc.writeUB(0x66C3,1)
else
    ipc.writeUB(0x66C2,0)
    ipc.writeUB(0x66C3,0)
end

speed_str = string.match(spdstate, "%d%d[%d.,]") -- speed as string
speed =tonumber(speed_str) -- converting speed from string to number
ipc.writeSW(0x66C1, speed)

Link to comment
Share on other sites

1 hour ago, shorthauler said:

MACH a rational number < 1. For MACH I only get a zero.

This is because it contains a comma not a full stop - MACH 0,78 not MACH 0.78 - or was that a typo?
If it is a comma, you could try replacing that with a full stop first....

And as with your other post, try adding some logging statements to determine what is happening....

John

 

 

Link to comment
Share on other sites

See the following:

Quote

function getnumbersfromtext(txt)
    local str = ""
    string.gsub(txt,"([%d.]+)",function(e)
      str = str .. e
      end)
    return tonumber(str);
end

n = getnumbersfromtext("SPD240")
ipc.log("SPD240: " .. n)
n = getnumbersfromtext("MACH 0.78")
ipc.log("MACH 0.78: " .. n)
n = getnumbersfromtext("MACH 1.78")
ipc.log("MACH 1.78: " .. n)
 

Output:

  1734078 LUA.15: SPD240: 240
  1734094 LUA.15: MACH 0.78: 0.78
  1734110 LUA.15: MACH 1.78: 1.78
 

Link to comment
Share on other sites

Thank you, so adapted to my variables, this would look like this?

spdstate = ipc.readSTR(0xABCD, 9)

function getnumbersfromtext(spdstate)
    local str = ""
    string.gsub(txt,"([%d.]+)",function(e)
      str = str .. e
      end)
    return tonumber(str);
end

speed = getnumbersfromtext
ipc.writeSW(0x66C1, speed)

 

Link to comment
Share on other sites

I think I may have the correct code now:

spdstate = ipc.readSTR(0xABCD, 9)

function getnumbersfromtext(spdstate)
return tonumber(spdstate:match"%d+[%d.,]*")
end

speed = getnumbersfromtext(spdstate) -- everything works until here, I get a correct Mach number such as 0.59
ipc.writeFLT(0x66C1, speed) -- I get 0.590000000000... as an output value that I read via the logging window or in Mobiflight

As per the log below, I am getting the correct results for "speed". But how do I write them best to the offset? If I use "writeFLT" for writing and "FLT32" for monitoring, I get a number with a seemingly infinite number of zeroes after the Mach value. I only need the two digits after the decimal, just like in the log.

Am I using the wrong format to write to the offset?

Best regards,
- shorthauler

 

********* LUA: "A320 SPD split" Log [from FSUIPC version 4.977] *********
   529704 System time = 24/09/2023 09:09:22, Simulator time = 13:20:07 (12:20Z)
   529704 LUA: beginning "E:\FSX\Flight Simulator X\Modules\A320 SPD split.lua"
   529719 LUA: E:\FSX\Flight Simulator X\Modules\A320 SPD split.lua:1
   529719 LUA: Global: ipcPARAM = 0
   529719 LUA: E:\FSX\Flight Simulator X\Modules\A320 SPD split.lua:11
   529719 LUA: Global: spdstate = MACH
0.56
   529719 LUA: E:\FSX\Flight Simulator X\Modules\A320 SPD split.lua:3
   529735 LUA: E:\FSX\Flight Simulator X\Modules\A320 SPD split.lua:13
   529735 LUA: E:\FSX\Flight Simulator X\Modules\A320 SPD split.lua:6 fn: getnumbersfromtext
   529735 LUA: Local: spdstate = MACH
0.56
   529735 LUA: E:\FSX\Flight Simulator X\Modules\A320 SPD split.lua:14
   529735 LUA: Global: speed = 0.56
   529766 >>> Thread forced exit (ipc.exit or os.exit) <<<
   529766 System time = 24/09/2023 09:09:22, Simulator time = 13:20:09 (12:20Z)
********* LUA execution terminated: Log Closed *********

 

Link to comment
Share on other sites

1 hour ago, shorthauler said:

ipc.writeFLT(0x66C1, speed) -- I get 0.590000000000... as an output value that I read via the logging window or in Mobiflight

But you should not do his... a float is 4 bytes/32-bits, and so you should write on a 4-byte boundary. This will also overwrite offsets 66C2, CC63 &  66C4

1 hour ago, shorthauler said:

If I use "writeFLT" for writing and "FLT32" for monitoring, I get a number with a seemingly infinite number of zeroes after the Mach value.

This is how floating point numbers work - they are not exact. If you only want to store to 2 decimal places, store the value * 100 as an int, and just remember to divide by 100 when you read it. The size of the offset that you need to store the number depends on the range - you can use 2-bytes if its always between -32,768 to 32,767 (signed) or 0-65,535 (signed), and 4-bytes for the full int range (-2,147,483,648 to 2,147,483,647 signed, 0 to 4,294,967,295 unsigned). And 1-byte if its between 0-255 (unsigned) or -128 - + 127 (signed).

Remember to always read the same size as writing, don't overlap your offsets (i.e. make sure you leave enough space for the offset to hold the data before assigning the next offset value), and respect offset boundaries depending on the size of the data the offset holds (as I explained in the other post!).

John

Link to comment
Share on other sites

Thanks a lot, *100 and then /100 in MobiFlight works great!

I am using free offset 66C1 for the speed and it occupies 66C2 as well, but not 66C3 and beyond. For "speed100" I am logging U16 in the simulator and a 2 byte integer in MobiFlight.

This is the final script. It works well. There is, however, a noticeable delay between the digit changes in the simulator and the digit changes in my FCU.

I am using "repeat ... until condition" to have the script constantly run over the string and check for changes. Maybe this can be done more efficiently.

- shorthauler

 

repeat

spdstate = ipc.readSTR(0xABCD, 9)

function getnumbersfromtext(spdstate)
return tonumber(spdstate:match"%d+[%d.,]*")
end

if (string.find(spdstate, "%-") and string.find(spdstate, "%*")) then
    ipc.writeUB(0x66C5,1)
    ipc.writeUB(0x66C6,1)
  elseif string.find(spdstate, "%-") then
    ipc.writeUB(0x66C5,1)
    ipc.writeUB(0x66C6,0)
  elseif string.find(spdstate, "%*") then
    ipc.writeUB(0x66C5,0)
    ipc.writeUB(0x66C6,1)
  else
    ipc.writeUB(0x66C5,0)
    ipc.writeUB(0x66C6,0)
end

if string.find(spdstate, "SPD") then
    ipc.writeUB(0x66C7,1)
else
    ipc.writeUB(0x66C7,0)
end

if string.find(spdstate, "MACH") then
    ipc.writeUB(0x66C8,1)
else
    ipc.writeUB(0x66C8,0)
end

if string.find(spdstate, "%-") then
    ipc.writeSW(0x66C1, 0)                    -- speed hast to be forced to 0, when the dashes appear in managed mode, otherwise there will be interferences with the dashes
else
    speed = getnumbersfromtext(spdstate)
    speed100 = speed*100
    ipc.writeUW(0x66C1, speed100)      -- logging "speed100" with U16 in the simulator and a 2 byte integer in MobiFlight
end

until condition

Link to comment
Share on other sites

14 hours ago, shorthauler said:

I am using free offset 66C1 for the speed and it occupies 66C2 as well, but not 66C3 and beyond. For "speed100" I am logging U16 in the simulator and a 2 byte integer in MobiFlight.

But, as I keep saying, ypu shouldn't do this.... If you are storing a number in an offset as a 2-byte word, you should store it starting on a 2-byte offset, e.g. at 66C0 or 66C2. It way seem to work, but you can get problems if you don't do this, depending on how the offset is accessed...

14 hours ago, shorthauler said:

I am using "repeat ... until condition" to have the script constantly run over the string and check for changes. Maybe this can be done more efficiently.

Rather than have it run in an endless loop, you can use the event.offset function, using offset 0xABCD, so that you update each time that offset changes value - this would be more efficient.

Link to comment
Share on other sites

Thank you, I was not aware of this. I replaced offset 66C1 by 66C0. The values stored in 66C0 still "leak" into 66C1.

I am not sure how I should apply "event.offset" to 0xABCD here. I made a line event.offset (0x54C4, "STR", 9, "getnumbersfromtext") and put it in front of everything else as first line. But this does not work.

If the format is event.offset(offset, "STR", length, "function-name") what should I use as function name?

Best

- shorthauler

Link to comment
Share on other sites

11 hours ago, shorthauler said:

The values stored in 66C0 still "leak" into 66C1.

No they don't, as I have explained several times. Offsets will be written starting from the offset specified and to the number of offsets required by the type and size of the data you are writing, and when you read from an offset it will read that offset and the consecutive ones up to the size if the data type you are reading. Everything works as it should, and nothing "leaks". You just need to understand how memory addresses work.

11 hours ago, shorthauler said:

I made a line event.offset (0x54C4, "STR", 9, "getnumbersfromtext") and put it in front of everything else as first line. But this does not work.

Of course not, as that would just call the getnumbersfromtext function each time the offset changed - that is obviously not what you want....

11 hours ago, shorthauler said:

If the format is event.offset(offset, "STR", length, "function-name") what should I use as function name?

Whatever you like - you have to wrap your script in a function, e.g. based upon the last script you posted

function getnumbersfromtext(spdstate)
    return tonumber(spdstate:match"%d+[%d.,]*")
end

funcyion decodeString(offset, spdstate)
    if (string.find(spdstate, "%-") and string.find(spdstate, "%*")) then
        ipc.writeUB(0x66C5,1)
        ipc.writeUB(0x66C6,1)
    elseif string.find(spdstate, "%-") then
        ipc.writeUB(0x66C5,1)
        ipc.writeUB(0x66C6,0)
    elseif string.find(spdstate, "%*") then
        ipc.writeUB(0x66C5,0)
        ipc.writeUB(0x66C6,1)
    else
        ipc.writeUB(0x66C5,0)
        ipc.writeUB(0x66C6,0)
    end

    if string.find(spdstate, "SPD") then
        ipc.writeUB(0x66C7,1)
    else
        ipc.writeUB(0x66C7,0)
    end

    if string.find(spdstate, "MACH") then
        ipc.writeUB(0x66C8,1)
    else
        ipc.writeUB(0x66C8,0)
    end

    if string.find(spdstate, "%-") then
        ipc.writeSW(0x66C1, 0) -- speed hast to be forced to 0, when the dashes appear in managed mode, otherwise there will be interferences with the dashes
    else
        speed = getnumbersfromtext(spdstate)
        speed100 = speed*100
        ipc.writeUW(0x66C1, speed100)      -- logging "speed100" with U16 in the simulator and a 2 byte integer in MobiFlight
    end
end -- of function decodeString

event.offset (0xABCD, "STR", 9, "decodeString") 

If you are planning to use lua, you should look at some on-line lua tutorials. Also take a look at the example lua scripts provided, which are located in your FSUIPC documents folders. There are also plenty of examples in these forums.

John

 

Link to comment
Share on other sites

Thank you, now everything works. I am consulting lua fora, but I was under the impression that event.offset was specific to FSUIPC. I misread the lua library document - the term offset is not between quotation marks, so it should indeed be written offset. I wrote the actual offset, silly me.

Thank you so much again

-shorthauler

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.