Jump to content

Experiment - Controlling Lockon from another application using lua


Joe Kurr

Recommended Posts

I first got this idea when we started work on our cockpit project, but at that time, I only knew how to export stuff from lockon via the export.lua script.

After studying the lua language a little, and searching the net, I found out that it is also possible to use export.lua as an import script :)

 

To try this out, I created a small program to run on my PDA, which functions like TouchBuddy in a way, but much simpler (at the moment, it has only six non-programmable buttons).

It communicates with the PC via a TCP socket, using port 10309.

 

On the PC, I was first planning to create a small server, which would translate the commands it received from the PDA into keystrokes for Lockon.

But since Lockon has the LoSetCommand() function in the export.lua script, I wondered if it would be possible to create the server using a lua script.

 

After some tests, I had a perfectly working server script, which handled all my commands, but it was running outside of Lockon, and since it used an endless loop, this might be a problem.

 

Time to learn coroutines :)

 

After a couple of hours of programming and testing, I finally managed to create a script, which runs inside Lockon, and listens on TCP port 10309 for incoming commands.

It then translates the received commands into the numeric command codes listed at the end of the export.lua script, and calls the LoSetCommand() function.

 

By using this script, I can now control my aircraft from any type of application, even via a script from a web browser :D

 

As I'm still in the early stages of learning lua, maybe some of you can comment on my script to make it better.

 

Here's the lua script:

 

---------------------------------------------------------------------------------------------------
-- TCP Listener script for controlling Lockon from an external program                           --
-- Author: Bas 'Joe Kurr' Weijers                                                                --
---------------------------------------------------------------------------------------------------

dofile "lua.lua"

-- Listener settings
-- By default, the listener binds to port 10309 on all local network interfaces
local host     = "*"
local port     = 10309

-- Command list
-- Send these commands from your application to execute the corresponding functions in Lockon
-- The numbers here correspond to the commands at the end of the original export.lua script
local commands = { 
 view_cockpit         = 7,   view_external        = 8,
 view_flyby           = 9,   view_ground_units    = 10,
 view_civilians       = 11,  view_chase           = 12,
 view_navy            = 13,  view_air_combat      = 14,
 view_theater         = 15,  view_airfield        = 16,

 chat_allies          = 50,  chat_common          = 57,

 acs_altitude_toggle  = 59,  acs_autopilot_toggle = 62,
 acs_thrust_toggle    = 63,

 mech_gear_toggle     = 68,  mech_hook_toggle     = 69,
 mech_wings_toggle    = 70,  mech_canopy_toggle   = 71,
 mech_flaps_toggle    = 72,  mech_flaps_down      = 145,
 mech_flaps_up        = 146, mech_airbrake_toggle = 73,
 mech_airbrake_open   = 147, mech_airbrake_close  = 148,
 mech_wheelbrakes_on  = 74,  mech_wheelbrakes_off = 75,
 mech_chute           = 76,

 refuel_on            = 79,  refuel_off           = 80,
 refuel_probe_toggle  = 155,

 mode_nav             = 105, mode_bvr             = 106,
 mode_vs              = 107, mode_bore            = 108,
 mode_helmet          = 109, mode_fio             = 110,
 mode_ground          = 111, mode_grid            = 112,
 
 kobra                = 121,
 
 engines_both_start   = 309, engines_both_stop    = 310,
 engines_left_start   = 311, engines_left_stop    = 312,
 engines_right_start  = 313, engines_right_stop   = 314,

 master_power_toggle  = 315,

 lights_toggle        = 175,

 jettison_weapons     = 82,  jettison_fueltanks   = 178,
 
 radar_toggle         = 86,
 eos_toggle           = 87
}

Coroutines     = Coroutines or {}
CoroutineIndex = CoroutineIndex or 0

local serverRunning = 0
local origStart     = LuaExportStart
local origStop      = LuaExportStop

function run_server()
 local socket = require("socket")

 local sck = socket.try(socket.bind(host, port))

 if (sck ~= nil) then
   addr, prt = socket.try(sck:getsockname())

   logtofile("Listener started")
   while (serverRunning == 1) do
     socket.try(sck:settimeout(0.01))
     conn, err = sck:accept()
     if conn ~= nil then
       msg, err = conn:receive()
       conn:close()
       if (msg == "END") then
         stop_server = 1
       else
 logtofile("Received: " .. msg .. " --> " .. commands[msg])
        LoSetCommand(commands[msg])
       end -- if
     end -- if
     coroutine.yield()
   end -- while
   sck:close()
   logtofile("Listener stopped")
 end -- if
