Errors when using library files

Help creating logic scripts for Air Manager Instruments

Moderators: russ, Ralph

Post Reply
Message
Author
floatingcub
Posts: 10
Joined: Fri Apr 03, 2020 4:09 am

Errors when using library files

#1 Post by floatingcub »

Hello,

Hoping someone can help unlock a mystery for me.

I've got an annunciator instrument I built which 100% works as expected. In an effort to better organize it, and in preparation to transition to LEDs instead of images, I split related functions out of the main script and created library files. For instance, there are functions specific to alerts for the engine/fuel system; they have all been moved to the engine.lua script.

My mystery revolves around when functions in the library scripts are executed, and how they utilize global variables. Prior to initializing a library file, I fill a variable called plane, which holds various reference data. When I run the instrument, I'm getting errors (attempt to index a nil value, attempt to compare number with nil). The location of the errors are where the library scripts refer to the plane variable. I am also getting errors when I try to reference an image variable that I set prior to initializing the library file. In this latter case, I tried moving the _init statements to the end of the function that loads images, but I still get the error.

Key parts of the logic.lua script:

Code: Select all

-- Define dimensions and location of each light area
dx =
{5,5,5,5,5,5,5,136,136,136,136,136,136,136,270,270,270,270,270,270,270,400,400,400,400,400,400,400,530,530,530,530,530,530,530,660,660,660,660,660,660,660,790,790,790,790,790,790,790}
dy = {14,74,141,207,274,339,405,14,74,141,207,274,339,405,14,74,141,207,274,339,405,14,74,141,207,274,339,405,14,74,141,207,274,339,405,14,74,141,207,274,339,405}
dw = {132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132}
dh = {67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67}

aircraft = {
["M20T"] = {
["vac_press"] = {4.3, 5.2},
["fuel_press"] = {25, 550},
["oil_press"] = {3400, 550},
["throttle"] = 10,
["flap"] = 55,
["alerts"] = {1,2,3,5,6,7,10,11,12,13,14,15,16,17,19,21,24,26,27,28,29,30,31,34,35,38,40,41,42},
["retract"] = true,
}
-- other aircraft omitted for brevity
}

-- To facilitate value access, prepare a variable that will be filled with the appropriate aircraft values
plane = {}

function load_images()
-- Load the lights, but keep them off

if plane.engines == 1 then
img_anun_off = img_add("exp_annun_single_off.png", 0, 0, 800, 480, "stretch")
else
img_anun_off = img_add("exp_annun_multi_off.png", 0, 0, 800, 480, "stretch")
end
img_lit = {}
img_dis = {}

-- Prepare the lighted alerts
for i = 1, 42 do
if plane.engines == 1 then
img_lit[i] = img_add("exp_annun_single.png", 0, 0, 800, 480)
else
img_lit[i] = img_add("exp_annun_multi.png", 0, 0, 800, 480)
end
viewport_rect(img_lit[i], dx[i], dy[i], dw[i], dh[i])
visible(img_lit[i], false)

-- Load the blocking image for alerts that don't apply to the aircraft
if not has_value(i) then
img_dis[i] = img_add("exp_annun_disabled.png", 0, 0, 800, 480)
viewport_rect(img_dis[i], dx[i], dy[i], dw[i], dh[i])
visible(img_dis[i], true)
end
end
end

function has_value(value)
-- Facilitates loading of working vs. disabled annunciator alert images
for i, val in ipairs(plane.alerts) do
if val == value then
return true
end
end
return false
end

function set_aircraft(atc_model, engines, type, center_cap)

model = atc_model
plane = aircraft[model]

if plane == nil then
plane = aircraft["Undefined"]
end
if type == 0 then
plane.type = "piston"
elseif type == 1 then
plane.type = "jet"
elseif type == 5 then
plane.type = "turboprop"
else
plane.type = "unsupported"
end
plane.engines = math.floor(engines)
plane.c_fuel_cap = center_cap

-- Prepare display
load_images()
-- Initialize all systems
electric_init()
engine_init()
switch_init()
mechanical_init()
gear_init()
light_init()
end

fsx_variable_subscribe("ATC MODEL", "String",
"NUMBER OF ENGINES", "Number",
"ENGINE TYPE", "Enum",
"FUEL TANK CENTER CAPACITY", "Gallons", set_aircraft)
Key parts of engine.lua:

Code: Select all

function engine_init()
end

function engine_liteup(fuelpress, oilpress, fuel_level, suction, feathered, autofeather, fire, xfeed)
visible(img_lit[1], fuelpress[1] == 1 or fuelpress[1] == nil)
visible(img_lit[2], oilpress[1] == 1 or oilpress[1] == nil)
visible(img_lit[4], fire == 1)
visible(img_lit[8], fuelpress[2] == 1 or fuelpress[2] == nil)
visible(img_lit[9], oilpress[2] == 1 or oilpress[2] == nil)
visible(img_lit[10], suction == 1)
visible(img_lit[15], fuel_level[1] == 1)
visible(img_lit[22], fuel_level[2] == 1)
visible(img_lit[18], autofeather == 1)
visible(img_lit[29], fuel_level[3] == 1)
visible(img_lit[32], feathered[1] == 1)
visible(img_lit[36], xfeed == 1)
visible(img_lit[39], feathered[2] == 1)
end

function fuel_oil_pressure(type, pressure1, pressure2, rpm1, rpm2)
-- omitted for brevity
end

