|
Post by MarkH on Jul 5, 2015 20:21:09 GMT
For LINDA users, I have written a function that scans all of the switches on all of the joysticks you have connected and determines whether each switch is ON or OFF. It then calls the Lua functions you have associated with those switches in LINDA. This ensures that your FSX aircraft is in sync with your switches. It seems to work pretty well for me, so I am uploading it here for people to try out. To use this, just download the file and put it in your fsx\modules\linda\libs folder, then you can call the function, SYNC_Aircraft_To_Switch_Settings(), by linking it to a button. The only thing to note is that this will never call any LINDA Lua function with the word 'toggle' in its name. [For guests, you will not be able to download the attachment. Instead you can create the file yourself from the text posted in the next message.]Attachments:lib-sync.lua (8.88 KB)
|
|
|
Post by MarkH on Jul 7, 2015 17:21:27 GMT
This is the text of the file. Paste this into a file named lib-sync.lua and put it in your fsx\modules\linda\libs folder.
(Updated - the DisplayMsg functions didn't work properly!)
-- ------------------------------------------------------------------------------------------------- -- FSX synchronisation with hardware panels -- ---------------------------------------- -- -- v1.1, July 8th 2015 -- by Mark Hurst -- www.almostaviation.com -- -- This function interrogates every switch for its current setting and then invokes the -- Lua function bound to that switch. The result is as if we had actually moved the switch -- into the position we find it in, and this usually suffices to synchronise FSX and the -- switches. Note that this does not guarantee the final state of the aircraft, it just -- sets the position of the switches. -- -- To do this we need to be able to identify and talk to each joystick connected. Thankfully -- LINDA has already done some of the work for us and we'll find details of all the joysticks -- just waiting for us to play with. -- -- LINDA identifies and addresses joysticks (HIDs) using the Vendor, Product and Unit ids. -- The first two are 4-digit hexadecimal numbers (format %04x). The Unit id is a hexadecimal -- number (format %x) appended to distinguish multiple devices of the same type (for example, -- Leo Bodnar boards). The three values are stored internally as a string with all three values -- in sequence, so it usually looks like a 9-digit hex number (e.g. on my system, 1DD211400 and -- 1DD211402 are the first and third Leo Bodnar BBI-32 boards enumerated by the Lua COM library -- functions.) -- -- LINDA helpfully maintains data structures that associate all the buttons of all the joysticks -- with the functions we have programmed. These are in the tables JSTK for the button-down actions -- and JSTKrl for the button-up actions. A Lua table is an associative array, so JSTK and JSTKrl -- are indexed on the joystick id (one of those 9-digit strings). Each entry in JSTK and JSTKrl -- is another table of 32 functions. (We can access this table with numeric indices, just like a -- regular array.) So here's how a portion of one of the tables might look: -- -- JSTK["1DD211402"][1] = TW_LandingLights_ON -- JSTK["1DD211402"][2] = TW_SetParkingBrake -- JSTK["1DD211402"][3] = TW_SetControlLocks -- ... -- JSTK["1DD211402"][32] = TW_BleedAirLeftON -- -- Changes -- ------- -- -- v1.1 -- Corrected problems with the DisplayMsg functions. -- -- -------------------------------------------------------------------------------------------------
local function DisplayMsgWindow(Title) -- Title, x, y, width and height (as % of display width and height). ipc.setowndisplay(Title, 34.55, 0, 20, 2.5) end
-- This moves the window off-screen. local function HideMsgWindow(Title) -- Title has to match the title we opened the window with! ipc.setowndisplay(Title, 100, 0, 20, 2.5) end
local function DisplayMsg(Message) ipc.display(Message) end
function SYNC_Aircraft_To_Switch_Settings()
local StartTime = os.clock()
-- We'll very likely have this function bound to a button, in which case -- we may get a re-entrant call to it!
if ReentryProtect == 1 then ipc.log("Aborting RE-ENTRANT call to Sync function!") return else ReentryProtect = 1 end
-- This takes a while, so let the user know we're doing something. DisplayMsg -- displays a window at the top of the screen.
DisplayMsgWindow("Scanning switches...")
ipc.log("Scanning switches...")
local VID -- These three are derived from the joystick ids in JSTK and JSTKrl local PID local UID
-- We're going to scan all the joysticks to see which switches (a.k.a. buttons) -- are currently set and which are unset, noting in each case what function is bound -- to the corresponding 'on press' or 'on release' action. We save these functions -- in the two tables defined below. -- -- Each entry in the tables we are building is itself a two-element table containing -- the joystick id and the function (e.g. {"1DD211402", TW_BleedAirLeftON}). (We need -- to keep the joystick name associated with the function because we need to supply it as -- a parameter when we call the function.)
local Switch_ON_Actions = {} local Switch_OFF_Actions = {}
local SwitchStates -- Holds a 32-bit bitmap of the buttons read from a HID
-- The JSTK table has a complete list of the joysticks connected. We'll step through -- the table and interrogate each joystick in turn.
for Stick, v in pairs(JSTK) do
VID = tonumber(string.sub(Stick,1,4), 16) PID = tonumber(string.sub(Stick,5,8), 16) UID = tonumber(string.sub(Stick,9))
--ipc.log(string.format("Joystick %s", Stick))
DevHandle, DataLen, wrf, wr, init = com.openhid(VID, PID, UID, 0)
if DevHandle == 0 then -- If we couldn't open the HID we just skip it --ipc.log(" (Could not open HID)") else DisplayMsg("Joystick " .. tostring(Stick)) DataBytes, NumBytes = com.readlast(DevHandle, DataLen)
if NumBytes ~= 0 then SwitchStates = com.gethidbuttons(DevHandle, DataBytes) -- Now we have the switch states for this joystick in a bitmap. We just -- step through each one and check the switch state.
for Switch = 0, 31, 1 do
if logic.And(SwitchStates, 2^Switch) == 0 then -- We need the button-release function. It is nil if no action has -- been associated with this button action in the LINDA GUI. Funct = JSTKrl[Stick][Switch + 1] if Funct ~= nil then --ipc.log(" Switch " .. Switch + 1 .. " is OFF - Bound to function " .. tostring(Funct)) --DisplayMsg("OFF " .. tostring(Funct)) table.insert(Switch_OFF_Actions, {Stick, Funct}) else --ipc.log(" Switch " .. Switch + 1 .. " is OFF (no function bound)") end else -- We need the button-down function. It is nil if no action has -- been associated with this button action in the LINDA GUI. Funct = JSTK[Stick][Switch + 1] if Funct ~= nil then --ipc.log(" Switch " .. Switch + 1 .. " is ON - Bound to function " .. tostring(Funct)) --DisplayMsg("ON " .. tostring(Funct)) table.insert(Switch_ON_Actions, {Stick, Funct}) else --ipc.log(" Switch " .. Switch + 1 .. " is ON (no function bound)") end end end -- Switches loop end com.close(DevHandle) end end --Joystick loop
-- We have all the functions we need to call. Now we need to call them to synchronise the -- aircraft in FSX with the state of our physical switches. We could have called these functions -- as we determined them, rather than saving them in tables, but it makes a difference in which -- order we call them. Specifically, for ON-OFF-ON and ON-ON-ON switches we always call two different -- OFF functions and one ON function. If we get these the wrong way around, the switch ends up set -- incorrectly in FSX. To cut a long story short, we call all the OFF functions first, followed by -- all the ON functions and this works out. -- -- We also encounter problems with functions that toggle a setting whenever a button is pressed. -- These are typically simple push-buttons but sometimes we also have a switch or latching push-button -- with a toggle function bound to both the press and release action. There is no logical way to relate -- the state of the switch in either case to the FSX function and hence it makes no sense ever to call -- these functions from here. We rely on the observation that such functions usually have the word -- 'toggle' somewhere in the name, which allows us to skip them. -- [TODO: we could also spot when the same function is mapped to the ON and OFF actions, which is -- almost certainly a toggle function.]
DisplayMsgWindow("Setting OFF actions") DisplayMsg("Setting OFF actions")
--ipc.log("OFF actions:") for Fun = 1, #Switch_OFF_Actions, 1 do Funct = Switch_OFF_Actions[Fun][2] if string.find(string.lower(tostring(Funct)), "toggle") ~= nil then --ipc.log(" " .. tostring(Switch_OFF_Actions[Fun][1]) .. ", [--" .. tostring(Funct) .. "--]") else --ipc.log(" " .. tostring(Switch_OFF_Actions[Fun][1]) .. ", " .. tostring(Funct)) DisplayMsg(tostring(Funct)) buttonExecute(Switch_OFF_Actions[Fun][1], Switch_OFF_Actions[Fun][2]) end end
DisplayMsgWindow("Setting ON actions") DisplayMsg("Setting ON actions") --ipc.log("ON actions:")
for Fun = 1, #Switch_ON_Actions, 1 do Funct = Switch_ON_Actions[Fun][2] if string.find(string.lower(tostring(Funct)), "toggle") ~= nil then --ipc.log(" " .. tostring(Switch_ON_Actions[Fun][1]) .. ", [--" .. tostring(Funct) .. "--]") else --ipc.log(" " .. tostring(Switch_ON_Actions[Fun][1]) .. ", " .. tostring(Funct)) DisplayMsg(tostring(Funct)) buttonExecute(Switch_ON_Actions[Fun][1], Switch_ON_Actions[Fun][2]) end end
ReentryProtect = 0
HideMsgWindow("Setting OFF actions")
ipc.log(string.format("Elapsed time = %d seconds", os.clock() - StartTime)) end
|
|
|
Post by Pete on Jul 9, 2015 0:19:51 GMT
Do I need Linda to use this?
Pete
|
|
|
Post by MarkH on Jul 9, 2015 6:45:18 GMT
Do I need Linda to use this? Yes! Sorry, I probably should have said that
|
|
|
Post by MarkR on Nov 24, 2015 14:44:54 GMT
Just found a link to this from FLYUK forums. This is brilliant thank you so much
|
|
|
Post by MarkH on Nov 24, 2015 17:54:51 GMT
Just found a link to this from FLYUK forums. This is brilliant thank you so much No problem, let us know if it works for you. I got a bit stuck trying to do the analogue inputs though
|
|