end -- function

function start_server()
 logtofile("Starting listener")
 serverRunning = 1
 CoroutineIndex = CoroutineIndex + 1
 Coroutines[CoroutineIndex] = coroutine.create(run_server)
 LoCreateCoroutineActivity(CoroutineIndex, 0.0, 0.1)
end

function stop_server()
 logtofile("Stopping listener")
 serverRunning = 0
end
 
function CoroutineResume(index, tCurrent)
coroutine.resume(Coroutines[index], tCurrent)
return coroutine.status(Coroutines[index]) ~= "dead"
end

function LuaExportStart()
 origStart()
 local file = io.open("./Temp/commander.log", "w")
 if file then
  io.output(file)
 end
 start_server()
end

function LuaExportStop()
 logtofile("End")
 stop_server()
 origStop()
end

function logtofile(message)
io.write(message .. "\n")
end
---------------------------------------------------------------------------------------------------
-- End of lockon-commander.lua                                                                   --
---------------------------------------------------------------------------------------------------

 

The sending application makes a connection each time a button is pressed, sends the corresponding command, and closes the connection again.

If this doesn't happen, the lua script will wait until the connection is closed before continuing, thus effectively pause the mission in Lockon.

 

Question to the devs:

 

I found that there is a function to toggle the gear up and down (command 68 ), but are there also separate commands for lowering and raising the gear?

I found that there are separate commands for the airbrake and flaps.

  • Like 2
Dutch Flanker Display Team | LLTM 2010 Tiger Spirit Award
Link to comment
Share on other sites

I built a simple touch-buddy like application on my PDA, to test the possibilities of the script I posted earlier.

I haven't put any energy in making a nice interface, it's just a series of tabs with a bunch of buttons on them, but it works very well :)

There is a slight delay when I push a button on my PDA, which is partly due to the lua script posted above only listening once every 0.1 seconds.

 

The whole application can be set up using a simple xml file, making it very easy to add tabs and buttons.

 

Here are some 'screenshots' of the first test:

 

PICT2140.JPG PICT2142.JPG

PICT2144.JPG PICT2145.JPG

 

The next step will be to try exporting flight data to the PDA, and rendering it there.

Dutch Flanker Display Team | LLTM 2010 Tiger Spirit Award
Link to comment
Share on other sites

Question to the devs:

 

I found that there is a function to toggle the gear up and down (command 68 ), but are there also separate commands for lowering and raising the gear?

 

This gear up and down command is 430 and 431 :thumbup:.

Look part of my code to not block lockon for receive data:

 

-- Creation de coroutines pour LOSIOC

Coroutines = {} -- Tables des coroutines

function CoroutineResume(index, tCurrent)

coroutine.resume(Coroutines[index], tCurrent)

return coroutine.status(Coroutines[index]) ~= "dead"

end

--

function LOSIOCModelTimer(t)

local tNext = t

LOSIOC:StarLOSIOC()

while LOSIOC.InitOK do

if LoGetPlayerPlaneId() then

LOSIOC:ReceptionData()

LOSIOC:SendData()

else

LOSIOC.Retab = true

end

tNext = coroutine.yield()

end

end

-- Declaration des coroutines

Coroutines[1] = coroutine.create(LOSIOCModelTimer)

LoCreateCoroutineActivity(1, 0, 0.05)

 

you can't create server, you can create client to communicate,

for first connexion set : socket.try(sck:settimeout(4000)); delay for wait connexion with your pocket PC

when connection is OK : socket.try(sck:settimeout(0)); no wait, for no block LOCKON.

 

Excuse me for my bad english, I'm french.

 

Link to comment
Share on other sites

This gear up and down command is 430 and 431 :thumbup:.

Look part of my code to not block lockon for receive data:

 

-- Creation de coroutines pour LOSIOC

Coroutines = {} -- Tables des coroutines

function CoroutineResume(index, tCurrent)

coroutine.resume(Coroutines[index], tCurrent)

return coroutine.status(Coroutines[index]) ~= "dead"

end

--

function LOSIOCModelTimer(t)

local tNext = t

