# LX Vario S3 by Benedikt Wolf (D-ECHO) based on # A3XX Lower ECAM Canvas # Joshua Davidson (it0uchpods) # THANKS TO Colin Geniet (SoundPitchController), original developers of the ilec-sc7 (WooT) # Information based on manual http://www.lx-avionik.de/wp/download/manuals/LXS3ManualGermanVer0100.pdf ####################################### ## REQUIRES: ## * second altimeter module enabled from ## * power supply from systems/electrical/outputs/S3 ## (opt) * vario sound set up in the aircraft's sound file (see S3-sound.txt as an example) ##################### ## Version 05/2020 ## ##################### ## Features of this version: ## * use maketimer, only update visible pages ## * use props.nas, store in local variables where sensible ## * store instrument directory in variable ## * clarity through indentation ## * use functions for common functionality ## * clean up listeners var S3_start = nil; var S3_main = nil; var S3_display = nil; var s3 = props.globals.initNode("/instrumentation/s3"); var start_prop = s3.initNode("start", 0.0, "DOUBLE"); var pushknob_prop = s3.initNode("knob-pushed", 0, "BOOL"); var te_rdg = s3.initNode("te-reading-mps", 0.0, "DOUBLE"); var te_avg = s3.initNode("te-average-mps", 0.0, "DOUBLE"); var volume = s3.initNode("volume", 0.5, "DOUBLE"); var alt = props.globals.initNode("instrumentation/altimeter[1]/indicated-altitude-ft", 0.0, "DOUBLE"); var volt_prop = props.globals.initNode("/systems/electrical/outputs/S3", 0.0, "DOUBLE"); var mc = s3.initNode("mc", 1.5, "DOUBLE"); var needle = s3.initNode( "needle-deg", 0.0, "DOUBLE" ); var instrument_dir = "Aircraft/Instruments-3d/glider/vario/S3/"; var canvas_S3_base = { init: func(canvas_group, file) { var font_mapper = func(family, weight) { return "LiberationFonts/LiberationSans-Bold.ttf"; }; canvas.parsesvg(canvas_group, file, {'font-mapper': font_mapper}); var svg_keys = me.getKeys(); foreach(var key; svg_keys) { me[key] = canvas_group.getElementById(key); } me.page = canvas_group; return me; }, getKeys: func() { return []; }, update: func() { var start = start_prop.getDoubleValue(); var volts = volt_prop.getDoubleValue(); if ( start == 1 and volts > 9 ) { S3_start.page.hide(); S3_main.page.show(); S3_main.update(); } else if ( start > 0 and start < 1 and volts > 9 ){ S3_main.page.hide(); S3_start.page.show(); } else { S3_main.page.hide(); S3_start.page.hide(); } }, }; var canvas_S3_main = { new: func(canvas_group, file) { var m = { parents: [canvas_S3_main , canvas_S3_base] }; m.init(canvas_group, file); return m; }, getKeys: func() { return ["altitude","average","average.needle","mccready.needle"]; }, update: func() { #Altimeter me["altitude"].setText( sprintf( "%4d", math.round( alt.getDoubleValue() * FT2M ) ) ); #Average climbrate var av = te_avg.getDoubleValue(); me["average"].setText(sprintf("%2.1f", av)); if(av<5 and av>-5){ var av2=av; }else if(av<-5){ var av2=-5; }else if(av>5){ var av2=5; } me["average.needle"].setRotation(av2*D2R*24); #McCready me["mccready.needle"].setRotation( mc.getDoubleValue()*D2R*24 ); } }; var canvas_S3_start = { new: func(canvas_group, file) { var m = { parents: [canvas_S3_start , canvas_S3_base] }; m.init(canvas_group, file); return m; }, getKeys: func() { return []; }, update: func() { } }; var s3_update = maketimer(0.2, func() { canvas_S3_base.update() } ); s3_update.simulatedTime = 1; var vario_needle_ctrl = func { if( start_prop.getDoubleValue() == 1.0 ){ needle.setDoubleValue( math.clamp( te_rdg.getDoubleValue() * 24, -132, 132 ) ); # max deflection: 132 deg at +- 5.5 m/s } else { needle.setDoubleValue( 0.0 ); } } var needle_update = maketimer( 0.0, vario_needle_ctrl ); needle_update.simulatedTime = 1; var ls = setlistener("sim/signals/fdm-initialized", func { S3_display = canvas.new({ "name": "S3", "size": [320, 240], "view": [320, 240], "mipmapping": 1 }); S3_display.addPlacement({"node": "S3.display"}); var groupMain = S3_display.createGroup(); var groupStart = S3_display.createGroup(); S3_main = canvas_S3_main.new(groupMain, instrument_dir~"S3_main.svg"); S3_start = canvas_S3_start.new(groupStart, instrument_dir~"S3_start.svg"); s3_update.start(); needle_update.start(); removelistener(ls); }); var i=0; var check_off = func () { if( pushknob_prop.getBoolValue() and i<50){ i=i+1; settimer(check_off, 0.1); }else if( pushknob_prop.getBoolValue() and i >= 50){ i=0; start_prop.setDoubleValue( 0.0 ); #put proper shutdown routine here later }else{ i=0; } } var check_electric_off = func () { if( volt_prop.getDoubleValue() < 9.0 and start_prop.getDoubleValue() != 0.0 ){ start_prop.setDoubleValue( 0.0 ); } } setlistener(pushknob_prop, func { if( pushknob_prop.getBoolValue() ) { if( volt_prop.getDoubleValue() >= 9.0 and start_prop.getDoubleValue() == 0.0 ){ interpolate(start_prop, 1, 4 ); } else { check_electric_off(); } check_off(); } }); setlistener(volt_prop, func { check_electric_off(); }); #The following code is based on the ILEC SC7 e-vario and computes the different values shown by the display and the mechanical needle io.include("Aircraft/Generic/soaring-instrumentation-sdk.nas"); #################################### #### INSTRUMENT SETUP #### #################################### # Vario sound pitch controller by Colin Geniet (for ASK21), thanks! # # var vario_sound = SoundPitchController.new( # input: Object connected to the pitch controller input, e.g. a variometer reading. # max_pitch: (optional) Maximum sound frequency factor, the output will be # in the range [1/max_pitch, max_pitch], default 2. # max_input: Value of input for which max_pitch is reached. # on_update: (optional) function to call whenever a new output is available var SoundPitchController = { parents: [InstrumentComponent], new: func(input, max_input, max_pitch = 2, on_update = nil) { return { parents: [me], input: input, max_pitch: max_pitch, max_input: max_input, on_update: on_update, }; }, update: func { var input = math.clamp(me.input.output, -me.max_input, me.max_input); me.output = math.pow(me.max_pitch, input / me.max_input); if (me.on_update != nil) me.on_update(me.output); }, }; var probe = TotalEnergyProbe.new(); var s3_needle = Dampener.new( input: probe, dampening: 1.5, on_update: update_prop("/instrumentation/s3/te-reading-mps"));#1.5 is default dampening value according to POH var averager = Averager.new( input: probe, buffer_size: 20, on_update: update_prop("/instrumentation/s3/te-average-mps")); #20s is default time according to POH var s3_sound = SoundPitchController.new( input: s3_needle, max_input: 5, on_update: update_prop("/instrumentation/s3/sound-pitch")); # Wrap everything together into an instrument var fast_instruments = UpdateLoop.new( update_period: 0, components: [probe, s3_needle, s3_sound], enable: 1); var slow_instruments = UpdateLoop.new( update_period: 1, components: [averager], enable: 1);