function annunciate_engine(fuelpress1, fuelpress2, oilpress1, oilpress2,
prop_rpm1, prop_rpm2, n1_rpm1, n1_rpm2,
c_percent, l_percent, r_percent,
fire1, fire2, xfeed, fuel_flow,
suction, feather1, feather2, autofeather1, autofeather2)

if plane.type == "piston" or plane.type == "turboprop" then
rpm1 = prop_rpm1
rpm2 = prop_rpm2
elseif plane.type == "jet" then
rpm1 = n1_rpm1
rpm2 = n1_rpm2
end

-- Fuel Pressure
fuelpress = fuel_oil_pressure("fuel", fuelpress1, fuelpress2, rpm1, rpm2)

-- Oil Pressure
oilpress = fuel_oil_pressure("oil", oilpress1, oilpress2, rpm1, rpm2)

-- Fuel Quantity
-- Alarm at <10%
fuel_level = {0, 0, 0}
fuel_level[1] = fif(l_percent < 10, 1, 0)
fuel_level[3] = fif(r_percent < 10, 1, 0)
if plane.c_fuel_cap > 0 then
fuel_level[2] = fif(c_percent < 10, 1, 0)
end

-- filling other variables here, omitted for brevity --
--[...]
-- using the variables next --
if power() and startup == false then engine_liteup(fuelpress, oilpress, fuel_level, suction, {pitch1, pitch2}, autofeather, fire, xfeed) end
end

fsx_variable_subscribe(
"GENERAL ENG FUEL PRESSURE:1", "Psi",
"GENERAL ENG FUEL PRESSURE:2", "Psi",
"GENERAL ENG OIL PRESSURE:1", "Psf",
"GENERAL ENG OIL PRESSURE:2", "Psf",
"PROP RPM:1", "Rpm",
"PROP RPM:2", "Rpm",
"ENG N1 RPM:1", "Rpm",
"ENG N1 RPM:2", "Rpm",
"FUEL TANK CENTER LEVEL", "Percent",
"FUEL TANK LEFT MAIN LEVEL", "Percent",
"FUEL TANK RIGHT MAIN LEVEL", "Percent",
"ENGINE ON FIRE:1", "Bool",
"ENGINE ON FIRE:2", "Bool",
"FUEL CROSS FEED", "Enum",
"RECIP ENG FUEL TANK SELECTOR:1", "Enum",
"SUCTION PRESSURE", "inHg",
"PROP BETA:1", "Radians",
"PROP BETA:2", "Radians",
"PROP AUTO FEATHER ARMED:1", "Bool",
"PROP AUTO FEATHER ARMED:2", "Bool",
annunciate_engine
)
I simply don't understand why Air Manager is executing a function inside a script that I have not yet initialized (if that is what is happening), or why variables which are set before initialization don't appear to be visible.

Any guidance here would be appreciated.

-Bryan

floatingcub
Posts: 10
Joined: Fri Apr 03, 2020 4:09 am

Re: Errors when using library files

#2 Post by floatingcub »

Nevermind, I just found this on the wiki (http://siminnovations.com/wiki/index.ph ... _libraries):
When the instrument is started, your library lua files will be executed first, followed by the logic.lua.
Given this, I will have to think hard about how the use of libraries is beneficial or even possible in this case, since I can't access variables in any consistent, desirable way. Or maybe there is just something that I'm missing here.

-Bryan

User avatar
Sling
Posts: 5237
Joined: Mon Sep 11, 2017 2:37 pm
Contact:

Re: Errors when using library files

#3 Post by Sling »

Hi Bryan,

It’s not a mystery I can assure. Let me explain.

First some facts to take into account.

The library file run order is random.
The logic.lua file will always be run last. i.e. always after the library files.
This is stated on the libraries wiki page.

So with this information in mind and looking at your code we can see that the lib file runs first and the subscribe callback triggers. The callback references variables that are not yet declared because you declare them in the logic.lua. This is why they are nil. There are a few ways to solve this but in my experience it’s always best to hold off doing your subscribes until last when working with more complex instruments that use lib files. The subscribes can stay in lib files but wrap them in a function and call it once at the end of logic.lua. A tiny change to your code.

I hope that helps. Let us know how you go.

Tony

User avatar
Sling
Posts: 5237
Joined: Mon Sep 11, 2017 2:37 pm
Contact:

Re: Errors when using library files

#4 Post by Sling »

Oops looks like we cross posted. I see you found the wiki info. Read my other post for an easy solution.

floatingcub
Posts: 10
Joined: Fri Apr 03, 2020 4:09 am

Re: Errors when using library files

#5 Post by floatingcub »

Thanks Tony. A quick change, as you suggested, and I see that it works now.

On a related note, what is the trick to posting code here so the interpreter doesn't add a space between each line? In my initial post I chose LUA from the 'Select code' dropdown in the editor.

-Bryan

User avatar
Sling
Posts: 5237
Joined: Mon Sep 11, 2017 2:37 pm
Contact:

Re: Errors when using library files

#6 Post by Sling »

Glad you got it going and learnt something to boot.

I think the code posting method you used tends to do that unfortunately. I tend not to use it, but the alternative. Don't use the 'select code' drop down but instead hit the </> button and paste your code between the inserted tags.

It looks like this.

Code: Select all

--code line 1
--code line 2
--code line 3

floatingcub
Posts: 10
Joined: Fri Apr 03, 2020 4:09 am

Re: Errors when using library files

#7 Post by floatingcub »

Code: Select all

Perfect, thanks!
;)

-Bryan

Post Reply