LOSIOC:StarLOSIOC()

while LOSIOC.InitOK do

if LoGetPlayerPlaneId() then

LOSIOC:ReceptionData()

LOSIOC:SendData()

else

LOSIOC.Retab = true

end

tNext = coroutine.yield()

end

end

-- Declaration des coroutines

Coroutines[1] = coroutine.create(LOSIOCModelTimer)

LoCreateCoroutineActivity(1, 0, 0.05)

 

you can't create server, you can create client to communicate,

for first connexion set : socket.try(sck:settimeout(4000)); delay for wait connexion with your pocket PC

when connection is OK : socket.try(sck:settimeout(0)); no wait, for no block LOCKON.

 

Excuse me for my bad english, I'm french.

 

So if I understand correctly, you're creating a TCP client in lockon, which reacts to commands pushed to it from a server (e.g. my PDA)?

Dutch Flanker Display Team | LLTM 2010 Tiger Spirit Award
Link to comment
Share on other sites

So if I understand correctly, you're creating a TCP client in lockon, which reacts to commands pushed to it from a server (e.g. my PDA)?

His example is about making the data receiving a co-routine, effectively making it to be executed as another thread.

 

About getting information from Lock On you can talk with Mnemonic, the creator of LO Virtual Panel. He already looks for making the export on PDA. If you could cooperate - it will be very useful for both the products (or the product? :) )

 

I propose to create two applications: a universal multi-threaded "server", which should be "connected" to the game and various "clients" - for sending commands, for displaying data, etc. This will eliminate the problem with pausing.

You want the best? Here i am...

Link to comment
Share on other sites

So if I understand correctly, you're creating a TCP client in lockon, which reacts to commands pushed to it from a server (e.g. my PDA)?

Yes, i use sioc as server to receive commands.

I use IOCP protocol for this.

What language you're use for create PDA program Vc++, c# or other?

Link to comment
Share on other sites

I propose to create two applications: a universal multi-threaded "server", which should be "connected" to the game and various "clients" - for sending commands, for displaying data, etc. This will eliminate the problem with pausing.

It's a good idea, it's my actually project C#. but, each clients don't use the same communication protocol

Link to comment
Share on other sites

  • 3 weeks later...

hi,

I terminate soon a TCP server for export infos and set command from Lockon to several clients in LUA language.

this server can accept 10 clients or more.

The protocol using it's IOCP protocol.

Your client must be a client to connect.

Joe Kurr modifie your application to connect at a server and send the command like this :

To Flaps ON:

socket.send("Arn.Resp:1=145:") -- this is and example, you adapted to your language code

or mail me your code i look at this

 

Lecreole.

 

PS:My english is not perferct, excuse me.

Link to comment
Share on other sites

  • 2 weeks later...
  • 6 months later...

Hopefully I won't make people too mad by re-opening this old thread.

 

This may be just what I've been looking for.

I know zero lua and right now don't have the time to learn it,

but I need a way for my cpp app to be able to send "toggle chat"

command to lockon.

 

I already used simulated keyboard input, but this can cause desync

problems, so I would much rather use lua to call on lockon's own functions.

 

Could I use this script for something like this?

Unfortunately I have no clue how to get it working :). Do you have any

examples of c++ or other language example on how to connect to your lockon

and send a command?

 

Thanks! //Yoda

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Link to comment
Share on other sites

Hey Joe Kurr, you did a great job. I'm not really a computer programmer, what I can tell from the info at hand is that LUA script has the capability of network interfacing, which enables your access through the TCP socket with a PAD.

 

My question is, is it possible to exchange data between Lock On and a peripheral(say like a USB storage device) with LUA script?

 

You said the application only scans the input per 100ms, does it mean despite the type of interface being used?

 

I'm only asking this because I'm trying to build a peripheral which will introduce various interesting functions. This device will not work just as an ordinary keyboard or joystick, but also exchange application-specific data with the software, like extracting map information to an external touchscreen, editing waypoints by hand and feeding it back to Lock On?

 

Here's what I've got:

 

attachment.php?attachmentid=19290&stc=1&d=1221144818

 

On the left is a development board based on the S3C2410 micro processor. It has a TCP port and one USB1.1 device port which can be used to communicate with a PC. As you can see there's also a touchscreen attached to it. That's a 480X272 TFT from SHARP. Very neat indeed. I still have to modify the Linux kernel onboard to light it up properly.

 

On the right is a Cypress CY7C68013A dev board. Which is USB2.0 high speed compatible. With appropriate firmware and well written driver, it can virtually work as anything found in the USB specification. No doubt it's difficult to understand all this, from microcontroller firmware, USB protocol, to driver development and PC programming. Yet I'm working hard on it to make the best out of it.

USB.thumb.jpg.cc62e74fc9eb1aeec790390f1b5979ae.jpg

Link to comment
Share on other sites

I am able to test it now, it works great...except : The open chat window command does not work!

This is command 50 and 57. (allies/all)

 

Sending this command (50 or 57) does nothing at all

 

I was able to open flaps & gear and such, everything else works,

but when I use chat_allies or chat_common nothing happens

 

chat_common should open chat window right? It doesnt do anything for me =/


Edited by =RvE=Yoda

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Link to comment
Share on other sites

Hey Joe Kurr, you did a great job. I'm not really a computer programmer, what I can tell from the info at hand is that LUA script has the capability of network interfacing, which enables your access through the TCP socket with a PAD.

 

My question is, is it possible to exchange data between Lock On and a peripheral(say like a USB storage device) with LUA script?

 

You said the application only scans the input per 100ms, does it mean despite the type of interface being used?

 

I'm only asking this because I'm trying to build a peripheral which will introduce various interesting functions. This device will not work just as an ordinary keyboard or joystick, but also exchange application-specific data with the software, like extracting map information to an external touchscreen, editing waypoints by hand and feeding it back to Lock On?

 

Here's what I've got:

 

[image]

 

On the left is a development board based on the S3C2410 micro processor. It has a TCP port and one USB1.1 device port which can be used to communicate with a PC. As you can see there's also a touchscreen attached to it. That's a 480X272 TFT from SHARP. Very neat indeed. I still have to modify the Linux kernel onboard to light it up properly.

 

On the right is a Cypress CY7C68013A dev board. Which is USB2.0 high speed compatible. With appropriate firmware and well written driver, it can virtually work as anything found in the USB specification. No doubt it's difficult to understand all this, from microcontroller firmware, USB protocol, to driver development and PC programming. Yet I'm working hard on it to make the best out of it.

 

Not everything you describe here can be done with Lockon.

AFAIK you can't edit waypoints while flying a mission.

 

In order to get your hardware to work, I think the easiest way is to write a separate application which interacts with your interface on one end, and communicates to a lua script in Lockon on the other end.

 

The reason I only listen on the network port once every 100ms is simple: the shorter you make this interval, the slower Lockon will run, as the function which listens for network input is blocking, i.e. it holds up everything until it receives a command, or times out.

Dutch Flanker Display Team | LLTM 2010 Tiger Spirit Award
Link to comment
Share on other sites

I am able to test it now, it works great...except : The open chat window command does not work!

This is command 50 and 57. (allies/all)

 

Sending this command (50 or 57) does nothing at all

 

I was able to open flaps & gear and such, everything else works,

but when I use chat_allies or chat_common nothing happens

 

chat_common should open chat window right? It doesnt do anything for me =/

 

Maybe you need to specify the message in the LoSetCommand function call.

Try LoSetCommand(50, "this is a test message") and see if that does anything.

 

I haven't tested this yet, just a guess here ;)

Dutch Flanker Display Team | LLTM 2010 Tiger Spirit Award
Link to comment
Share on other sites

Maybe you need to specify the message in the LoSetCommand function call.

Try LoSetCommand(50, "this is a test message") and see if that does anything.

 

I haven't tested this yet, just a guess here ;)

 

 

no it doesnt work ;)

 

but we have solved the chat problem in another way

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Link to comment
Share on other sites

Not everything you describe here can be done with Lockon.

AFAIK you can't edit waypoints while flying a mission.

 

In order to get your hardware to work, I think the easiest way is to write a separate application which interacts with your interface on one end, and communicates to a lua script in Lockon on the other end.

 

The reason I only listen on the network port once every 100ms is simple: the shorter you make this interval, the slower Lockon will run, as the function which listens for network input is blocking, i.e. it holds up everything until it receives a command, or times out.

 

Thanks a lot Joe, I'll spend more time reviewing the whole thing.

Link to comment
Share on other sites

  • 12 years later...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...