1
0
Fork 0

Updated DualControl: Moved everything to Aircraft/Generic/DualControl/.

- Updated all references to Aircraft/ZLT-NT/DualControl/ found.
This commit is contained in:
Anders Gidenstam 2010-12-19 23:09:53 +01:00
parent edc9b64e6c
commit 09dc9afe47
40 changed files with 17590 additions and 0 deletions

View file

@ -0,0 +1,22 @@
Anders Gidenstam (anders(at)gidenstam.org)
- Dual control Nasal modules
- Configuration of dual-control 3d instruments.
DualControl borrows content from the following authors' contributions
to FlightGear:
Syd Adams - from Aircraft/Instruments-3d/
- KY-196 Comm Radio.
- VHF 22 Comm Radio.
- VIR 32 Nav Radio.
- KI-206 VOR Gauge.
- KR-97 ADF Radio.
- KI-227 ADF Gauge.
Torsten Dreyer - from Aircraft/SenceaII/Instruments-3d/
- KX-165 Nav Comm Radio.
- KR-87 ADF Radio.
Ron Jensen - from Aircraft/Instruments-3d
- KAP140 Autopilot 3d.

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1,380 @@
<?xml version="1.0"?>
<!-- CTL 62 ADF Control for ADF-462 receiver
Active and preset displayed +
4 frequency memory storage
2.375"W x 2.625"H
Freq. range 190.0 - 1800.0 (normal)
Strap option 2179.0 - 2185.0
500 khz spacing
Syd Adams
Adapted for dual control by Anders Gidenstam
NOTE: ctl62.nas MUST be loaded as Nasal module ADF462.
-->
<PropertyList>
<path>ctl62.ac</path>
<animation>
<type>select</type>
<object-name>freq.002</object-name>
<object-name>freq.003</object-name>
<object-name>freq.dec</object-name>
<object-name>freq.004</object-name>
<object-name>freq.005</object-name>
<condition>
<greater-than>
<property>systems/electrical/outputs/adf</property>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>stby.002</object-name>
<object-name>stby.003</object-name>
<object-name>stby.dec</object-name>
<object-name>stby.004</object-name>
<object-name>stby.005</object-name>
<condition>
<greater-than>
<property>systems/electrical/outputs/adf</property>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>freq.001</object-name>
<condition>
<and>
<greater-than>
<property>systems/electrical/outputs/adf</property>
<value>1</value>
</greater-than>
<greater-than>
<property>instrumentation/adf/frequencies/selected-khz</property>
<value>999.5</value>
</greater-than>
</and>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>stby.001</object-name>
<condition>
<and>
<greater-than>
<property>systems/electrical/outputs/adf</property>
<value>1</value>
</greater-than>
<greater-than>
<property>instrumentation/adf/frequencies/standby-khz</property>
<value>999.5</value>
</greater-than>
</and>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>mem.annun</object-name>
<condition>
<greater-than>
<property>systems/electrical/outputs/adf</property>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>rotate</type>
<object-name>CTL-62.pwr</object-name>
<property>instrumentation/adf/serviceable</property>
<interpolation>
<entry><ind>0</ind><dep>0</dep></entry>
<entry><ind>1.0</ind><dep>30</dep></entry>
</interpolation>
<center>
<x-m>0.0</x-m>
<y-m>-0.014</y-m>
<z-m>-0.018</z-m>
</center>
<axis>
<x>-1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- Active Frequency -->
<animation>
<type>textranslate</type>
<object-name>freq.001</object-name>
<property>instrumentation/adf/frequencies/selected-khz</property>
<factor>0.0001</factor>
<step>1000</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.002</object-name>
<property>instrumentation/adf/frequencies/selected-khz</property>
<factor>0.001</factor>
<step>100</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.003</object-name>
<property>instrumentation/adf/frequencies/selected-khz</property>
<factor>0.01</factor>
<step>10</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.004</object-name>
<property>instrumentation/adf/frequencies/selected-khz</property>
<factor>0.1</factor>
<step>1</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.005</object-name>
<property>instrumentation/adf/frequencies/selected-khz</property>
<factor>1.0</factor>
<step>0.1</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<!-- Preselected Frequency -->
<animation>
<type>textranslate</type>
<object-name>stby.001</object-name>
<property>instrumentation/adf/frequencies/standby-khz</property>
<factor>0.0001</factor>
<step>1000</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.002</object-name>
<property>instrumentation/adf/frequencies/standby-khz</property>
<factor>0.001</factor>
<step>100</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.003</object-name>
<property>instrumentation/adf/frequencies/standby-khz</property>
<factor>0.01</factor>
<step>10</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.004</object-name>
<property>instrumentation/adf/frequencies/standby-khz</property>
<factor>0.1</factor>
<step>1</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.005</object-name>
<property>instrumentation/adf/frequencies/standby-khz</property>
<factor>1.0</factor>
<step>0.1</step>
<bias>0.05</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<!-- OSG hotspots -->
<animation>
<type>pick</type>
<object-name>CTL-62.xfr</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>ADF462.swap(0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>pwr.off</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>property-assign</command>
<property>instrumentation/adf/serviceable</property>
<value>false</value>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>pwr.on</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>property-assign</command>
<property>instrumentation/adf/serviceable</property>
<value>true</value>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>freq.knob.small</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, 1.0);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, 1.0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>freq.knob.large</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, 10.0);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, -10.0);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, -10.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>ADF462.adjust_frequency(0, 10.0);</script>
</binding>
</action>
</animation>
</PropertyList>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,229 @@
###############################################################################
##
## Nasal for dual control of a ADF 462 radio over the multiplayer
## network.
##
## Copyright (C) 2008 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Note:
# This module MUST be loaded as ADF462.
#
# Slave button presses.
var swap_btn = "frq-swap-btn";
var freq_decS = "freq-decS-clicked";
var freq_incS = "freq-incS-clicked";
var freq_decL = "freq-decL-clicked";
var freq_incL = "freq-incL-clicked";
# Settings
var freq_selected = "frequencies/selected-khz";
var freq_standby = "frequencies/standby-khz";
var adf_base = ["instrumentation/adf[0]",
"instrumentation/adf[1]"];
###########################################################################
var master_ctl62 = {
new : func(n) {
var obj = {};
obj.parents = [master_ctl62];
obj.adf_base = props.globals.getNode(adf_base[n]);
return obj;
},
swap : func() {
var tmp = me.adf_base.getNode(freq_selected).getValue();
me.adf_base.getNode(freq_selected).setValue
(me.adf_base.getNode(freq_standby).getValue());
me.adf_base.getNode(freq_standby).setValue(tmp);
},
adjust_frequency : func(d) {
adjust_radio_frequency(
me.adf_base.getNode(freq_standby),
d,
190.0,
1800.0);
}
};
###########################################################################
var slave_ctl62 = {
new : func(n, airoot) {
var obj = {};
obj.parents = [slave_ctl62];
obj.root = airoot;
obj.adf_base = props.globals.getNode(adf_base[n]);
return obj;
},
swap : func() {
var p = me.adf_base.getNode(swap_btn);
print("ADF62[?].SWAP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
adjust_frequency : func(d) {
var p = 0;
if (abs(d) < 5.0) {
p = (d < 0) ? me.adf_base.getNode(freq_decS)
: me.adf_base.getNode(freq_incS);
} else {
p = (d < 0) ? me.adf_base.getNode(freq_decL)
: me.adf_base.getNode(freq_incL);
}
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
}
};
###########################################################################
# The ADF 462 pick animations default to master.
# NOTE: Use make_master() and make_slave_to().
# Do NOT change ctl62 directly.
var ctl62 = [master_ctl62.new(0), master_ctl62.new(1)];
###########################################################################
# API for pick animations and dual control setup.
###########################################################################
###########################################################################
# n - Adf#
var make_master = func(n) {
ctl62[n] = master_ctl62.new(n);
}
###########################################################################
# n - Adf#
var make_slave_to = func(n, airoot) {
ctl62[n] = slave_ctl62.new(n, airoot);
}
###########################################################################
# n - Adf#
var swap = func(n) {
ctl62[n].swap();
}
###########################################################################
# n - Adf#
# d - adjustment
var adjust_frequency = func(n, d) {
ctl62[n].adjust_frequency(d);
}
###########################################################################
# Create aliases to drive a radio 3d model in an AI/MP model.
# n - Adf#
var animate_aimodel = func(n, airoot) {
var p = "systems/electrical/outputs/adf["~ n ~"]";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = "instrumentation/adf["~ n ~"]/serviceable";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = adf_base[n] ~ "/" ~ freq_selected;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = adf_base[n] ~ "/" ~ freq_standby;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
}
###########################################################################
# Create a TDMEncoder node array for sending the current radio state to
# slaves.
# n - Adf#
var master_send_state = func(n) {
var b = props.globals.getNode(adf_base[n]);
return
[
b.getNode(freq_selected),
b.getNode(freq_standby)
];
}
###########################################################################
# Create a SwitchDecoder action array for processing button presses
# from a slave.
# n - Adf#
var master_receive_slave_buttons = func(n) {
return
[
func (b) {
if (b) { swap(n); }
},
func (b) {
if (b) { adjust_frequency(n, -1.0); }
},
func (b) {
if (b) { adjust_frequency(n, 1.0); }
},
func (b) {
if (b) { adjust_frequency(n, -10.0); }
},
func (b) {
if (b) { adjust_frequency(n, 10.0); }
}
];
}
###########################################################################
# Create a TDMDecoder action array for processing the radio state
# from the master.
# n - Adf#
var slave_receive_master_state = func(n) {
var b = props.globals.getNode(adf_base[n]);
return
[
func (v) {
b.getNode(freq_selected).setValue(v);
},
func (v) {
b.getNode(freq_standby).setValue(v);
}
];
}
###########################################################################
# Create a SwitchEncoder node array for sending button presses
# to the master
# n - Adf#
var slave_send_buttons = func(n) {
var b = props.globals.getNode(adf_base[n]);
return
[
b.getNode(swap_btn, 1),
b.getNode(freq_decS, 1),
b.getNode(freq_incS, 1),
b.getNode(freq_decL, 1),
b.getNode(freq_incL, 1),
];
}
###########################################################################
# (Not so) Generic frequency stepper.
# f - frequency property
# d - change
# min - min frequency
# max - max frequency
var adjust_radio_frequency = func(f, d, min, max) {
var old = f.getValue();
var new = old + d;
if (new < min - 0.05) {
new = max + (new - min);
if ((max - new) >= -d) new += -d;
}
if (new > max + 0.05) {
new = min + (new - max);
if ((new - min) >= d) new -= d;
}
# print("Old: " ~ old ~ " Intermediate: " ~ (old + d) ~ " New: " ~ new);
f.setValue(new);
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<PropertyList>
<path>null.ac</path> <!-- A suitably empty AC3D file. -->
<model>
<path>Aircraft/Instruments-3d/kap140/KAP140TwoAxisAlt.xml</path>
</model>
<!-- Override OSG Hotspots for dual control -->
<!-- Not even needed at this stage. -->
</PropertyList>

View file

@ -0,0 +1,330 @@
###############################################################################
##
## Nasal for dual control of a KAP 140 autopilot over the multiplayer
## network.
##
## Copyright (C) 2008 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Note:
# This module MUST be loaded as kap140.
#
# Load the real KAP 140 module as kap140_implementation.
if (!contains(globals, "kap140_implementation")) {
io.load_nasal(getprop("/sim/fg-root") ~
"/Aircraft/Generic/kap140.nas",
"kap140_implementation");
}
# Slave button presses.
var ap_btn = "ap-btn";
var hdg_btn = "hdg-btn";
var nav_btn = "nav-btn";
var apr_btn = "apr-btn";
var alt_btn = "alt-btn";
var rev_btn = "rev-btn";
var down_btn = "down-btn";
var up_btn = "up-btn";
var arm_btn = "arm-btn";
var baro_press_btn = "baro-press-btn";
var baro_release_btn = "baro-release-btn";
var base = "autopilot/kap140/";
var buttons = base ~ "buttons/";
###############################################################################
# API function wrappers.
var apButton = func {
kap140.apButton();
}
var hdgButton = func {
kap140.hdgButton();
}
var navButton = func {
kap140.navButton();
}
var aprButton = func {
kap140.aprButton();
}
var altButton = func {
kap140.altButton();
}
var revButton = func {
kap140.revButton();
}
var downButton = func {
kap140.downButton();
}
var upButton = func {
kap140.upButton();
}
var armButton = func {
kap140.armButton();
}
var baroButtonPress = func {
kap140.baroButtonPress();
}
var baroButtonRelease = func {
kap140.baroButtonRelease();
}
var knobSmallDown = func {
kap140.knobSmallDown();
}
var knobSmallUp = func {
kap140.knobSmallUp();
}
var knobLargeDown = func {
kap140.knobLargeDown();
}
var knobLargeUp = func {
kap140.knobLargeUp();
}
###############################################################################
###########################################################################
# The master is just the standard implementation.
var master_kap140 =
contains(globals, "kap140_implementation") ? kap140_implementation : nil;
###########################################################################
var slave_kap140 = {
new : func(airoot) {
var obj = {};
obj.parents = [slave_kap140];
obj.root = airoot;
obj.base = props.globals.getNode("/autopilot/kap140/buttons", 1);
return obj;
},
apButton : func {
var p = me.base.getNode(ap_btn);
print("KAP140.AP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
hdgButton : func {
var p = me.base.getNode(hdg_btn);
print("KAP140.HDG");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
navButton : func {
var p = me.base.getNode(nav_btn);
print("KAP140.NAV");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
aprButton : func {
var p = me.base.getNode(apr_btn);
print("KAP140.APR");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
altButton : func {
var p = me.base.getNode(alt_btn);
print("KAP140.ALT");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
revButton : func {
var p = me.base.getNode(rev_btn);
print("KAP140.REV");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
downButton : func {
var p = me.base.getNode(down_btn);
print("KAP140.DN");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
upButton : func {
var p = me.base.getNode(up_btn);
print("KAP140.UP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
armButton : func {
var p = me.base.getNode(arm_btn);
print("KAP140.ARM");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
baroButtonPress : func {
var p = me.base.getNode(baro_press_btn);
print("KAP140.BARO_PRESS");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
baroButtonRelease : func {
var p = me.base.getNode(baro_release_btn);
print("KAP140.BARO_RELEASE");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
knobSmallDown : func {
},
knobSmallUp : func {
},
knobLargeDown : func {
},
knobLargeUp : func {
},
};
###########################################################################
# The KAP140 pick animations default to master.
var kap140 = master_kap140;
###########################################################################
# API for dual control setup.
###########################################################################
###########################################################################
var make_master = func {
master_kap140 =
contains(globals, "kap140_implementation") ? kap140_implementation : nil;
}
###########################################################################
var make_slave_to = func(airoot) {
kap140 = slave_kap140.new(airoot);
}
###########################################################################
# Create aliases to drive the KAP 140 3d model in an AI/MP model.
var animate_aimodel = func(airoot) {
# var p = base ~ "/data-is-valid";
# airoot.getNode(p, 1).alias(props.globals.getNode(p));
}
###########################################################################
# Create a TDMEncoder node array for sending the current state to
# slaves.
var master_send_state = func {
return
[
];
}
###########################################################################
# Create a SwitchDecoder action array for processing button presses
# from a slave.
var master_receive_slave_buttons = func {
return
[
func (b) {
if (b) { kap140.apButton(); }
},
func (b) {
if (b) { kap140.hdgButton(); }
},
func (b) {
if (b) { kap140.navButton(); }
},
func (b) {
if (b) { kap140.aprButton(); }
},
func (b) {
if (b) { kap140.altButton(); }
},
func (b) {
if (b) { kap140.revButton(); }
},
func (b) {
if (b) { kap140.downButton(); }
},
func (b) {
if (b) { kap140.upButton(); }
},
func (b) {
if (b) { kap140.armButton(); }
},
func (b) {
if (b) { kap140.baroButtonPress(); }
},
func (b) {
if (b) { kap140.baroButtonRelease(); }
}
];
}
###########################################################################
# Create a TDMDecoder action array for processing the state
# from the master.
var slave_receive_master_state = func {
return
[
];
}
###########################################################################
# Create a SwitchEncoder node array for sending button presses
# to the master
var slave_send_buttons = func {
return
[
props.globals.getNode(buttons ~ ap_btn, 1),
props.globals.getNode(buttons ~ hdg_btn, 1),
props.globals.getNode(buttons ~ nav_btn, 1),
props.globals.getNode(buttons ~ apr_btn, 1),
props.globals.getNode(buttons ~ alt_btn, 1),
props.globals.getNode(buttons ~ rev_btn, 1),
props.globals.getNode(buttons ~ down_btn, 1),
props.globals.getNode(buttons ~ up_btn, 1),
props.globals.getNode(buttons ~ arm_btn, 1),
props.globals.getNode(buttons ~ baro_press_btn, 1),
props.globals.getNode(buttons ~ baro_release_btn, 1)
];
}

View file

@ -0,0 +1,3 @@
AC3Db
OBJECT poly
kids 0

View file

@ -0,0 +1,823 @@
AC3Db
MATERIAL "DefaultWhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 spec 0.5 0.5 0.5 shi 64 trans 0
MATERIAL "illum" rgb 1 1 1 amb 1 1 1 emis 0.7 0.7 0.7 spec 0 0 0 shi 0 trans 0
MATERIAL "glosswhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 spec 0.255556 0.255556 0.255556 shi 32 trans 0
MATERIAL "flatpaint" rgb 0.8 0.8 0.8 amb 0.8 0.8 0.8 emis 0.051361 0.051361 0.051361 spec 0 0 0 shi 32 trans 0
OBJECT world
kids 13
OBJECT poly
name "DME.kt1"
data 9
Plane.145
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 0.002169
0.001016 0.002312 0.002169
0.001016 0.002312 0.007201
0.001016 0.011226 0.007201
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DME.kt2"
data 9
Plane.146
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 -0.003798
0.001016 0.002312 -0.003798
0.001016 0.002312 0.001234
0.001016 0.011226 0.001234
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DME.kt3"
data 9
Plane.147
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 -0.009766
0.001016 0.002312 -0.009766
0.001016 0.002312 -0.004733
0.001016 0.011226 -0.004733
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DME.mn1"
data 9
Plane.149
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 -0.024916
0.001016 0.002312 -0.024916
0.001016 0.002312 -0.019884
0.001016 0.011226 -0.019884
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DME.mn2"
data 9
Plane.148
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 -0.030883
0.001016 0.002312 -0.030883
0.001016 0.002312 -0.025851
0.001016 0.011226 -0.025851
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DME.nm"
data 9
Plane.150
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.000959 0.003707 0.022752
0.000959 0.002877 0.022752
0.000959 0.002877 0.023547
0.000959 0.003707 0.023547
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0709507837892 0.181225210428
3 0.0457188934088 0.181225210428
2 0.0457188934088 0.166461586952
1 0.0709507837892 0.166461586952
kids 0
OBJECT poly
name "DME.nm1"
data 9
Plane.131
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 0.02914
0.001016 0.002312 0.02914
0.001016 0.002312 0.034172
0.001016 0.011226 0.034172
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DME.nm2"
data 9
Plane.143
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 0.023676
0.001016 0.002312 0.023676
0.001016 0.002312 0.028708
0.001016 0.011226 0.028708
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DME.nm3"
data 9
Plane.151
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 4
0.001016 0.011226 0.017181
0.001016 0.002312 0.017181
0.001016 0.002312 0.022214
0.001016 0.011226 0.022214
numsurf 1
SURF 0x00
mat 1
refs 4
0 0.0838298201561 0.199461504817
3 0.0236648730934 0.199461504817
2 0.0236648730934 0.00404679775238
1 0.0838298201561 0.00404679775238
kids 0
OBJECT poly
name "DMEswitch"
data 8
Cylinder
texture "dme.png"
texrep 1 1
crease 40.000000
numvert 28
0.001039 -0.006427 0.003573
0.001039 -0.005119 0.001308
0.001039 -0.005119 -0.001308
0.001039 -0.006427 -0.003573
0.001039 -0.008692 -0.004881
0.001039 -0.011308 -0.004881
0.001039 -0.013573 -0.003573
0.001039 -0.014881 -0.001308
0.001039 -0.014881 0.001308
0.001039 -0.013573 0.003573
0.001039 -0.011308 0.004881
0.001039 -0.008692 0.004881
0.004499 -0.006686 0.003314
0.004499 -0.005473 0.001213
0.004499 -0.005473 -0.001213
0.004499 -0.006686 -0.003314
0.004499 -0.008787 -0.004527
0.004499 -0.011213 -0.004527
0.004499 -0.013314 -0.003314
0.004499 -0.014527 -0.001213
0.004499 -0.014527 0.001213
0.004499 -0.013314 0.003314
0.004499 -0.011213 0.004527
0.004499 -0.008787 0.004527
0.007779 -0.008787 -0.004193
0.007779 -0.011213 -0.004193
0.007779 -0.011213 0.004193
0.007779 -0.008787 0.004193
numsurf 21
SURF 0x10
mat 2
refs 4
0 0.535729765892 0.453892558813
12 0.53325176239 0.448936551809
13 0.544875144958 0.408671677113
1 0.548260271549 0.410485655069
SURF 0x10
mat 2
refs 4
1 0.548260271549 0.410485655069
13 0.544875144958 0.408671677113
14 0.544875144958 0.362177878618
2 0.548260271549 0.36036375165
SURF 0x10
mat 2
refs 4
2 0.548260271549 0.36036375165
14 0.544875144958 0.362177878618
15 0.533251881599 0.321913033724
3 0.535729765892 0.316956788301
SURF 0x10
mat 2
refs 4
3 0.535729765892 0.316956788301
15 0.533251881599 0.321913033724
16 0.513119459152 0.298666030169
4 0.514026403427 0.291895896196
SURF 0x10
mat 2
refs 4
4 0.514026403427 0.291895896196
16 0.513119459152 0.298666030169
17 0.489872395992 0.298665940762
5 0.488965392113 0.291895896196
SURF 0x10
mat 2
refs 4
5 0.488965392113 0.291895896196
17 0.489872395992 0.298665940762
18 0.46974003315 0.321912825108
6 0.467261910439 0.316956788301
SURF 0x10
mat 2
refs 4
6 0.467261910439 0.316956788301
18 0.46974003315 0.321912825108
19 0.458116590977 0.3621776402
7 0.454731464386 0.360363692045
SURF 0x10
mat 2
refs 4
7 0.454731464386 0.360363692045
19 0.458116590977 0.3621776402
20 0.458116590977 0.408671438694
8 0.454731464386 0.410485595465
SURF 0x10
mat 2
refs 4
8 0.454731464386 0.410485595465
20 0.458116590977 0.408671438694
21 0.46974003315 0.448936372995
9 0.467261910439 0.453892499208
SURF 0x10
mat 2
refs 4
9 0.467261910439 0.453892499208
21 0.46974003315 0.448936372995
22 0.489872336388 0.472183257341
10 0.488965272903 0.478953510523
SURF 0x10
mat 2
refs 4
10 0.488965272903 0.463854044676
22 0.489872336388 0.457083791494
23 0.513119280338 0.457083910704
11 0.514026403427 0.463854044676
SURF 0x10
mat 2
refs 4
12 0.53325176239 0.448936551809
0 0.535729765892 0.453892558813
11 0.514026403427 0.478953510523
23 0.513119280338 0.472183376551
SURF 0x10
mat 2
refs 4
18 0.46974003315 0.321912825108
21 0.46974003315 0.448936372995
20 0.458116590977 0.408671438694
19 0.458116590977 0.3621776402
SURF 0x10
mat 2
refs 4
17 0.489872395992 0.298665940762
22 0.489872336388 0.472183257341
21 0.46974003315 0.448936372995
18 0.46974003315 0.321912825108
SURF 0x10
mat 2
refs 4
12 0.53325176239 0.448936551809
15 0.533251881599 0.321913033724
14 0.544875144958 0.362177878618
13 0.544875144958 0.408671677113
SURF 0x10
mat 2
refs 4
12 0.53325176239 0.448936551809
23 0.513119280338 0.472183376551
16 0.513119459152 0.298666030169
15 0.533251881599 0.321913033724
SURF 0x10
mat 2
refs 4
17 0.489872395992 0.298665940762
16 0.513119459152 0.298666030169
24 0.513119459152 0.30507221818
25 0.489872395992 0.305072128773
SURF 0x10
mat 2
refs 4
23 0.513119280338 0.457083910704
22 0.489872336388 0.457083791494
26 0.489872336388 0.450677603483
27 0.513119280338 0.450677722692
SURF 0x10
mat 2
refs 4
22 0.489872336388 0.472183257341
17 0.489872395992 0.298665940762
25 0.489872395992 0.305072128773
26 0.489872336388 0.46577706933
SURF 0x10
mat 2
refs 4
16 0.513119459152 0.298666030169
23 0.513119280338 0.472183376551
27 0.513119280338 0.46577718854
24 0.513119459152 0.30507221818
SURF 0x10
mat 2
refs 4
25 0.489872395992 0.305072128773
24 0.513119459152 0.30507221818
27 0.513119280338 0.46577718854
26 0.489872336388 0.46577706933
kids 0
OBJECT poly
name "dmebezel"
data 8
Mesh.079
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 56
0.000842 0.007242 -0.039319
0.000842 -0.007229 -0.039331
0.000842 -0.014511 -0.032798
0.000842 -0.014515 0.032738
0.000842 -0.007242 0.039319
0.000842 0.007229 0.039331
0.000843 0.01451 0.032798
0.000842 0.014515 -0.032738
0.002247 0.007242 -0.039319
0.002247 0.014515 -0.032738
0.002247 0.01451 0.032798
0.002246 0.007229 0.039331
0.002246 -0.007242 0.039319
0.002247 -0.007229 -0.039331
0.002247 -0.014516 0.032738
0.002247 -0.014511 -0.032798
0.002246 0.01607 -0.033721
0.002247 0.008025 -0.04088
0.002246 0.016065 0.033782
0.002247 0.00801 0.040893
0.002247 -0.008025 0.04088
0.002247 -0.00801 -0.040894
0.002247 -0.01607 0.03372
0.002247 -0.016065 -0.033782
0.000843 -6e-06 0.039325
0.000842 7e-06 -0.039325
0.00165 0.01607 -0.033721
0.00165 0.008025 -0.04088
0.00165 0.016065 0.033782
0.00165 0.00801 0.040893
0.00165 -0.008025 0.04088
0.00165 -0.00801 -0.040894
0.00165 -0.01607 0.03372
0.00165 -0.016065 -0.033782
0.00165 0.017447 -0.043733
0.00165 0.016138 -0.044932
0.00165 0.017442 0.043812
0.00165 0.016107 0.044946
0.00165 -0.016138 0.044932
0.00165 -0.016108 -0.044947
0.00165 -0.017448 0.043732
0.00165 -0.017442 -0.043812
0.000147 0.017447 -0.043733
0.000147 0.016138 -0.044932
0.000147 0.017442 0.043812
0.000147 0.016107 0.044946
0.000147 -0.016138 0.044932
0.000147 -0.016108 -0.044947
0.000147 -0.017448 0.043732
0.000147 -0.017442 -0.043812
0.000842 -0.007229 -0.039331
0.000842 -0.014511 -0.032798
0.000842 -0.014515 0.032738
0.000842 -0.007242 0.039319
0.000843 -6e-06 0.039325
0.000842 7e-06 -0.039325
numsurf 46
SURF 0x00
mat 3
refs 4
7 0.752499580383 0.500000059605
0 0.752499580383 0.400000065565
8 0.852499604225 0.400000065565
9 0.852499604225 0.500000059605
SURF 0x00
mat 3
refs 4
6 0.752499580383 0.500000059605
7 0.752499580383 0.400000065565
9 0.852499604225 0.400000065565
10 0.852499604225 0.500000059605
SURF 0x00
mat 3
refs 4
5 0.752499580383 0.500000059605
6 0.752499580383 0.400000065565
10 0.852499604225 0.400000065565
11 0.852499604225 0.500000059605
SURF 0x00
mat 3
refs 3
4 0.752499580383 0.500000059605
24 0.752499580383 0.400000065565
12 0.852499604225 0.400000065565
SURF 0x00
mat 3
refs 4
3 0.752499580383 0.500000059605
4 0.752499580383 0.400000065565
12 0.852499604225 0.400000065565
14 0.852499604225 0.500000059605
SURF 0x00
mat 3
refs 4
2 0.752499580383 0.500000059605
3 0.752499580383 0.400000065565
14 0.852499604225 0.400000065565
15 0.852499604225 0.500000059605
SURF 0x00
mat 3
refs 4
1 0.752499580383 0.500000059605
2 0.752499580383 0.400000065565
15 0.852499604225 0.400000065565
13 0.852499604225 0.500000059605
SURF 0x00
mat 3
refs 4
9 0.516570031643 0.94054287672
8 0.516570031643 0.927807867527
17 0.529305040836 0.927807867527
16 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 4
10 0.516570031643 0.94054287672
9 0.516570031643 0.927807867527
16 0.529305040836 0.927807867527
18 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 4
11 0.516570031643 0.94054287672
10 0.516570031643 0.927807867527
18 0.529305040836 0.927807867527
19 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 4
12 0.516570031643 0.94054287672
11 0.516570031643 0.927807867527
19 0.529305040836 0.927807867527
20 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 4
8 0.516570031643 0.94054287672
13 0.516570031643 0.927807867527
21 0.529305040836 0.927807867527
17 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 4
14 0.516570031643 0.94054287672
12 0.516570031643 0.927807867527
20 0.529305040836 0.927807867527
22 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 4
15 0.516570031643 0.94054287672
14 0.516570031643 0.927807867527
22 0.529305040836 0.927807867527
23 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 4
13 0.516570031643 0.94054287672
15 0.516570031643 0.927807867527
23 0.529305040836 0.927807867527
21 0.529305040836 0.94054287672
SURF 0x00
mat 3
refs 3
0 0.752499580383 0.500000059605
25 0.752499580383 0.400000065565
13 0.852499604225 0.400000065565
SURF 0x00
mat 3
refs 3
0 0.752499580383 0.500000059605
13 0.752499580383 0.400000065565
8 0.852499604225 0.400000065565
SURF 0x00
mat 3
refs 3
5 0.752499580383 0.500000059605
11 0.752499580383 0.400000065565
12 0.852499604225 0.400000065565
SURF 0x00
mat 3
refs 3
25 0.752499580383 0.500000059605
1 0.752499580383 0.400000065565
13 0.852499604225 0.400000065565
SURF 0x00
mat 3
refs 3
24 0.752499580383 0.500000059605
5 0.752499580383 0.400000065565
12 0.852499604225 0.400000065565
SURF 0x00
mat 3
refs 4
16 0.928124308586 0.311250269413
17 0.928124308586 0.27125030756
27 0.968124330044 0.27125030756
26 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
18 0.928124308586 0.311250269413
16 0.928124308586 0.27125030756
26 0.968124330044 0.27125030756
28 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
19 0.928124308586 0.311250269413
18 0.928124308586 0.27125030756
28 0.968124330044 0.27125030756
29 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
20 0.928124308586 0.311250269413
19 0.928124308586 0.27125030756
29 0.968124330044 0.27125030756
30 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
17 0.928124308586 0.311250269413
21 0.928124308586 0.27125030756
31 0.968124330044 0.27125030756
27 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
22 0.928124308586 0.311250269413
20 0.928124308586 0.27125030756
30 0.968124330044 0.27125030756
32 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
23 0.928124308586 0.311250269413
22 0.928124308586 0.27125030756
32 0.968124330044 0.27125030756
33 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
21 0.928124308586 0.311250269413
23 0.928124308586 0.27125030756
33 0.968124330044 0.27125030756
31 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
26 0.928124308586 0.311250269413
27 0.928124308586 0.27125030756
35 0.968124330044 0.27125030756
34 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
28 0.928124308586 0.311250269413
26 0.928124308586 0.27125030756
34 0.968124330044 0.27125030756
36 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
29 0.928124308586 0.311250269413
28 0.928124308586 0.27125030756
36 0.968124330044 0.27125030756
37 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
30 0.928124308586 0.311250269413
29 0.928124308586 0.27125030756
37 0.968124330044 0.27125030756
38 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
27 0.928124308586 0.311250269413
31 0.928124308586 0.27125030756
39 0.968124330044 0.27125030756
35 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
32 0.928124308586 0.311250269413
30 0.928124308586 0.27125030756
38 0.968124330044 0.27125030756
40 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
33 0.928124308586 0.311250269413
32 0.928124308586 0.27125030756
40 0.968124330044 0.27125030756
41 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
31 0.928124308586 0.311250269413
33 0.928124308586 0.27125030756
41 0.968124330044 0.27125030756
39 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
34 0.928124308586 0.311250269413
35 0.928124308586 0.27125030756
43 0.968124330044 0.27125030756
42 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
36 0.928124308586 0.311250269413
34 0.928124308586 0.27125030756
42 0.968124330044 0.27125030756
44 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
37 0.928124308586 0.311250269413
36 0.928124308586 0.27125030756
44 0.968124330044 0.27125030756
45 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
38 0.928124308586 0.311250269413
37 0.928124308586 0.27125030756
45 0.968124330044 0.27125030756
46 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
35 0.928124308586 0.311250269413
39 0.928124308586 0.27125030756
47 0.968124330044 0.27125030756
43 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
40 0.928124308586 0.311250269413
38 0.928124308586 0.27125030756
46 0.968124330044 0.27125030756
48 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
41 0.928124308586 0.311250269413
40 0.928124308586 0.27125030756
48 0.968124330044 0.27125030756
49 0.968124330044 0.311250269413
SURF 0x00
mat 3
refs 4
39 0.928124308586 0.311250269413
41 0.928124308586 0.27125030756
49 0.968124330044 0.27125030756
47 0.968124330044 0.311250269413
SURF 0x10
mat 3
refs 4
50 0.920733690262 0.440070271492
53 0.0834924578667 0.439790010452
52 0.153548210859 0.284956693649
51 0.851188838482 0.285044133663
SURF 0x10
mat 3
refs 4
50 0.920733690262 0.440070271492
55 0.920669853687 0.594127893448
54 0.0834285616875 0.593843877316
53 0.0834924578667 0.439790010452
kids 0
OBJECT poly
name "dmeface"
data 8
Mesh.094
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 6
0.000842 7e-06 -0.039325
0.000843 -6e-06 0.039325
0.000842 0.014515 -0.032738
0.000843 0.01451 0.032798
0.000842 0.007229 0.039331
0.000842 0.007242 -0.039319
numsurf 2
SURF 0x10
mat 1
refs 4
0 0.922852396965 0.604025781155
5 0.922788202763 0.758947312832
4 0.0807167291641 0.758664429188
1 0.0807809233665 0.603740155697
SURF 0x10
mat 1
refs 4
5 0.922788202763 0.758947312832
2 0.848569154739 0.914694130421
3 0.154421895742 0.914586186409
4 0.0807167291641 0.758664429188
kids 0
OBJECT poly
name "dmeface.001"
data 8
Mesh.354
texture "dme.png"
texrep 1 1
crease 30.000000
numvert 6
0.000706 1.1e-05 -0.039929
0.000707 -3e-06 0.039929
0.000768 0.015102 -0.03324
0.000768 0.015097 0.033301
0.000737 0.007523 0.039935
0.000737 0.007536 -0.039922
numsurf 2
SURF 0x10
mat 1
refs 4
0 0.610067427158 0.813914358616
5 0.61005282402 0.849155306816
4 0.41850155592 0.849090993404
1 0.418516159058 0.813849389553
SURF 0x10
mat 1
refs 4
5 0.61005282402 0.849155306816
2 0.593169748783 0.884584009647
3 0.435267746449 0.884559452534
4 0.41850155592 0.849090993404
kids 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -0,0 +1,66 @@
###############################################################################
## $Id$
##
## Nasal for KDI 572 DME.
##
## Copyright (C) 2006 - 2008 Syd Adams
## Adapted for dual control by Anders Gidenstam
##
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Note:
# This module MUST be loaded as KDI572.
#
var base = ["instrumentation/dme[0]",
"instrumentation/dme[1]"];
###########################################################################
# API for pick animations.
###########################################################################
var dme_step = func(stp) {
var switch= getprop("instrumentation/dme/switch-position");
switch += stp;
if (switch >3) switch=3;
if (switch <0) switch=0;
setprop("instrumentation/dme/switch-position", switch);
if (switch==0) {
setprop("instrumentation/dme/frequencies/source",
"instrumentation/dme/frequencies/selected-mhz");
} elsif (switch==1) {
setprop("instrumentation/dme/frequencies/source",
"instrumentation/nav[0]/frequencies/selected-mhz");
} elsif (switch==2) {
setprop("instrumentation/dme/frequencies/source",
"instrumentation/dme/frequencies/selected-mhz");
} elsif (switch==3) {
setprop("instrumentation/dme/frequencies/source",
"instrumentation/nav[1]/frequencies/selected-mhz");
}
}
###########################################################################
# API for dual control setup.
###########################################################################
###########################################################################
# Create aliases to drive a KDI-572 3d model in an AI/MP model.
# n - unit#
var animate_aimodel = func(n, airoot) {
var p = "systems/electrical/outputs/dme";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/switch-position";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/in-range";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/indicated-distance-nm";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/indicated-ground-speed-kt";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/indicated-time-min";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
}

View file

@ -0,0 +1,228 @@
<?xml version="1.0"?>
<!--
Author : Syd Adams
KDI-572 DME Indicator
-->
<PropertyList>
<path>dme.ac</path>
<animation>
<type>select</type>
<object-name>dmeface</object-name>
<condition>
<and>
<greater-than>
<property>systems/electrical/outputs/dme</property>
<value>8</value>
</greater-than>
<greater-than>
<property>instrumentation/dme/switch-position</property>
<value>0</value>
</greater-than>
</and>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>DME.nm</object-name>
<object-name>DME.nm1</object-name>
<object-name>DME.nm2</object-name>
<object-name>DME.nm3</object-name>
<object-name>DME.kt1</object-name>
<object-name>DME.kt2</object-name>
<object-name>DME.kt3</object-name>
<object-name>DME.mn1</object-name>
<object-name>DME.mn2</object-name>
<condition>
<and>
<greater-than>
<property>systems/electrical/outputs/dme</property>
<value>8</value>
</greater-than>
<property>instrumentation/dme/in-range</property>
</and>
</condition>
</animation>
<animation>
<type>rotate</type>
<object-name>DMEswitch</object-name>
<property>instrumentation/dme/switch-position</property>
<interpolation>
<entry>
<ind>0</ind><dep>0.0</dep>
</entry>
<entry>
<ind>1</ind><dep>35.0</dep>
</entry>
<entry>
<ind>2</ind><dep>90.0</dep>
</entry>
<entry>
<ind>3</ind><dep>150.0</dep>
</entry>
</interpolation>
<axis>
<x>-1</x>
<y>0</y>
<z>0</z>
</axis>
<center>
<x-m>0</x-m>
<y-m>0</y-m>
<z-m>-0.010</z-m>
</center>
</animation>
<!-- distance-->
<animation>
<type>textranslate</type>
<object-name>DME.nm1</object-name>
<property>instrumentation/dme/indicated-distance-nm</property>
<factor>0.01</factor>
<step>10</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>DME.nm2</object-name>
<property>instrumentation/dme/indicated-distance-nm</property>
<factor>0.1</factor>
<step>1</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>DME.nm3</object-name>
<property>instrumentation/dme/indicated-distance-nm</property>
<factor>1.0</factor>
<step>0.1</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- speed-->
<animation>
<type>textranslate</type>
<object-name>DME.kt1</object-name>
<property>instrumentation/dme/indicated-ground-speed-kt</property>
<factor>0.001</factor>
<step>100</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>DME.kt2</object-name>
<property>instrumentation/dme/indicated-ground-speed-kt</property>
<factor>0.01</factor>
<step>10</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>DME.kt3</object-name>
<property>instrumentation/dme/indicated-ground-speed-kt</property>
<factor>0.1</factor>
<step>1</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- time-->
<animation>
<type>textranslate</type>
<object-name>DME.mn1</object-name>
<property>instrumentation/dme/indicated-time-min</property>
<factor>0.01</factor>
<step>10</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>DME.mn2</object-name>
<property>instrumentation/dme/indicated-time-min</property>
<factor>0.1</factor>
<step>1</step>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- Pick animations -->
<animation>
<type>pick</type>
<object-name>DMEswitch</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KDI572.dme_step(1)</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KDI572.dme_step(-1)</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KDI572.dme_step(-1)</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KDI572.dme_step(1)</script>
</binding>
</action>
</animation>
</PropertyList>

View file

@ -0,0 +1,176 @@
<?xml version="1.0"?>
<!-- KI 206
Bendix/King VOR / LOC / Glideslope Indicator
Syd Adams
Anders Gidenstam (pick animations)
-->
<PropertyList>
<path>Aircraft/Instruments-3d/ki206/ki206.ac</path>
<texture-path>Aircraft/Instruments-3d/ki206/</texture-path>
<animation>
<type>material</type>
<object-name>KI206.gsflag</object-name>
<object-name>KI206.toflag</object-name>
<object-name>KI206.fromflag</object-name>
<object-name>KI206.navflag</object-name>
<object-name>KI206.face</object-name>
<object-name>KI206card</object-name>
<object-name>KI206.locneedle</object-name>
<object-name>KI206.gsneedle</object-name>
<object-name>KI206.knob</object-name>
<emission>
<red>0.8</red>
<green>0.4</green>
<blue>0.2</blue>
<factor-prop>/systems/electrical/outputs/instrument-lights</factor-prop>
</emission>
</animation>
<animation>
<type>select</type>
<object-name>KI206.navflag</object-name>
<condition>
<or>
<not>
<property>instrumentation/nav[0]/data-is-valid</property>
</not>
<less-than>
<property>systems/electrical/outputs/nav[0]</property>
<value>0.1</value>
</less-than>
<not>
<property>instrumentation/nav[0]/in-range</property>
</not>
</or>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>KI206.gsflag</object-name>
<condition>
<or>
<not>
<property>instrumentation/nav[0]/has-gs</property>
</not>
<less-than>
<property>systems/electrical/outputs/nav[0]</property>
<value>0.1</value>
</less-than>
<greater-than>
<property>instrumentation/nav[0]/in-range</property>
<value>30000</value>
</greater-than>
</or>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>KI206.toflag</object-name>
<condition>
<property>instrumentation/nav[0]/to-flag</property>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>KI206.fromflag</object-name>
<condition>
<property>instrumentation/nav[0]/from-flag</property>
</condition>
</animation>
<animation>
<type>rotate</type>
<object-name>KI206card</object-name>
<property>instrumentation/nav[0]/radials/selected-deg</property>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>translate</type>
<object-name>KI206.locneedle</object-name>
<property>instrumentation/nav[0]/heading-needle-deflection</property>
<interpolation>
<entry><ind>-10.0</ind><dep>-0.0113</dep></entry>
<entry><ind>0.0</ind><dep>0.0</dep></entry>
<entry><ind>10.0</ind><dep>0.0113</dep></entry>
</interpolation>
<axis>
<x>0.0</x>
<y>1.0</y>
<z>0.0</z>
</axis>
</animation>
<animation>
<type>translate</type>
<object-name>KI206.gsneedle</object-name>
<property>instrumentation/nav[0]/gs-needle-deflection</property>
<interpolation>
<entry><ind>-9999.0</ind><dep>-0.0113</dep></entry>
<entry><ind>-10.0</ind><dep>-0.0113</dep></entry>
<entry><ind>0.0</ind><dep>0.0</dep></entry>
<entry><ind>10.0</ind><dep>0.0113</dep></entry>
<entry><ind>9999.0</ind><dep>0.0113</dep></entry>
</interpolation>
<axis>
<x>0.0</x>
<y>0.0</y>
<z>1.0</z>
</axis>
</animation>
<animation>
<type>pick</type>
<object-name>KI206.knob</object-name>
<visible>true</visible>
<action>
<name>click</name>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(0, 1.0);</script>
</binding>
</action>
<action>
<name>click</name>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(0, -1.0);</script>
</binding>
</action>
<action>
<name>click</name>
<button>3</button>
<repeatable>false</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(0, -1.0);</script>
</binding>
</action>
<action>
<name>click</name>
<button>4</button>
<repeatable>false</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(0, 1.0);</script>
</binding>
</action>
</animation>
</PropertyList>

View file

@ -0,0 +1,176 @@
<?xml version="1.0"?>
<!-- KI 206
Bendix/King VOR / LOC / Glideslope Indicator
Syd Adams
Anders Gidenstam (pick animations)
-->
<PropertyList>
<path>Aircraft/Instruments-3d/ki206/ki206.ac</path>
<texture-path>Aircraft/Instruments-3d/ki206/</texture-path>
<animation>
<type>material</type>
<object-name>KI206.gsflag</object-name>
<object-name>KI206.toflag</object-name>
<object-name>KI206.fromflag</object-name>
<object-name>KI206.navflag</object-name>
<object-name>KI206.face</object-name>
<object-name>KI206card</object-name>
<object-name>KI206.locneedle</object-name>
<object-name>KI206.gsneedle</object-name>
<object-name>KI206.knob</object-name>
<emission>
<red>0.8</red>
<green>0.4</green>
<blue>0.2</blue>
<factor-prop>/systems/electrical/outputs/instrument-lights</factor-prop>
</emission>
</animation>
<animation>
<type>select</type>
<object-name>KI206.navflag</object-name>
<condition>
<or>
<not>
<property>instrumentation/nav[1]/data-is-valid</property>
</not>
<less-than>
<property>systems/electrical/outputs/nav[1]</property>
<value>0.1</value>
</less-than>
<not>
<property>instrumentation/nav[1]/in-range</property>
</not>
</or>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>KI206.gsflag</object-name>
<condition>
<or>
<not>
<property>instrumentation/nav[1]/has-gs</property>
</not>
<less-than>
<property>systems/electrical/outputs/nav[1]</property>
<value>0.1</value>
</less-than>
<greater-than>
<property>instrumentation/nav[1]/in-range</property>
<value>30000</value>
</greater-than>
</or>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>KI206.toflag</object-name>
<condition>
<property>instrumentation/nav[1]/to-flag</property>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>KI206.fromflag</object-name>
<condition>
<property>instrumentation/nav[1]/from-flag</property>
</condition>
</animation>
<animation>
<type>rotate</type>
<object-name>KI206card</object-name>
<property>instrumentation/nav[1]/radials/selected-deg</property>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>translate</type>
<object-name>KI206.locneedle</object-name>
<property>instrumentation/nav[1]/heading-needle-deflection</property>
<interpolation>
<entry><ind>-10.0</ind><dep>-0.0113</dep></entry>
<entry><ind>0.0</ind><dep>0.0</dep></entry>
<entry><ind>10.0</ind><dep>0.0113</dep></entry>
</interpolation>
<axis>
<x>0.0</x>
<y>1.0</y>
<z>0.0</z>
</axis>
</animation>
<animation>
<type>translate</type>
<object-name>KI206.gsneedle</object-name>
<property>instrumentation/nav[1]/gs-needle-deflection</property>
<interpolation>
<entry><ind>-9999.0</ind><dep>-0.0113</dep></entry>
<entry><ind>-10.0</ind><dep>-0.0113</dep></entry>
<entry><ind>0.0</ind><dep>0.0</dep></entry>
<entry><ind>10.0</ind><dep>0.0113</dep></entry>
<entry><ind>9999.0</ind><dep>0.0113</dep></entry>
</interpolation>
<axis>
<x>0.0</x>
<y>0.0</y>
<z>1.0</z>
</axis>
</animation>
<animation>
<type>pick</type>
<object-name>KI206.knob</object-name>
<visible>true</visible>
<action>
<name>click</name>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(1, 1.0);</script>
</binding>
</action>
<action>
<name>click</name>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(1, -1.0);</script>
</binding>
</action>
<action>
<name>click</name>
<button>3</button>
<repeatable>false</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(1, -1.0);</script>
</binding>
</action>
<action>
<name>click</name>
<button>4</button>
<repeatable>false</repeatable>
<interval-sec>0.1</interval-sec>
<binding>
<command>nasal</command>
<script>KI206.adjust_radial(1, 1.0);</script>
</binding>
</action>
</animation>
</PropertyList>

View file

@ -0,0 +1,166 @@
###############################################################################
##
## Nasal for dual control of a KI-206 VOR indicator over the multiplayer
## network.
##
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Note:
# This module MUST be loaded as KI206.
# Slave button presses.
var radial_decS = "radial-decS-clicked";
var radial_incS = "radial-incS-clicked";
# Only one step size implemented.
var selected_radial = "radials/selected-deg";
var base = ["instrumentation/nav[0]",
"instrumentation/nav[1]"];
###########################################################################
var master_ki206 = {
new : func(n) {
var obj = {};
obj.parents = [master_ki206];
obj.base = props.globals.getNode(base[n]);
return obj;
},
adjust_radial : func(d) {
p = me.base.getNode(selected_radial);
var v = p.getValue() + d;
if (v < 0) { v += 360; };
if (v > 360) { v -= 360; };
p.setValue(v);
}
};
###########################################################################
var slave_ki206 = {
new : func(n, airoot) {
var obj = {};
obj.parents = [slave_ki206];
obj.root = airoot;
obj.base = props.globals.getNode(base[n]);
return obj;
},
adjust_radial : func(d) {
var p = 0;
if (abs(d) < 0.99) {
p = (d < 0) ? me.base.getNode(radial_decS)
: me.base.getNode(radial_incS);
} else {
p = (d < 0) ? me.base.getNode(radial_decS)
: me.base.getNode(radial_incS);
}
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
}
};
###########################################################################
# The KI-206 pick animations default to master.
# NOTE: Use make_master() and make_slave_to(). Do NOT change ki206 directly.
var ki206 = [master_ki206.new(0), master_ki206.new(1)];
###########################################################################
# API for pick animations and dual control setup.
###########################################################################
###########################################################################
# n - Nav#
var make_master = func(n) {
ki206[n] = master_ki206.new(n);
}
###########################################################################
# n - Nav#
var make_slave_to = func(n, airoot) {
ki206[n] = KI206.slave_ki206.new(n, airoot);
}
###########################################################################
# n - Nav#
# d - adjustment delta
var adjust_radial = func(n, d) {
ki206[n].adjust_radial(d);
}
###########################################################################
# Create aliases to drive the KI 206 3d model in an AI/MP model.
# n - Nav#
var animate_aimodel = func(n, airoot) {
var p = base[n] ~ "/data-is-valid";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/in-range";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/has-gs";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/to-flag";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/from-flag";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/" ~ selected_radial;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/heading-needle-deflection";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/gs-needle-deflection";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
}
###########################################################################
# Create a TDMEncoder node array for sending the current radio state to
# slaves.
# n - Nav#
var master_send_state = func(n) {
return
[
props.globals.getNode(base[n] ~ "/" ~ selected_radial)
];
}
###########################################################################
# Create a SwitchDecoder action array for processing button presses
# from a slave.
# n - Nav#
var master_receive_slave_buttons = func(n) {
return
[
func (b) {
if (b) { KI206.adjust_radial(n, -1.0); }
},
func (b) {
if (b) { KI206.adjust_radial(n, 1.0); }
}
];
}
###########################################################################
# Create a TDMDecoder action array for processing the radio state
# from the master.
# n - Nav#
var slave_receive_master_state = func(n) {
return
[
func (v) {
props.globals.getNode(base[n] ~ "/" ~ selected_radial).setValue(v);
}
];
}
###########################################################################
# Create a SwitchEncoder node array for sending button presses
# to the master
# n - Nav#
var slave_send_buttons = func(n) {
return
[
props.globals.getNode(base[n] ~ "/" ~ radial_decS, 1),
props.globals.getNode(base[n] ~ "/" ~ radial_incS, 1),
];
}

View file

@ -0,0 +1,362 @@
<?xml version="1.0"?>
<!-- KR-87 ADF receiver
3d model by Torsten Dreyer
Adapted for dual control by Anders Gidenstam
NOTE: kr87.nas MUST be loaded as Nasal module KR87.
-->
<PropertyList>
<path>kr87.ac</path>
<texture-path>Aircraft/Generic/DualControl/Instruments/KX165/</texture-path>
<animation>
<type>select</type>
<object-name>kr87.indicators</object-name>
<condition>
<property>instrumentation/adf[0]/serviceable</property>
<property>instrumentation/adf[0]/power-btn</property>
<greater-than>
<property>systems/electrical/outputs/adf[0]</property>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>material</type>
<object-name>kr87.knobs.ADF</object-name>
<object-name>kr87.knobs.BFO</object-name>
<object-name>kr87.knobs.FRQ</object-name>
<object-name>kr87.knobs.FLT</object-name>
<object-name>kr87.knobs.SET</object-name>
<emission>
<red-prop>sim/model/instrument-lighting/emission/red</red-prop>
<green-prop>sim/model/instrument-lighting/emission/green</green-prop>
<blue-prop>sim/model/instrument-lighting/emission/blue</blue-prop>
<factor-prop>controls/lighting/instruments-norm</factor-prop>
</emission>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.ANT</object-name>
<condition>
<not>
<property>instrumentation/adf[0]/adf-btn</property>
</not>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.ADF</object-name>
<condition>
<property>instrumentation/adf[0]/adf-btn</property>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.BFO</object-name>
<condition>
<property>instrumentation/adf[0]/bfo-btn</property>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.FRQ</object-name>
<condition>
<equals>
<property>instrumentation/adf[0]/display-mode</property>
<value type="int">0</value>
</equals>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.FLT</object-name>
<condition>
<equals>
<property>instrumentation/adf[0]/display-mode</property>
<value type="int">1</value>
</equals>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.ET</object-name>
<condition>
<equals>
<property>instrumentation/adf[0]/display-mode</property>
<value type="int">2</value>
</equals>
</condition>
</animation>
<!-- Use FREQ -->
<animation>
<type>select</type>
<object-name>kr87.indicators.Use.1000</object-name>
<condition>
<greater-than-equals>
<property>instrumentation/adf[0]/frequencies/selected-khz</property>
<value type="int">1000</value>
</greater-than-equals>
</condition>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Use.1000</object-name>
<property>instrumentation/adf[0]/frequencies/selected-khz</property>
<step>1000</step>
<factor>0.0001</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Use.100</object-name>
<property>instrumentation/adf[0]/frequencies/selected-khz</property>
<step>100</step>
<factor>0.001</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Use.10</object-name>
<property>instrumentation/adf[0]/frequencies/selected-khz</property>
<step>10</step>
<factor>0.01</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Use.1</object-name>
<property>instrumentation/adf[0]/frequencies/selected-khz</property>
<step>1</step>
<factor>0.1</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- STBY FREQ -->
<animation>
<condition>
<not-equals>
<property>instrumentation/adf[0]/display-mode</property>
<value type="int">0</value>
</not-equals>
</condition>
<type>select</type>
<object-name>kr87.indicators.dots</object-name>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.Stby.1000</object-name>
<condition>
<greater-than-equals>
<property>instrumentation/adf[0]/right-display</property>
<value type="int">1000</value>
</greater-than-equals>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>kr87.indicators.Stby.100</object-name>
<condition>
<greater-than-equals>
<property>instrumentation/adf[0]/right-display</property>
<value type="int">100</value>
</greater-than-equals>
</condition>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Stby.1000</object-name>
<property>instrumentation/adf[0]/right-display</property>
<step>1000</step>
<factor>0.0001</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Stby.100</object-name>
<property>instrumentation/adf[0]/right-display</property>
<step>100</step>
<factor>0.001</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Stby.10</object-name>
<property>instrumentation/adf[0]/right-display</property>
<step>10</step>
<factor>0.01</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>kr87.indicators.Stby.1</object-name>
<property>instrumentation/adf[0]/right-display</property>
<step>1</step>
<factor>0.1</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>noshadow</type>
</animation>
<!-- OSG Hotspots for dual control -->
<animation>
<type>pick</type>
<object-name>kr87.knobs.FRQ</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KR87.swap(0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>kr87.knobs.FRQOuter</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, 100);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, -100);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, -100.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, 100.0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>kr87.knobs.FRQInner</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, 1.0);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KR87.adjust_frequency(0, 1.0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>kr87.knobs.BFO</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KR87.toggle_BFO(0);</script>
</binding>
</action>
</animation>
</PropertyList>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,266 @@
###############################################################################
##
## Nasal for dual control of a KR-87 ADF radio over the multiplayer
## network.
##
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Note:
# This module MUST be loaded as KR87.
#
# Slave button presses.
var swap_btn = "frq-btn";
var freq_decS = "freq-decS-clicked";
var freq_incS = "freq-incS-clicked";
var freq_decL = "freq-decL-clicked";
var freq_incL = "freq-incL-clicked";
var bfo_btn = "bfo-btn";
# Settings
var freq_selected = "frequencies/selected-khz";
var freq_standby = "frequencies/standby-khz";
var base = ["instrumentation/adf[0]",
"instrumentation/adf[1]"];
###########################################################################
var master_kr87 = {
new : func(n) {
var obj = {};
obj.parents = [master_kr87];
obj.base = props.globals.getNode(base[n]);
if (obj.base == nil) return;
obj.base.getNode("right-display", 1).
setValue(obj.base.getNode(freq_standby).getValue());
# Always show the standby frequency.
obj.base.getNode("display-mode", 1).setValue(0);
return obj;
},
swap : func() {
var tmp = me.base.getNode(freq_selected).getValue();
me.base.getNode(freq_selected).setValue
(me.base.getNode(freq_standby).getValue());
me.base.getNode(freq_standby).setValue(tmp);
me.base.getNode("right-display").setValue(tmp);
},
adjust_frequency : func(d) {
adjust_radio_frequency(
me.base.getNode(freq_standby),
d,
200,
1800);
me.base.getNode("right-display").
setValue(me.base.getNode(freq_standby).getValue());
},
toggle_BFO : func {
var p = me.base.getNode(bfo_btn).getValue() ? 0 : 1;
me.base.getNode(bfo_btn).setValue(p);
me.base.getNode("ident-audible").setValue(p);
}
};
###########################################################################
var slave_kr87 = {
new : func(n, airoot) {
var obj = {};
obj.parents = [slave_kr87];
obj.airoot = airoot;
obj.base = props.globals.getNode(base[n]);
if (obj.base == nil) return;
obj.base.getNode("right-display", 1).
setValue(obj.base.getNode(freq_standby).getValue());
# Always show the standby frequency.
obj.base.getNode(base[n] ~ "/display-mode", 1).setValue(0);
return obj;
},
swap : func() {
var p = me.base.getNode(swap_btn);
# print("KR87[?].SWAP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
adjust_frequency : func(d) {
var p = 0;
if (abs(d) < 50) {
p = (d < 0) ? me.base.getNode(freq_decS)
: me.base.getNode(freq_incS);
} else {
p = (d < 0) ? me.base.getNode(freq_decL)
: me.base.getNode(freq_incL);
}
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
};
###########################################################################
# The KR-87 pick animations default to master.
# NOTE: Use make_master() and make_slave_to().
# Do NOT change kr87 directly.
var kr87 = [master_kr87.new(0), master_kr87.new(1)];
###########################################################################
# API for pick animations.
###########################################################################
###########################################################################
# n - ADF#
swap = func(n) {
kr87[n].swap();
}
###########################################################################
# n - ADF#
# d - adjustment
adjust_frequency = func(n, d) {
kr87[n].adjust_frequency(d);
}
###########################################################################
# n - ADF#
# p - pressed
toggle_BFO = func(n) {
kr87[n].toggle_BFO();
}
###########################################################################
# API for dual control setup.
###########################################################################
###########################################################################
# n - ADF#
var make_master = func(n) {
kr87[n] = master_kr87.new(n);
}
###########################################################################
# n - ADF#
var make_slave_to = func(n, airoot) {
kr87[n] = slave_kr87.new(n, airoot);
}
###########################################################################
# Create aliases to drive a KR-87 3d model in an AI/MP model.
# n - ADF#
var animate_aimodel = func(n, airoot) {
var p = "systems/electrical/outputs/adf["~ n ~"]";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = "instrumentation/adf["~ n ~"]/serviceable";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/" ~ freq_selected;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/" ~ freq_standby;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/display-mode";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/right-display";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base[n] ~ "/power-btn";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
}
###########################################################################
# Create a TDMEncoder node array for sending the current radio state to
# slaves.
# n - Adf#
var master_send_state = func(n) {
var b = props.globals.getNode(base[n]);
return
[
b.getNode(freq_selected),
b.getNode(freq_standby)
];
}
###########################################################################
# Create a SwitchDecoder action array for processing button presses
# from a slave.
# n - Adf#
var master_receive_slave_buttons = func(n) {
return
[
func (b) {
if (b) { swap(n); }
},
func (b) {
if (b) { adjust_frequency(n, -1.0); }
},
func (b) {
if (b) { adjust_frequency(n, 1.0); }
},
func (b) {
if (b) { adjust_frequency(n, -100.0); }
},
func (b) {
if (b) { adjust_frequency(n, 100.0); }
}
];
}
###########################################################################
# Create a TDMDecoder action array for processing the radio state
# from the master.
# n - Adf#
var slave_receive_master_state = func(n) {
var b = props.globals.getNode(base[n]);
return
[
func (v) {
b.getNode(freq_selected).setValue(v);
},
func (v) {
b.getNode(freq_standby).setValue(v);
b.getNode("right-display").setValue(v);
}
];
}
###########################################################################
# Create a SwitchEncoder node array for sending button presses
# to the master
# n - Adf#
var slave_send_buttons = func(n) {
var b = props.globals.getNode(base[n]);
return
[
b.getNode(swap_btn, 1),
b.getNode(freq_decS, 1),
b.getNode(freq_incS, 1),
b.getNode(freq_decL, 1),
b.getNode(freq_incL, 1),
# b.getNode(bfo_btn, 1)
];
}
###########################################################################
# (Not so) Generic frequency stepper.
# f - frequency property
# d - change
# min - min frequency
# max - max frequency
var adjust_radio_frequency = func(f, d, min, max) {
var old = f.getValue();
var new = old + d;
if (new < min - 0.05) {
new = max + (new - min);
if ((max - new) >= -d) new += -d;
}
if (new > max + 0.05) {
new = min + (new - max);
if ((new - min) >= d) new -= d;
}
# print("Old: " ~ old ~ " Intermediate: " ~ (old + d) ~ " New: " ~ new);
f.setValue(new);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,335 @@
###############################################################################
##
## Nasal for dual control of a KX165 NavComm radio over the multiplayer
## network.
##
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Note:
# This module MUST be loaded as KX165.
#
# Slave button presses.
var swap_btn = "frq-swap-btn";
var freq_decS = "freq-decS-clicked";
var freq_incS = "freq-incS-clicked";
var freq_decL = "freq-decL-clicked";
var freq_incL = "freq-incL-clicked";
# Settings
var freq_selected = "frequencies/selected-mhz";
var freq_standby = "frequencies/standby-mhz";
var comm_base = ["instrumentation/comm[0]",
"instrumentation/comm[1]"];
var nav_base = ["instrumentation/nav[0]",
"instrumentation/nav[1]"];
###########################################################################
var master_kx165tso = {
new : func(n) {
var obj = {};
obj.parents = [master_kx165tso];
obj.nav_base = props.globals.getNode("instrumentation/nav[" ~ n ~ "]");
obj.comm_base = props.globals.getNode("instrumentation/comm[" ~ n ~ "]");
return obj;
},
swap_nav : func() {
var tmp = me.nav_base.getNode(freq_selected).getValue();
me.nav_base.getNode(freq_selected).setValue
(me.nav_base.getNode(freq_standby).getValue());
me.nav_base.getNode(freq_standby).setValue(tmp);
},
swap_comm : func() {
var tmp = me.comm_base.getNode(freq_selected).getValue();
me.comm_base.getNode(freq_selected).setValue
(me.comm_base.getNode(freq_standby).getValue());
me.comm_base.getNode(freq_standby).setValue(tmp);
},
adjust_nav_frequency : func(d) {
adjust_radio_frequency(
me.nav_base.getNode(freq_standby),
d,
108,
117.95);
},
adjust_comm_frequency : func(d) {
adjust_radio_frequency(
me.comm_base.getNode(freq_standby),
d,
118,
135.975);
}
};
###########################################################################
var slave_kx165tso = {
new : func(n, airoot) {
var obj = {};
obj.parents = [slave_kx165tso];
obj.root = airoot;
obj.nav_base = props.globals.getNode("instrumentation/nav[" ~ n ~ "]");
obj.comm_base = props.globals.getNode("instrumentation/comm[" ~ n ~ "]");
return obj;
},
swap_nav : func() {
var p = me.nav_base.getNode(swap_btn);
# print("KX165tso[?].NAVSWAP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
swap_comm : func() {
var p = me.comm_base.getNode(swap_btn);
# print("KX165tso[?].COMMSWAP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
adjust_nav_frequency : func(d) {
var p = 0;
if (abs(d) < 0.99) {
p = (d < 0) ? me.nav_base.getNode(freq_decS)
: me.nav_base.getNode(freq_incS);
} else {
p = (d < 0) ? me.nav_base.getNode(freq_decL)
: me.nav_base.getNode(freq_incL);
}
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
adjust_comm_frequency : func(d) {
var p = 0;
if (abs(d) < 0.99) {
p = (d < 0) ? me.comm_base.getNode(freq_decS)
: me.comm_base.getNode(freq_incS);
} else {
p = (d < 0) ? me.comm_base.getNode(freq_decL)
: me.comm_base.getNode(freq_incL);
}
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
}
};
###########################################################################
# The KX-165 pick animations default to master.
# NOTE: Use make_master() and make_slave_to().
# Do NOT change kx165tso directly.
var kx165tso = [master_kx165tso.new(0), master_kx165tso.new(1)];
###########################################################################
# API for pick animations and dual control setup.
###########################################################################
###########################################################################
# n - NavComm#
var make_master = func(n) {
kx165tso[n] = master_kx165tso.new(n);
}
###########################################################################
# n - NavComm#
var make_slave_to = func(n, airoot) {
kx165tso[n] = slave_kx165tso.new(n, airoot);
}
###########################################################################
# n - NavComm#
swap_nav = func(n) {
kx165tso[n].swap_nav();
}
###########################################################################
# n - NavComm#
swap_comm = func(n, b) {
kx165tso[n].comm_base.getNode(swap_btn, 1).setValue(b);
if (b) kx165tso[n].swap_comm();
}
###########################################################################
# n - NavComm#
# d - adjustment
adjust_nav_frequency = func(n, d) {
kx165tso[n].adjust_nav_frequency(d);
}
###########################################################################
# n - NavComm#
# d - adjustment
adjust_comm_frequency = func(n, d) {
kx165tso[n].adjust_comm_frequency(d);
}
###########################################################################
# Create aliases to drive a radio 3d model in an AI/MP model.
# n - NavComm#
var animate_aimodel = func(n, airoot) {
# Comm
var base = comm_base[n];
var p = "systems/electrical/outputs/comm["~ n ~"]";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = "instrumentation/comm["~ n ~"]/serviceable";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base ~ "/" ~ freq_selected;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base ~ "/" ~ freq_standby;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base ~ "/" ~ swap_btn;
props.globals.getNode(p, 1).alias(airoot.getNode(p));
# Nav
base = nav_base[n];
p = "systems/electrical/outputs/nav["~ n ~"]";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = "instrumentation/nav["~ n ~"]/serviceable";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base ~ "/" ~ freq_selected;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base ~ "/" ~ freq_standby;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = base ~ "/" ~ swap_btn;
props.globals.getNode(p, 1).alias(airoot.getNode(p));
}
###########################################################################
# Create a TDMEncoder node array for sending the current radio state to
# slaves.
# n - NavComm#
var master_send_state = func(n) {
var cb = props.globals.getNode(comm_base[n]);
var nb = props.globals.getNode(nav_base[n]);
return
[
cb.getNode(freq_selected),
cb.getNode(freq_standby),
nb.getNode(freq_selected),
nb.getNode(freq_standby)
];
}
###########################################################################
# Create a SwitchDecoder action array for processing button presses
# from a slave.
# n - Comm#
var master_receive_slave_buttons = func(n) {
return
[
# Comm
func (b) {
if (b) {
swap_comm(n, 1);
settimer(func { swap_comm(n, 0); }, 1.0)
}
},
func (b) {
if (b) { adjust_comm_frequency(n, -0.025); }
},
func (b) {
if (b) { adjust_comm_frequency(n, 0.025); }
},
func (b) {
if (b) { adjust_comm_frequency(n, -1.0); }
},
func (b) {
if (b) { adjust_comm_frequency(n, 1.0); }
},
# Nav
func (b) {
if (b) { swap_nav(n); }
},
func (b) {
if (b) { adjust_nav_frequency(n, -0.05); }
},
func (b) {
if (b) { adjust_nav_frequency(n, 0.05); }
},
func (b) {
if (b) { adjust_nav_frequency(n, -1.0); }
},
func (b) {
if (b) { adjust_nav_frequency(n, 1.0); }
}
];
}
###########################################################################
# Create a TDMDecoder action array for processing the radio state
# from the master.
# n - NavComm#
var slave_receive_master_state = func(n) {
var cb = props.globals.getNode(comm_base[n]);
var nb = props.globals.getNode(nav_base[n]);
return
[
func (v) {
cb.getNode(freq_selected).setValue(v);
},
func (v) {
cb.getNode(freq_standby).setValue(v);
},
func (v) {
nb.getNode(freq_selected).setValue(v);
},
func (v) {
nb.getNode(freq_standby).setValue(v);
}
];
}
###########################################################################
# Create a SwitchEncoder node array for sending button presses
# to the master
# n - NavComm#
var slave_send_buttons = func(n) {
var cb = props.globals.getNode(comm_base[n]);
var nb = props.globals.getNode(nav_base[n]);
return
[
# Comm
cb.getNode(swap_btn, 1),
cb.getNode(freq_decS, 1),
cb.getNode(freq_incS, 1),
cb.getNode(freq_decL, 1),
cb.getNode(freq_incL, 1),
# Nav
nb.getNode(swap_btn, 1),
nb.getNode(freq_decS, 1),
nb.getNode(freq_incS, 1),
nb.getNode(freq_decL, 1),
nb.getNode(freq_incL, 1)
];
}
###########################################################################
# Generic frequency stepper.
# f - frequency property
# d - change
# min - min frequency
# max - max frequency
var adjust_radio_frequency = func(f, d, min, max) {
var old = f.getValue();
var new = old + d;
if (new < min - 0.005) { new = int(max) + (new - int(new)); }
if (new > max + 0.005) {
new = int(min) + (new - int(new));
if (int(new + 0.005) > min) new -= 1;
}
# print("Old: " ~ old ~ " Intermediate: " ~ (old + d) ~ " New: " ~ new);
f.setValue(new);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View file

@ -0,0 +1,599 @@
<?xml version="1.0"?>
<PropertyList>
<path>kx165tso.ac</path>
<animation>
<type>select</type>
<object-name>CommUse</object-name>
<object-name>CommStby</object-name>
<object-name>NavUse</object-name>
<object-name>NavStby</object-name>
<condition>
<property>instrumentation/comm[0]/serviceable</property>
<property>instrumentation/nav[0]/serviceable</property>
<!-- property>instrumentation/nav[0]/power-btn</property -->
</condition>
</animation>
<!-- comm part -->
<animation>
<type>material</type>
<object-name>CommToggle</object-name>
<object-name>NavToggle</object-name>
<emission>
<red-prop>sim/model/instrument-lighting/emission/red</red-prop>
<green-prop>sim/model/instrument-lighting/emission/green</green-prop>
<blue-prop>sim/model/instrument-lighting/emission/blue</blue-prop>
<factor-prop>controls/lighting/instruments-norm</factor-prop>
</emission>
</animation>
<animation>
<type>translate</type>
<object-name>CommToggle</object-name>
<property>instrumentation/comm[0]/frq-swap-btn</property>
<factor>-0.004</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse100M</object-name>
<property>instrumentation/comm[0]/frequencies/selected-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse10M</object-name>
<property>instrumentation/comm[0]/frequencies/selected-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse1M</object-name>
<property>instrumentation/comm[0]/frequencies/selected-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse100K</object-name>
<property>instrumentation/comm[0]/frequencies/selected-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse10K</object-name>
<property>instrumentation/comm[0]/frequencies/selected-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby100M</object-name>
<property>instrumentation/comm[0]/frequencies/standby-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby10M</object-name>
<property>instrumentation/comm[0]/frequencies/standby-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby1M</object-name>
<property>instrumentation/comm[0]/frequencies/standby-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby100K</object-name>
<property>instrumentation/comm[0]/frequencies/standby-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby10K</object-name>
<property>instrumentation/comm[0]/frequencies/standby-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- NAV part -->
<animation>
<type>translate</type>
<object-name>NavToggle</object-name>
<property>instrumentation/nav[0]/frq-swap-btn</property>
<factor>-0.004</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse100M</object-name>
<property>instrumentation/nav[0]/frequencies/selected-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse10M</object-name>
<property>instrumentation/nav[0]/frequencies/selected-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse1M</object-name>
<property>instrumentation/nav[0]/frequencies/selected-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse100K</object-name>
<property>instrumentation/nav[0]/frequencies/selected-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse10K</object-name>
<property>instrumentation/nav[0]/frequencies/selected-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby100M</object-name>
<property>instrumentation/nav[0]/frequencies/standby-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby10M</object-name>
<property>instrumentation/nav[0]/frequencies/standby-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby1M</object-name>
<property>instrumentation/nav[0]/frequencies/standby-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby100K</object-name>
<property>instrumentation/nav[0]/frequencies/standby-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby10K</object-name>
<property>instrumentation/nav[0]/frequencies/standby-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- knobs and buttons -->
<animation>
<type>rotate</type>
<object-name>CommVolume</object-name>
<property>instrumentation/comm[0]/volume</property>
<factor>-270</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
<center>
<x-m>0.0188947</x-m>
<y-m>-0.0620002</y-m>
<z-m>-0.0139999</z-m>
</center>
</animation>
<animation>
<type>translate</type>
<object-name>CommVolume</object-name>
<property>instrumentation/comm[0]/volume</property>
<factor>0.002</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>rotate</type>
<object-name>CommKHz</object-name>
<property>instrumentation/comm[0]/frequencies/standby-mhz</property>
<factor>-1200</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
<center>
<x-m>0.0320882</x-m>
<y-m>-0.022</y-m>
<z-m>-0.012</z-m>
</center>
</animation>
<animation>
<type>rotate</type>
<object-name>NavVolume</object-name>
<property>instrumentation/nav[0]/volume</property>
<factor>-270</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
<center>
<x-m>0.0188946</x-m>
<y-m>0.0180001</y-m>
<z-m>-0.0139999</z-m>
</center>
</animation>
<animation>
<type>translate</type>
<object-name>NavVolume</object-name>
<property>instrumentation/nav[0]/volume</property>
<factor>0.002</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- OSG Hotspots for dual control -->
<animation>
<type>pick</type>
<object-name>CommToggle</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.swap_comm(0, 1);</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>KX165.swap_comm(0, 0);</script>
</binding>
</mod-up>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>CommKHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, 0.025);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, -0.025);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, -0.025);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, 0.025);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>CommMHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, 1.0);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(0, 1.0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>NavToggle</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.swap_nav(0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>NavKHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, 0.05);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, -0.05);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, -0.05);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, 0.05);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>NavMHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, 1.0);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, -1.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(0, 1.0);</script>
</binding>
</action>
</animation>
<animation>
<type>noshadow</type>
</animation>
<animation>
<type>range</type>
<min-m>0</min-m>
<max-m>10</max-m>
</animation>
</PropertyList>

View file

@ -0,0 +1,599 @@
<?xml version="1.0"?>
<PropertyList>
<path>kx165tso.ac</path>
<animation>
<type>select</type>
<object-name>CommUse</object-name>
<object-name>CommStby</object-name>
<object-name>NavUse</object-name>
<object-name>NavStby</object-name>
<condition>
<property>instrumentation/comm[1]/serviceable</property>
<property>instrumentation/nav[1]/serviceable</property>
<!-- property>instrumentation/nav[1]/power-btn</property -->
</condition>
</animation>
<!-- comm part -->
<animation>
<type>material</type>
<object-name>CommToggle</object-name>
<object-name>NavToggle</object-name>
<emission>
<red-prop>sim/model/instrument-lighting/emission/red</red-prop>
<green-prop>sim/model/instrument-lighting/emission/green</green-prop>
<blue-prop>sim/model/instrument-lighting/emission/blue</blue-prop>
<factor-prop>controls/lighting/instruments-norm</factor-prop>
</emission>
</animation>
<animation>
<type>translate</type>
<object-name>CommToggle</object-name>
<property>instrumentation/comm[1]/frq-swap-btn</property>
<factor>-0.004</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse100M</object-name>
<property>instrumentation/comm[1]/frequencies/selected-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse10M</object-name>
<property>instrumentation/comm[1]/frequencies/selected-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse1M</object-name>
<property>instrumentation/comm[1]/frequencies/selected-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse100K</object-name>
<property>instrumentation/comm[1]/frequencies/selected-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommUse10K</object-name>
<property>instrumentation/comm[1]/frequencies/selected-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby100M</object-name>
<property>instrumentation/comm[1]/frequencies/standby-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby10M</object-name>
<property>instrumentation/comm[1]/frequencies/standby-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby1M</object-name>
<property>instrumentation/comm[1]/frequencies/standby-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby100K</object-name>
<property>instrumentation/comm[1]/frequencies/standby-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>CommStby10K</object-name>
<property>instrumentation/comm[1]/frequencies/standby-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- NAV part -->
<animation>
<type>translate</type>
<object-name>NavToggle</object-name>
<property>instrumentation/nav[1]/frq-swap-btn</property>
<factor>-0.004</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse100M</object-name>
<property>instrumentation/nav[1]/frequencies/selected-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse10M</object-name>
<property>instrumentation/nav[1]/frequencies/selected-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse1M</object-name>
<property>instrumentation/nav[1]/frequencies/selected-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse100K</object-name>
<property>instrumentation/nav[1]/frequencies/selected-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavUse10K</object-name>
<property>instrumentation/nav[1]/frequencies/selected-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby100M</object-name>
<property>instrumentation/nav[1]/frequencies/standby-mhz</property>
<step>100</step>
<factor>0.001</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby10M</object-name>
<property>instrumentation/nav[1]/frequencies/standby-mhz</property>
<step>10</step>
<factor>0.01</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby1M</object-name>
<property>instrumentation/nav[1]/frequencies/standby-mhz</property>
<step>1</step>
<factor>0.1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby100K</object-name>
<property>instrumentation/nav[1]/frequencies/standby-mhz</property>
<step>0.1</step>
<factor>1</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>NavStby10K</object-name>
<property>instrumentation/nav[1]/frequencies/standby-mhz</property>
<step>0.01</step>
<factor>10</factor>
<bias>0.0005</bias>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- knobs and buttons -->
<animation>
<type>rotate</type>
<object-name>CommVolume</object-name>
<property>instrumentation/comm[1]/volume</property>
<factor>-270</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
<center>
<x-m>0.0188947</x-m>
<y-m>-0.0620002</y-m>
<z-m>-0.0139999</z-m>
</center>
</animation>
<animation>
<type>translate</type>
<object-name>CommVolume</object-name>
<property>instrumentation/comm[1]/volume</property>
<factor>0.002</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>rotate</type>
<object-name>CommKHz</object-name>
<property>instrumentation/comm[1]/frequencies/standby-mhz</property>
<factor>-1200</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
<center>
<x-m>0.0320882</x-m>
<y-m>-0.022</y-m>
<z-m>-0.012</z-m>
</center>
</animation>
<animation>
<type>rotate</type>
<object-name>NavVolume</object-name>
<property>instrumentation/nav[1]/volume</property>
<factor>-270</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
<center>
<x-m>0.0188946</x-m>
<y-m>0.0180001</y-m>
<z-m>-0.0139999</z-m>
</center>
</animation>
<animation>
<type>translate</type>
<object-name>NavVolume</object-name>
<property>instrumentation/nav[1]/volume</property>
<factor>0.002</factor>
<axis>
<x>1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- OSG Hotspots for dual control -->
<animation>
<type>pick</type>
<object-name>CommToggle</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.swap_comm(1, 1);</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>KX165.swap_comm(1, 0);</script>
</binding>
</mod-up>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>CommKHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, 0.025);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, -0.025);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, -0.025);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, 0.025);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>CommMHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, 1.0);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, -1.0);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, -1.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_comm_frequency(1, 1.0);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>NavToggle</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.swap_nav(1);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>NavKHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, 0.05);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, -0.05);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, -0.05);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, 0.05);</script>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>NavMHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, 1.0);</script>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, -1.0);</script>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, -1.0);</script>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script>KX165.adjust_nav_frequency(1, 1.0);</script>
</binding>
</action>
</animation>
<animation>
<type>noshadow</type>
</animation>
<animation>
<type>range</type>
<min-m>0</min-m>
<max-m>10</max-m>
</animation>
</PropertyList>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -0,0 +1,387 @@
<?xml version="1.0"?>
<!-- CTL 22 Comm1 Control for VHF-22 tranceiver
Active and preset displayed +
6 frequency memory storage
2.375"W x 2.625"H
Freq. range 118.000 - 135.975 (normal) @ 25 khz spacing
Syd Adams
Adapted for dual control by Anders Gidenstam
NOTE: ctl22.nas MUST be loaded as Nasal module VHF22.
-->
<PropertyList>
<!-- Overlay these for the second etc radio. -->
<params>
<serviceable>instrumentation/comm[0]/serviceable</serviceable>
<electrical-supply>systems/electrical/outputs/comm[0]</electrical-supply>
<selected-freq-mhz>instrumentation/comm[0]/frequencies/selected-mhz</selected-freq-mhz>
<standby-freq-mhz>instrumentation/comm[0]/frequencies/standby-mhz</standby-freq-mhz>
<swap-script>VHF22.swap(0);</swap-script>
<small-inc-script>VHF22.adjust_frequency(0, 0.025);</small-inc-script>
<small-dec-script>VHF22.adjust_frequency(0, -0.025);</small-dec-script>
<big-inc-script>VHF22.adjust_frequency(0, 1.0);</big-inc-script>
<big-dec-script>VHF22.adjust_frequency(0, -1.0);</big-dec-script>
</params>
<path>ctl22.ac</path>
<animation>
<type>select</type>
<object-name>freq.001</object-name>
<object-name>freq.002</object-name>
<object-name>freq.003</object-name>
<object-name>freq.dec</object-name>
<object-name>freq.004</object-name>
<object-name>freq.005</object-name>
<object-name>freq.006</object-name>
<condition>
<greater-than>
<property alias="../../../../params/electrical-supply"/>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>stby.001</object-name>
<object-name>stby.002</object-name>
<object-name>stby.003</object-name>
<object-name>stby.dec</object-name>
<object-name>stby.004</object-name>
<object-name>stby.005</object-name>
<object-name>stby.006</object-name>
<condition>
<greater-than>
<property alias="../../../../params/electrical-supply"/>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>mem.annun</object-name>
<condition>
<greater-than>
<property alias="../../../../params/electrical-supply"/>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>rotate</type>
<object-name>CTL-22.pwr</object-name>
<property alias="../../params/serviceable"/>
<interpolation>
<entry><ind>0</ind><dep>0</dep></entry>
<entry><ind>1.0</ind><dep>30</dep></entry>
</interpolation>
<center>
<x-m>0.0</x-m>
<y-m>-0.014</y-m>
<z-m>-0.018</z-m>
</center>
<axis>
<x>-1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- Active Frequency -->
<animation>
<type>textranslate</type>
<object-name>freq.001</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>0.001</factor>
<step>100</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.002</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>0.01</factor>
<step>10</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.003</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>0.1</factor>
<step>1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.004</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>1.0</factor>
<step>0.1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.005</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>10.0</factor>
<step>0.01</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.006</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>100.0</factor>
<step>0.001</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<!-- Preselected Frequency -->
<animation>
<type>textranslate</type>
<object-name>stby.001</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>0.001</factor>
<step>100</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.002</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>0.01</factor>
<step>10</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.003</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>0.1</factor>
<step>1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.004</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>1.0</factor>
<step>0.1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.005</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>10.0</factor>
<step>0.01</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.006</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>100</factor>
<step>0.001</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>pick</type>
<object-name>CTL-22.xfr</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/swap-script"/>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>pwr.off</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>property-assign</command>
<property alias="../../../../params/serviceable"/>
<value>false</value>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>pwr.on</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>property-assign</command>
<property alias="../../../../params/serviceable"/>
<value>true</value>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>freq.knob.kHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-inc-script"/>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-dec-script"/>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-dec-script"/>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-inc-script"/>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>freq.knob.MHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-inc-script"/>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-dec-script"/>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-dec-script"/>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-inc-script"/>
</binding>
</action>
</animation>
</PropertyList>

View file

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<!-- CTL 22 Comm1 Control for VHF-22 tranceiver
Active and preset displayed +
6 frequency memory storage
2.375"W x 2.625"H
Freq. range 118.000 - 135.975 (normal) @ 25 khz spacing
Syd Adams
Adapted for dual control by Anders Gidenstam
NOTE: ctl22.nas MUST be loaded as Nasal module VHF22.
-->
<PropertyList include="ctl22-com.xml">
<params>
<serviceable>instrumentation/comm[0]/serviceable</serviceable>
<electrical-supply>systems/electrical/outputs/comm[0]</electrical-supply>
<selected-freq-mhz>instrumentation/comm[0]/frequencies/selected-mhz</selected-freq-mhz>
<standby-freq-mhz>instrumentation/comm[0]/frequencies/standby-mhz</standby-freq-mhz>
<swap-script>VHF22.swap(0);</swap-script>
<small-inc-script>VHF22.adjust_frequency(0, 0.025);</small-inc-script>
<small-dec-script>VHF22.adjust_frequency(0, -0.025);</small-dec-script>
<big-inc-script>VHF22.adjust_frequency(0, 1.0);</big-inc-script>
<big-dec-script>VHF22.adjust_frequency(0, -1.0);</big-dec-script>
</params>
</PropertyList>

View file

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<!-- CTL 22 Comm1 Control for VHF-22 tranceiver
Active and preset displayed +
6 frequency memory storage
2.375"W x 2.625"H
Freq. range 118.000 - 135.975 (normal) @ 25 khz spacing
Syd Adams
Adapted for dual control by Anders Gidenstam
NOTE: ctl22.nas MUST be loaded as Nasal module VHF22.
-->
<PropertyList include="ctl22-com.xml">
<params>
<serviceable>instrumentation/comm[1]/serviceable</serviceable>
<electrical-supply>systems/electrical/outputs/comm[1]</electrical-supply>
<selected-freq-mhz>instrumentation/comm[1]/frequencies/selected-mhz</selected-freq-mhz>
<standby-freq-mhz>instrumentation/comm[1]/frequencies/standby-mhz</standby-freq-mhz>
<swap-script>VHF22.swap(1);</swap-script>
<small-inc-script>VHF22.adjust_frequency(1, 0.025);</small-inc-script>
<small-dec-script>VHF22.adjust_frequency(1, -0.025);</small-dec-script>
<big-inc-script>VHF22.adjust_frequency(1, 1.0);</big-inc-script>
<big-dec-script>VHF22.adjust_frequency(1, -1.0);</big-dec-script>
</params>
</PropertyList>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,226 @@
###############################################################################
##
## Nasal for dual control of a VHF 22 Comm radio over the multiplayer
## network.
##
## Copyright (C) 2008 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license.
##
###############################################################################
# Note:
# This module MUST be loaded as VHF22.
#
# Slave button presses.
var swap_btn = "frq-swap-btn";
var freq_decS = "freq-decS-clicked";
var freq_incS = "freq-incS-clicked";
var freq_decL = "freq-decL-clicked";
var freq_incL = "freq-incL-clicked";
# Settings
var freq_selected = "frequencies/selected-mhz";
var freq_standby = "frequencies/standby-mhz";
var comm_base = ["instrumentation/comm[0]",
"instrumentation/comm[1]"];
###########################################################################
var master_ctl22 = {
new : func(n) {
var obj = {};
obj.parents = [master_ctl22];
obj.comm_base = props.globals.getNode(comm_base[n]);
return obj;
},
swap : func() {
var tmp = me.comm_base.getNode(freq_selected).getValue();
me.comm_base.getNode(freq_selected).setValue
(me.comm_base.getNode(freq_standby).getValue());
me.comm_base.getNode(freq_standby).setValue(tmp);
},
adjust_frequency : func(d) {
adjust_radio_frequency(
me.comm_base.getNode(freq_standby),
d,
118,
135.975);
}
};
###########################################################################
var slave_ctl22 = {
new : func(n, airoot) {
var obj = {};
obj.parents = [slave_ctl22];
obj.root = airoot;
obj.comm_base = props.globals.getNode(comm_base[n]);
return obj;
},
swap : func() {
var p = me.comm_base.getNode(swap_btn);
print("VHF22[?].SWAP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
adjust_frequency : func(d) {
var p = 0;
if (abs(d) < 0.99) {
p = (d < 0) ? me.comm_base.getNode(freq_decS)
: me.comm_base.getNode(freq_incS);
} else {
p = (d < 0) ? me.comm_base.getNode(freq_decL)
: me.comm_base.getNode(freq_incL);
}
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
}
};
###########################################################################
# The VHF-22 pick animations default to master.
# NOTE: Use make_master() and make_slave_to().
# Do NOT change ctl22 directly.
var ctl22 = [master_ctl22.new(0), master_ctl22.new(1)];
###########################################################################
# API for pick animations and dual control setup.
###########################################################################
###########################################################################
# n - Comm#
var make_master = func(n) {
ctl22[n] = master_ctl22.new(n);
}
###########################################################################
# n - Comm#
var make_slave_to = func(n, airoot) {
ctl22[n] = slave_ctl22.new(n, airoot);
}
###########################################################################
# n - Comm#
var swap = func(n) {
ctl22[n].swap();
}
###########################################################################
# n - Comm#
# d - adjustment
var adjust_frequency = func(n, d) {
ctl22[n].adjust_frequency(d);
}
###########################################################################
# Create aliases to drive a radio 3d model in an AI/MP model.
# n - Comm#
var animate_aimodel = func(n, airoot) {
var p = "systems/electrical/outputs/comm["~ n ~"]";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = comm_base[n] ~ "/serviceable";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = comm_base[n] ~ "/" ~ freq_selected;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = comm_base[n] ~ "/" ~ freq_standby;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
}
###########################################################################
# Create a TDMEncoder node array for sending the current radio state to
# slaves.
# n - Comm#
var master_send_state = func(n) {
var b = props.globals.getNode(comm_base[n]);
return
[
b.getNode(freq_selected),
b.getNode(freq_standby)
];
}
###########################################################################
# Create a SwitchDecoder action array for processing button presses
# from a slave.
# n - Comm#
var master_receive_slave_buttons = func(n) {
return
[
func (b) {
if (b) { swap(n); }
},
func (b) {
if (b) { adjust_frequency(n, -0.025); }
},
func (b) {
if (b) { adjust_frequency(n, 0.025); }
},
func (b) {
if (b) { adjust_frequency(n, -1.0); }
},
func (b) {
if (b) { adjust_frequency(n, 1.0); }
}
];
}
###########################################################################
# Create a TDMDecoder action array for processing the radio state
# from the master.
# n - Comm#
var slave_receive_master_state = func(n) {
var b = props.globals.getNode(comm_base[n]);
return
[
func (v) {
b.getNode(freq_selected).setValue(v);
},
func (v) {
b.getNode(freq_standby).setValue(v);
}
];
}
###########################################################################
# Create a SwitchEncoder node array for sending button presses
# to the master
# n - Comm#
var slave_send_buttons = func(n) {
var b = props.globals.getNode(comm_base[n]);
return
[
b.getNode(swap_btn, 1),
b.getNode(freq_decS, 1),
b.getNode(freq_incS, 1),
b.getNode(freq_decL, 1),
b.getNode(freq_incL, 1),
];
}
###########################################################################
# Generic frequency stepper.
# f - frequency property
# d - change
# min - min frequency
# max - max frequency
var adjust_radio_frequency = func(f, d, min, max) {
var old = f.getValue();
var new = old + d;
if (new < min - 0.005) { new = int(max) + (new - int(new)); }
if (new > max + 0.005) {
new = int(min) + (new - int(new));
if (int(new + 0.005) > min) new -= 1;
}
# print("Old: " ~ old ~ " Intermediate: " ~ (old + d) ~ " New: " ~ new);
f.setValue(new);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -0,0 +1,358 @@
<?xml version="1.0"?>
<!-- CTL 32 Nav1 Control for VIR-32 receiver
Active and preset displayed +
6 frequency memory storage
2.375"W x 2.625"H
Freq. range 108.000 - 117.975 (normal)
Strap option 133.00 - 135.95
05 khz spacing
Syd Adams
Adapted for dual control by Anders Gidenstam
NOTE: ctl32.nas MUST be loaded as Nasal module VIR32.
-->
<PropertyList>
<params>
<serviceable>instrumentation/nav[0]/serviceable</serviceable>
<electrical-supply>systems/electrical/outputs/nav[0]</electrical-supply>
<selected-freq-mhz>instrumentation/nav[0]/frequencies/selected-mhz</selected-freq-mhz>
<standby-freq-mhz>instrumentation/nav[0]/frequencies/standby-mhz</standby-freq-mhz>
<swap-script>VIR32.swap(0);</swap-script>
<small-inc-script>VIR32.adjust_frequency(0, 0.05);</small-inc-script>
<small-dec-script>VIR32.adjust_frequency(0, -0.05);</small-dec-script>
<big-inc-script>VIR32.adjust_frequency(0, 1.0);</big-inc-script>
<big-dec-script>VIR32.adjust_frequency(0, -1.0);</big-dec-script>
</params>
<path>ctl32.ac</path>
<animation>
<type>select</type>
<object-name>freq.001</object-name>
<object-name>freq.002</object-name>
<object-name>freq.003</object-name>
<object-name>freq.dec</object-name>
<object-name>freq.004</object-name>
<object-name>freq.005</object-name>
<condition>
<greater-than>
<property alias="../../../../params/electrical-supply"/>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>stby.001</object-name>
<object-name>stby.002</object-name>
<object-name>stby.003</object-name>
<object-name>stby.dec</object-name>
<object-name>stby.004</object-name>
<object-name>stby.005</object-name>
<condition>
<greater-than>
<property alias="../../../../params/electrical-supply"/>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>mem.annun</object-name>
<condition>
<greater-than>
<property alias="../../../../params/electrical-supply"/>
<value>1</value>
</greater-than>
</condition>
</animation>
<animation>
<type>rotate</type>
<object-name>CTL-32.pwr</object-name>
<property alias="../../params/serviceable"/>
<interpolation>
<entry><ind>0</ind><dep>0</dep></entry>
<entry><ind>1.0</ind><dep>30</dep></entry>
</interpolation>
<center>
<x-m>0.0</x-m>
<y-m>-0.014</y-m>
<z-m>-0.018</z-m>
</center>
<axis>
<x>-1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<!-- Active Frequency -->
<animation>
<type>textranslate</type>
<object-name>freq.001</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>0.001</factor>
<step>100</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.002</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>0.01</factor>
<step>10</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.003</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>0.1</factor>
<step>1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.004</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>1</factor>
<step>0.1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>freq.005</object-name>
<property alias="../../params/selected-freq-mhz"/>
<factor>10</factor>
<step>0.01</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<!-- Preselected Frequency -->
<animation>
<type>textranslate</type>
<object-name>stby.001</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>0.001</factor>
<step>100</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.002</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>0.01</factor>
<step>10</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.003</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>0.1</factor>
<step>1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.004</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>1</factor>
<step>0.1</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>textranslate</type>
<object-name>stby.005</object-name>
<property alias="../../params/standby-freq-mhz"/>
<factor>10</factor>
<step>0.01</step>
<bias>0.0005</bias>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>pick</type>
<object-name>CTL-32.xfr</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/swap-script"/>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>pwr.off</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>property-assign</command>
<property alias="../../../../params/serviceable"/>
<value>false</value>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>pwr.on</object-name>
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>property-assign</command>
<property alias="../../../../params/serviceable"/>
<value>true</value>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>freq.knob.kHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-inc-script"/>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-dec-script"/>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-dec-script"/>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/small-inc-script"/>
</binding>
</action>
</animation>
<animation>
<type>pick</type>
<object-name>freq.knob.MHz</object-name>
<action>
<button>0</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-inc-script"/>
</binding>
</action>
<action>
<button>1</button>
<repeatable>true</repeatable>
<interval-sec>0.2</interval-sec>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-dec-script"/>
</binding>
</action>
<action>
<button>3</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-dec-script"/>
</binding>
</action>
<action>
<button>4</button>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
<script alias="../../../../params/big-inc-script"/>
</binding>
</action>
</animation>
</PropertyList>

View file

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<!-- CTL 32 Nav1 Control for VIR-32 receiver
Active and preset displayed +
6 frequency memory storage
2.375"W x 2.625"H
Freq. range 108.000 - 117.975 (normal)
Strap option 133.00 - 135.95
05 khz spacing
Syd Adams
Adapted for dual control by Anders Gidenstam
NOTE: ctl32.nas MUST be loaded as Nasal module VIR32.
-->
<PropertyList include="ctl32-nav.xml">
<params>
<serviceable>instrumentation/nav[0]/serviceable</serviceable>
<electrical-supply>systems/electrical/outputs/nav[0]</electrical-supply>
<selected-freq-mhz>instrumentation/nav[0]/frequencies/selected-mhz</selected-freq-mhz>
<standby-freq-mhz>instrumentation/nav[0]/frequencies/standby-mhz</standby-freq-mhz>
<swap-script>VIR32.swap(0);</swap-script>
<small-inc-script>VIR32.adjust_frequency(0, 0.05);</small-inc-script>
<small-dec-script>VIR32.adjust_frequency(0, -0.05);</small-dec-script>
<big-inc-script>VIR32.adjust_frequency(0, 1.0);</big-inc-script>
<big-dec-script>VIR32.adjust_frequency(0, -1.0);</big-dec-script>
</params>
</PropertyList>

View file

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<!-- CTL 32 Nav1 Control for VIR-32 receiver
Active and preset displayed +
6 frequency memory storage
2.375"W x 2.625"H
Freq. range 108.000 - 117.975 (normal)
Strap option 133.00 - 135.95
05 khz spacing
Syd Adams
Adapted for dual control by Anders Gidenstam
NOTE: ctl32.nas MUST be loaded as Nasal module VIR32.
-->
<PropertyList include="ctl32-nav.xml">
<params>
<serviceable>instrumentation/nav[1]/serviceable</serviceable>
<electrical-supply>systems/electrical/outputs/nav[1]</electrical-supply>
<selected-freq-mhz>instrumentation/nav[1]/frequencies/selected-mhz</selected-freq-mhz>
<standby-freq-mhz>instrumentation/nav[1]/frequencies/standby-mhz</standby-freq-mhz>
<swap-script>VIR32.swap(1);</swap-script>
<small-inc-script>VIR32.adjust_frequency(1, 0.05);</small-inc-script>
<small-dec-script>VIR32.adjust_frequency(1, -0.05);</small-dec-script>
<big-inc-script>VIR32.adjust_frequency(1, 1.0);</big-inc-script>
<big-dec-script>VIR32.adjust_frequency(1, -1.0);</big-dec-script>
</params>
</PropertyList>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,226 @@
###############################################################################
##
## Nasal for dual control of a VIR 32 Nav radio over the multiplayer
## network.
##
## Copyright (C) 2008 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Note:
# This module MUST be loaded as VIR32.
#
# Slave button presses.
var swap_btn = "frq-swap-btn";
var freq_decS = "freq-decS-clicked";
var freq_incS = "freq-incS-clicked";
var freq_decL = "freq-decL-clicked";
var freq_incL = "freq-incL-clicked";
# Settings
var freq_selected = "frequencies/selected-mhz";
var freq_standby = "frequencies/standby-mhz";
var nav_base = ["instrumentation/nav[0]",
"instrumentation/nav[1]"];
###########################################################################
var master_ctl32 = {
new : func(n) {
var obj = {};
obj.parents = [master_ctl32];
obj.nav_base = props.globals.getNode(nav_base[n]);
return obj;
},
swap : func() {
var tmp = me.nav_base.getNode(freq_selected).getValue();
me.nav_base.getNode(freq_selected).setValue
(me.nav_base.getNode(freq_standby).getValue());
me.nav_base.getNode(freq_standby).setValue(tmp);
},
adjust_frequency : func(d) {
adjust_radio_frequency(
me.nav_base.getNode(freq_standby),
d,
108,
117.975);
}
};
###########################################################################
var slave_ctl32 = {
new : func(n, airoot) {
var obj = {};
obj.parents = [slave_ctl32];
obj.root = airoot;
obj.nav_base = props.globals.getNode(nav_base[n]);
return obj;
},
swap : func() {
var p = me.nav_base.getNode(swap_btn);
print("VIR32[?].SWAP");
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
},
adjust_frequency : func(d) {
var p = 0;
if (abs(d) < 0.99) {
p = (d < 0) ? me.nav_base.getNode(freq_decS)
: me.nav_base.getNode(freq_incS);
} else {
p = (d < 0) ? me.nav_base.getNode(freq_decL)
: me.nav_base.getNode(freq_incL);
}
if (!p.getValue()) {
p.setValue(1);
settimer(func { p.setValue(0); },
1.0);
}
}
};
###########################################################################
# The VIR-32 pick animations default to master.
# NOTE: Use make_master() and make_slave_to().
# Do NOT change ctl32 directly.
var ctl32 = [master_ctl32.new(0), master_ctl32.new(1)];
###########################################################################
# API for pick animations and dual control setup.
###########################################################################
###########################################################################
# n - Nav#
var make_master = func(n) {
ctl32[n] = master_ctl32.new(n);
}
###########################################################################
# n - Nav#
var make_slave_to = func(n, airoot) {
ctl32[n] = slave_ctl32.new(n, airoot);
}
###########################################################################
# n - Nav#
var swap = func(n) {
ctl32[n].swap();
}
###########################################################################
# n - Nav#
# d - adjustment
var adjust_frequency = func(n, d) {
ctl32[n].adjust_frequency(d);
}
###########################################################################
# Create aliases to drive a radio 3d model in an AI/MP model.
# n - Nav#
var animate_aimodel = func(n, airoot) {
var p = "systems/electrical/outputs/nav["~ n ~"]";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = "instrumentation/nav["~ n ~"]/serviceable";
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = nav_base[n] ~ "/" ~ freq_selected;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
p = nav_base[n] ~ "/" ~ freq_standby;
airoot.getNode(p, 1).alias(props.globals.getNode(p));
}
###########################################################################
# Create a TDMEncoder node array for sending the current radio state to
# slaves.
# n - Nav#
var master_send_state = func(n) {
var b = props.globals.getNode(nav_base[n]);
return
[
b.getNode(freq_selected),
b.getNode(freq_standby)
];
}
###########################################################################
# Create a SwitchDecoder action array for processing button presses
# from a slave.
# n - Nav#
var master_receive_slave_buttons = func(n) {
return
[
func (b) {
if (b) { swap(n); }
},
func (b) {
if (b) { adjust_frequency(n, -0.05); }
},
func (b) {
if (b) { adjust_frequency(n, 0.05); }
},
func (b) {
if (b) { adjust_frequency(n, -1.0); }
},
func (b) {
if (b) { adjust_frequency(n, 1.0); }
}
];
}
###########################################################################
# Create a TDMDecoder action array for processing the radio state
# from the master.
# n - Nav#
var slave_receive_master_state = func(n) {
var b = props.globals.getNode(nav_base[n]);
return
[
func (v) {
b.getNode(freq_selected).setValue(v);
},
func (v) {
b.getNode(freq_standby).setValue(v);
}
];
}
###########################################################################
# Create a SwitchEncoder node array for sending button presses
# to the master
# n - Nav#
var slave_send_buttons = func(n) {
var b = props.globals.getNode(nav_base[n]);
return
[
b.getNode(swap_btn, 1),
b.getNode(freq_decS, 1),
b.getNode(freq_incS, 1),
b.getNode(freq_decL, 1),
b.getNode(freq_incL, 1),
];
}
###########################################################################
# Generic frequency stepper.
# f - frequency property
# d - change
# min - min frequency
# max - max frequency
var adjust_radio_frequency = func(f, d, min, max) {
var old = f.getValue();
var new = old + d;
if (new < min - 0.005) { new = int(max) + (new - int(new)); }
if (new > max + 0.005) {
new = int(min) + (new - int(new));
if (int(new + 0.005) > min) new -= 1;
}
# print("Old: " ~ old ~ " Intermediate: " ~ (old + d) ~ " New: " ~ new);
f.setValue(new);
}

View file

@ -0,0 +1,51 @@
<?xml version="1.0"?>
<!-- KI 227-01
Bendix/King Slaved Magnetic Heading Indicator
Syd Adams
Anders Gidenstam (changed to gyro slaved compass card)
-->
<PropertyList>
<path>Aircraft/Instruments-3d/kr87-adf/ki227.ac</path>
<texture-path>Aircraft/Instruments-3d/kr87-adf/</texture-path>
<animation>
<type>material</type>
<object-name>KI227card</object-name>
<object-name>KI227.needle</object-name>
<object-name>KI227.knob</object-name>
<object-name>KI227.face</object-name>
<emission>
<red>0.8</red>
<green>0.4</green>
<blue>0.2</blue>
<factor-prop>/systems/electrical/outputs/instrument-lights</factor-prop>
</emission>
</animation>
<animation>
<type>rotate</type>
<object-name>KI227card</object-name>
<!-- Slave the compass card to the HSI gyro - a single needle RMI. -->
<property>/instrumentation/heading-indicator/indicated-heading-deg</property>
<factor>-1</factor>
<axis>
<x>-1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
<animation>
<type>rotate</type>
<object-name>KI227.needle</object-name>
<property>/instrumentation/adf/indicated-bearing-deg</property>
<axis>
<x>-1</x>
<y>0</y>
<z>0</z>
</axis>
</animation>
</PropertyList>

View file

@ -0,0 +1,90 @@
Dual control for FlightGear/CVS (copilot OSG only)
--------------------------------------------------
Anders Gidenstam (anders at gidenstam dot org)
This collection of Nasal code and instruments enables a pilot and
copilot to jointly fly an aircraft over the FlightGear multiplayer
network. Pilot and copilot can have shared control over primary
flight controls, throttle, mixture, elevator trim, flaps, brakes,
cockpit switches, part of the radio stack and instrument settings
and so on.
To use the system two "aircraft" needs to be created:
- The pilot uses the original aircraft (or a variant thereof).
The pilot need to specify the callsign of the copilot (other copilots
will be ignored).
Usage example:
fgfs --aircraft=ZLT-NT --prop:/sim/remote/pilot-callsign="copilot"
- The copilot uses a special "aircraft", <aircraft>-copilot, which
piggybacks on the designated pilot and captures the local control
inputs. A current limitation is that only the cockpit view
is jitter free. There is also a noticeable delay between control inputs
and effect, since they are passed via the the multiplayer protocol.
The severity of this delay depend on round trip time and some other
factors - the delay seems significantly longer than the round trip time
itself which is due to buffering in the MP protocol receiver.
That said, I have flown successfully as copilot in a setup with
100-120ms round trip time between both pilot and server and copilot and
server (total delay >500ms). Landing is a bit exciting in that
case, however.
Usage example:
fgfs --aircraft=ZLT-NT-copilot --prop:/sim/remote/pilot-callsign="pilot"
Visit http://www.gidenstam.org/FlightGear/DualControl/ for the latest
information.
Developer notes
---------------
The dual control mechanism is divided into to several parts:
- the generic core modules in DualControl/ ;
- the 3d instrument sharing wrappers in DualControl/instruments/ ; and
- the aircraft specific configuration in Systems/ZLT-NT-dual-control.nas
and the ZLT-NT/-set/-copilot-set files.
See the ZLT-NT aircraft for an example how everything come together.
aircraft_dual_control
---------------------
The aircraft specific dual control Nasal module MUST be loaded as
aircraft_dual_control and MUST define the following variables and
functions:
pilot_connect_copilot(copilot) : returns a list of DCT components
Does whatever initialization needed to connect the copilot and
returns a list of dual-control-tools components whose update() method will
be called (in list order) once per frame.
copilot is the node hash for the base of the multiplayer tree for the
copilot user.
pilot_disconnect_copilot() : void
Does whatever cleanup needed when the copilot disconnects.
copilot_connect_pilot(pilot) : returns a list of DCT components
Does whatever initialization needed to connect to the pilot and
returns a list of dual-control-tools components whose update() method will
be called (in list order) once per frame.
pilot is the node hash for the base of the multiplayer tree for the
pilot user.
copilot_disconnect_pilot() :
Does whatever cleanup needed when the pilot disconnects.
pilot_type : string
The identifying string of the pilot aircraft is the path of the
3d model XML file of the pilot aircraft (as found in sim/model/path
under the multiplayer entry).
copilot_type : string
The identifying string of the copilot aircraft is the path of the
3d model XML file of the copilot aircraft (as found in sim/model/path
under the multiplayer entry).

View file

@ -0,0 +1,255 @@
###############################################################################
## $Id$
##
## Nasal for copilot for dual control over the multiplayer network.
##
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Renaming (almost :)
var DCT = dual_control_tools;
var ADC = aircraft_dual_control;
# NOTE: By loading the aircraft specific dual control module
# as <aircraft_dual_control> this file is generic.
# The aircraft specific modul must set the variables
# pilot_type and copilot_type to the name (with full path) of
# main 3d model XML for the pilot and copilot aircraft.
# This module should be loades under the name dual_control.
# Allow aircraft to override the copilot view name. Deprecated.
if (!contains(ADC, "copilot_view")) {
ADC.copilot_view = "Copilot View";
}
# Properties for position and orientation of local aircraft.
var l_lat = "/position/latitude-deg";
var l_lon = "/position/longitude-deg";
var l_alt = "/position/altitude-ft";
var l_heading = "/orientation/heading-deg";
var l_pitch = "/orientation/pitch-deg";
var l_roll = "/orientation/roll-deg";
# Replicate remote state.
var r_airspeed = "velocities/true-airspeed-kt";
var l_airspeed = "/velocities/airspeed-kt";
var vertspeed = "velocities/vertical-speed-fps";
# Default external views to slave to the MP pilot.
var views = {};
views["Helicopter View"] = 2;
views["Chase View"] = 3;
views["Tower View"] = 0;
views["Fly-By View"] = 1;
views["Chase View Without Yaw"] = 1;
######################################################################
# Connect to new pilot
var process_data = 0;
var connect = func (pilot) {
# Set external view eye and target paths.
foreach (var vn; keys(views)) {
var view_cfg = "/sim/view[" ~ view.indexof(vn) ~ "]/config";
setprop(view_cfg ~ "/at-model", 0);
if (views[vn] > 0) {
setprop(view_cfg ~ "/eye-lat-deg-path",
pilot.getNode(DCT.lat_mpp).getPath());
setprop(view_cfg ~ "/eye-lon-deg-path",
pilot.getNode(DCT.lon_mpp).getPath());
setprop(view_cfg ~ "/eye-alt-ft-path",
pilot.getNode(DCT.alt_mpp).getPath());
}
if (views[vn] > 1) {
setprop(view_cfg ~ "/eye-heading-deg-path",
pilot.getNode(DCT.heading_mpp).getPath());
}
if (views[vn] > 2) {
setprop(view_cfg ~ "/eye-pitch-deg-path",
pilot.getNode(DCT.pitch_mpp).getPath());
setprop(view_cfg ~ "/eye-roll-deg-path",
pilot.getNode(DCT.roll_mpp).getPath());
}
setprop(view_cfg ~ "/target-lat-deg-path",
pilot.getNode(DCT.lat_mpp).getPath());
setprop(view_cfg ~ "/target-lon-deg-path",
pilot.getNode(DCT.lon_mpp).getPath());
setprop(view_cfg ~ "/target-alt-ft-path",
pilot.getNode(DCT.alt_mpp).getPath());
setprop(view_cfg ~ "/target-heading-deg-path",
pilot.getNode(DCT.heading_mpp).getPath());
setprop(view_cfg ~ "/target-pitch-deg-path",
pilot.getNode(DCT.pitch_mpp).getPath());
setprop(view_cfg ~ "/target-roll-deg-path",
pilot.getNode(DCT.roll_mpp).getPath());
}
# Tweak MP/AI filters
pilot.getNode("controls/allow-extrapolation").setBoolValue(1);
pilot.getNode("controls/lag-adjust-system-speed").setValue(5.0);
# Set up property aliases
# Set up property mappings.
process_data =
[
# Map /postition/*
DCT.Translator.new
(pilot.getNode(DCT.lat_mpp), props.globals.getNode(l_lat)),
DCT.Translator.new
(pilot.getNode(DCT.lon_mpp), props.globals.getNode(l_lon)),
DCT.Translator.new
(pilot.getNode(DCT.alt_mpp), props.globals.getNode(l_alt)),
# Map /orientation/*
DCT.Translator.new
(pilot.getNode(DCT.heading_mpp),
props.globals.getNode(l_heading)),
DCT.Translator.new
(pilot.getNode(DCT.pitch_mpp),
props.globals.getNode(l_pitch)),
DCT.Translator.new
(pilot.getNode(DCT.roll_mpp),
props.globals.getNode(l_roll)),
# Map /velocities/*
DCT.Translator.new
(pilot.getNode(r_airspeed),
props.globals.getNode(l_airspeed)),
DCT.Translator.new
(pilot.getNode(vertspeed),
props.globals.getNode(vertspeed)),
] ~ ADC.copilot_connect_pilot(pilot);
print("Dual control ... connected to pilot.");
setprop("/sim/messages/copilot", "Welcome aboard.");
}
var disconnect = func {
# Reset external view eye and target paths.
foreach (var vn; keys(views)) {
var view_cfg = "/sim/view[" ~ view.indexof(vn) ~ "]/config";
if (views[vn] > 0) {
setprop(view_cfg ~ "/eye-lat-deg-path",
"/position/latitude-deg");
setprop(view_cfg ~ "/eye-lon-deg-path",
"/position/longitude-deg");
setprop(view_cfg ~ "/eye-alt-ft-path",
"/position/altitude-ft");
}
if (views[vn] > 1) {
setprop(view_cfg ~ "/eye-heading-deg-path",
"/orientation/heading-deg");
}
if (views[vn] > 2) {
setprop(view_cfg ~ "/eye-pitch-deg-path",
"/orientation/pitch-deg");
setprop(view_cfg ~ "/eye-roll-deg-path",
"/orientation/roll-deg");
}
setprop(view_cfg ~ "/target-lat-deg-path",
"/sim/viewer/target/latitude-deg");
setprop(view_cfg ~ "/target-lon-deg-path",
"/sim/viewer/target/longitude-deg");
setprop(view_cfg ~ "/target-alt-ft-path",
"/sim/viewer/target/altitude-ft");
setprop(view_cfg ~ "/target-heading-deg-path",
"/sim/viewer/target/heading-deg");
setprop(view_cfg ~ "/target-pitch-deg-path",
"/sim/viewer/target/pitch-deg");
setprop(view_cfg ~ "/target-roll-deg-path",
"/sim/viewer/target/roll-deg");
}
}
######################################################################
# Main loop singleton class.
var main = {
init : func {
me.loopid = 0;
me.active = 0;
setlistener("/ai/models/model-added", func {
settimer(func { me.activate(); }, 2);
});
print("Copilot dual control ... initialized");
settimer(func { me.activate(); }, 5);
},
reset : func {
if (me.active) {
print("Dual control ... disconnected from pilot.");
disconnect();
ADC.copilot_disconnect_pilot();
}
me.active = 0;
me.loopid += 1;
me._loop_(me.loopid);
},
activate : func {
if (!me.active) {
me.reset();
}
},
update : func {
var mpplayers =
props.globals.getNode("/ai/models").getChildren("multiplayer");
var r_callsign = getprop("/sim/remote/pilot-callsign");
foreach (var pilot; mpplayers) {
if ((pilot.getChild("valid").getValue()) and
(pilot.getChild("callsign") != nil) and
(pilot.getChild("callsign").getValue() == r_callsign)) {
if (me.active == 0) {
# Note: sim/model/path contains the model XML file.
if ((pilot.getNode("sim/model/path") != nil) and
(pilot.getNode("sim/model/path").getValue() ==
ADC.pilot_type)) {
me.active = 1;
connect(pilot);
} else {
print("Dual control ... pilot rejected - wrong aircraft type.");
me.loopid += 1;
return;
}
}
# Mess with the MP filters. Highly experimental.
if (pilot.getNode("controls/lag-time-offset") != nil) {
var v = pilot.getNode("controls/lag-time-offset").getValue();
#pilot.getNode("controls/lag-time-offset").setValue(0.99 * v);
}
foreach (var w; process_data) {
w.update();
}
return;
}
}
# The pilot player is not around. Idle loop.
if (me.active) {
print("Dual control ... disconnected from pilot.");
disconnect();
ADC.copilot_disconnect_pilot();
}
me.active = 0;
me.loopid += 1;
},
_loop_ : func(id) {
id == me.loopid or return;
me.update();
settimer(func { me._loop_(id); }, 0);
}
};
###############################################################################
# Initialization.
var last_view = 0;
setlistener("/sim/signals/fdm-initialized", func {
main.init();
});

View file

@ -0,0 +1,644 @@
###############################################################################
##
## Nasal module for dual control over the multiplayer network.
##
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
## MP properties
var lat_mpp = "position/latitude-deg";
var lon_mpp = "position/longitude-deg";
var alt_mpp = "position/altitude-ft";
var heading_mpp = "orientation/true-heading-deg";
var pitch_mpp = "orientation/pitch-deg";
var roll_mpp = "orientation/roll-deg";
# Import components from the mp_broadcast module.
var Binary = mp_broadcast.Binary;
var MessageChannel = mp_broadcast.MessageChannel;
###############################################################################
# Utility classes
############################################################
# Translate a property into another.
# Factor and offsets are only used for numeric values.
# src - source : property node
# dest - destination : property node
# factor - : double
# offset - : double
var Translator = {};
Translator.new = func (src = nil, dest = nil, factor = 1, offset = 0) {
var obj = { parents : [Translator],
src : src,
dest : dest,
factor : factor,
offset : offset };
if (obj.src == nil or obj.dest == nil) {
print("Translator[");
print(" ", debug.string(obj.src));
print(" ", debug.string(obj.dest));
print("]");
fail();
}
return obj;
}
Translator.update = func () {
var v = me.src.getValue();
if (is_num(v)) {
me.dest.setValue(me.factor * v + me.offset);
} else {
if (typeof(v) == "scalar")
me.dest.setValue(v);
}
}
############################################################
# Detects flanks on two insignals encoded in a property.
# - positive signal up/down flank
# - negative signal up/down flank
# n - source : property node
# on_positive_flank - action : func (v)
# on_negative_flank - action : func (v)
var EdgeTrigger = {};
EdgeTrigger.new = func (n, on_positive_flank, on_negative_flank) {
var obj = { parents : [EdgeTrigger],
old : 0,
node : n,
pos_flank : on_positive_flank,
neg_flank : on_negative_flank };
if (obj.node == nil) {
print("EdgeTrigger[");
print(" ", debug.string(obj.node));
print("]");
fail();
}
return obj;
}
EdgeTrigger.update = func {
# NOTE: float MP properties get interpolated.
# This detector relies on that steady state is reached between
# flanks.
var val = me.node.getValue();
if (!is_num(val)) return;
if (me.old == 1) {
if (val < me.old) {
me.pos_flank(0);
}
} elsif (me.old == 0) {
if (val > me.old) {
me.pos_flank(1);
} elsif (val < me.old) {
me.neg_flank(1);
}
} elsif (me.old == -1) {
if (val > me.old) {
me.neg_flank(0);
}
}
me.old = val;
}
############################################################
# StableTrigger: Triggers an action when a MPP property
# becomes stable (i.e. doesn't change for
# MIN_STABLE seconds).
# src - MP prop : property node
# action - action to take when the value becomes stable : [func(v)]
# An action is triggered when value has stabilized.
var StableTrigger = {};
StableTrigger.new = func (src, action) {
var obj = { parents : [StableTrigger],
src : src,
action : action,
old : 0,
stable_since : 0,
wait : 0,
MIN_STABLE : 0.01 };
# Error checking.
var bad = (obj.src == nil) or (action = nil);
if (bad) {
print("StableTrigger[");
print(" ", debug.string(obj.src));
print(" ", debug.string(obj.action));
print("]");
fail();
}
return obj;
}
StableTrigger.update = func () {
var v = me.src.getValue();
if (!is_num(v)) return;
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
if ((me.old == v) and
((t - me.stable_since) > me.MIN_STABLE) and (me.wait == 1)) {
# Trigger action.
me.action(v);
me.wait = 0;
} elsif (me.old == v) {
# Wait. This is either before the signal is stable or after the action.
} else {
me.stable_since = t;
me.wait = 1;
me.old = me.src.getValue();
}
}
############################################################
# Selects the most recent value of two properties.
# src1 - : property node
# src2 - : property node
# dest - : property node
# threshold - : double
var MostRecentSelector = {};
MostRecentSelector.new = func (src1, src2, dest, threshold) {
var obj = { parents : [MostRecentSelector],
old1 : 0,
old2 : 0,
src1 : src1,
src2 : src2,
dest : dest,
thres : threshold };
if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) {
print("MostRecentSelector[");
print(" ", debug.string(obj.src1));
print(" ", debug.string(obj.src2));
print(" ", debug.string(obj.dest));
print("]");
}
return obj;
}
MostRecentSelector.update = func {
var v1 = me.src1.getValue();
var v2 = me.src2.getValue();
if (!is_num(v1) and !is_num(v2)) return;
elsif (!is_num(v1)) me.dest.setValue(v2);
elsif (!is_num(v2)) me.dest.setValue(v1);
else {
if (abs (v2 - me.old2) > me.thres) {
me.old2 = v2;
me.dest.setValue(me.old2);
}
if (abs (v1 - me.old1) > me.thres) {
me.old1 = v1;
me.dest.setValue(me.old1);
}
}
}
############################################################
# Adds two input properties.
# src1 - : property node
# src2 - : property node
# dest - : property node
var Adder = {};
Adder.new = func (src1, src2, dest) {
var obj = { parents : [DeltaAccumulator],
src1 : src1,
src2 : src2,
dest : dest };
if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) {
print("Adder[");
print(" ", debug.string(obj.src1));
print(" ", debug.string(obj.src2));
print(" ", debug.string(obj.dest));
print("]");
fail();
}
return obj;
}
Adder.update = func () {
var v1 = me.src1.getValue();
var v2 = me.src2.getValue();
if (!is_num(v1) or !is_num(v2)) return;
me.dest.setValue(v1 + v2);
}
############################################################
# Adds the delta of src to dest.
# src - : property node
# dest - : property node
var DeltaAdder = {};
DeltaAdder.new = func (src, dest) {
var obj = { parents : [DeltaAdder],
old : 0,
src : src,
dest : dest };
if (obj.src == nil or obj.dest == nil) {
print("DeltaAdder[", debug.string(obj.src), ", ",
debug.string(obj.dest), "]");
fail();
}
return obj;
}
DeltaAdder.update = func () {
var v = me.src.getValue();
if (!is_num(v)) return;
me.dest.setValue((v - me.old) + me.dest.getValue());
me.old = v;
}
############################################################
# Switch encoder: Encodes upto 32 boolean properties in one
# int property.
# inputs - list of property nodes
# dest - where the bitmask is stored : property node
var SwitchEncoder = {};
SwitchEncoder.new = func (inputs, dest) {
var obj = { parents : [SwitchEncoder],
inputs : inputs,
dest : dest };
# Error checking.
var bad = (obj.dest == nil);
foreach (var i; inputs) {
if (i == nil) { bad = 1; }
}
if (bad) {
print("SwitchEncoder[");
foreach (var i; inputs) {
print(" ", debug.string(i));
}
print(" ", debug.string(obj.dest));
print("]");
fail();
}
return obj;
}
SwitchEncoder.update = func () {
var v = 0;
var b = 1;
forindex (var i; me.inputs) {
if (me.inputs[i].getBoolValue()) {
v = v + b;
}
b *= 2;
}
me.dest.setIntValue(v);
}
############################################################
# Switch decoder: Decodes a bitmask in an int property.
# src - : property node
# actions - list of actions : [func(b)]
# Actions are triggered when their input bit change.
# Due to interpolation the decoder needs to wait for a
# stable input value.
var SwitchDecoder = {};
SwitchDecoder.new = func (src, actions) {
var obj = { parents : [SwitchDecoder],
wait : 0,
old : 0,
old_stable : 0,
stable_since : 0,
reset : 1,
src : src,
actions : actions,
MIN_STABLE : 0.1 };
# Error checking.
var bad = (obj.src == nil);
foreach (var a; obj.actions) {
if (a == nil) { bad = 1; }
}
if (bad) {
print("SwitchDecoder[");
print(" ", debug.string(obj.src));
foreach (var a; obj.actions) {
print(" ", debug.string(a));
}
print("]");
fail();
}
return obj;
}
SwitchDecoder.update = func () {
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
var v = me.src.getValue();
if (!is_num(v)) return;
if ((me.old == v) and ((t - me.stable_since) > me.MIN_STABLE) and
(me.wait == 1)) {
var ov = me.old_stable;
# Use this to improve.
#<cptf> here's the boring version: var bittest = func(u, b) { while (b) { u = int(u / 2); b -= 1; } u != int(u / 2) * 2; }
forindex (var i; me.actions) {
var m = math.mod(v, 2);
var om = math.mod(ov, 2);
if ((m != om or me.reset)) { me.actions[i](m?1:0); }
v = (v - m)/2;
ov = (ov - om)/2;
}
me.old_stable = me.src.getValue();
me.wait = 0;
me.reset = 0;
} elsif (me.old == v) {
# Wait. This is either before the bitmask is stable or after
# it has been processed.
} else {
me.stable_since = t;
me.wait = 1;
me.old = me.src.getValue();
}
}
############################################################
# Time division multiplexing encoder: Transmits a list of
# properties over a MP enabled string property.
# inputs - input properties : [property node]
# dest - MP string prop : property node
# Note: TDM can have high latency so it is best used for
# non-time critical properties.
var TDMEncoder = {};
TDMEncoder.new = func (inputs, dest) {
var obj = { parents : [TDMEncoder],
inputs : inputs,
channel : MessageChannel.new(dest,
func (msg) {
print("This should not happen!");
}),
MIN_INT : 0.25,
last_time : 0,
next_item : 0,
old : [] };
# Error checking.
var bad = (dest == nil) or (obj.channel == nil);
foreach (var i; inputs) {
if (i == nil) { bad = 1; }
}
if (bad) {
print("TDMEncoder[");
foreach (var i; inputs) {
print(" ", debug.string(i));
}
print(" ", debug.string(dest));
print("]");
}
setsize(obj.old, size(obj.inputs));
return obj;
}
TDMEncoder.update = func () {
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
if (t > me.last_time + me.MIN_INT) {
var n = size(me.inputs);
while (1) {
var v = me.inputs[me.next_item].getValue();
if ((n <= 0) or (me.old[me.next_item] != v)) {
# Set the MP properties to send the next item.
me.channel.send(Binary.encodeByte(me.next_item) ~
Binary.encodeDouble(v));
me.old[me.next_item] = v;
me.last_time = t;
me.next_item += 1;
if (me.next_item >= size(me.inputs)) { me.next_item = 0; }
return;
} else {
# Search for changed property.
n -= 1;
me.next_item += 1;
if (me.next_item >= size(me.inputs)) { me.next_item = 0; }
}
}
}
}
############################################################
# Time division multiplexing decoder: Receives a list of
# properties over a MP enabled string property.
# src - MP string prop : property node
# actions - list of actions : [func(v)]
# An action is triggered when its value is received.
# Note: TDM can have high latency so it is best used for
# non-time critical properties.
var TDMDecoder = {};
TDMDecoder.new = func (src, actions) {
var obj = { parents : [TDMDecoder],
actions : actions };
obj.channel = MessageChannel.new(src,
func (msg) {
obj.process(msg);
});
# Error checking.
var bad = (src == nil) or (obj.channel == nil);
foreach (var a; actions) {
if (a == nil) { bad = 1; }
}
if (bad) {
print("TDMDecoder[");
print(" ", debug.string(src));
foreach (var a; actions) {
print(" ", debug.string(a));
}
print("]");
fail();
}
return obj;
}
TDMDecoder.process = func (msg) {
var v1 = Binary.decodeByte(msg);
var v2 = Binary.decodeDouble(substr(msg, 1));
# Trigger action.
me.actions[v1](v2);
}
TDMDecoder.update = func {
me.channel.update();
}
###############################################################################
# Internal utility functions
var is_num = func (v) {
return num(v) != nil;
}
# fail causes a Nasal runtime error so we get a backtrace.
var fail = func {
error_detected_in_calling_context();
}
###############################################################################
###############################################################################
# Copilot selection dialog.
#
# Usage: dual_control_tools.copilot_dialog.show(<copilot type string>);
#
var COPILOT_DLG = 0;
var copilot_dialog = {};
############################################################
copilot_dialog.init = func (copilot_type, x = nil, y = nil) {
me.x = x;
me.y = y;
me.bg = [0, 0, 0, 0.3]; # background color
me.fg = [[1.0, 1.0, 1.0, 1.0]];
#
# "private"
if (contains(aircraft_dual_control, "copilot_view")) {
me.title = "Pilot selection";
} else {
me.title = "Copilot selection";
}
me.basenode = props.globals.getNode("/sim/remote", 1);
me.dialog = nil;
me.namenode = props.Node.new({"dialog-name" : me.title });
me.listeners = [];
me.copilot_type = copilot_type;
}
############################################################
copilot_dialog.create = func {
if (me.dialog != nil)
me.close();
me.dialog = gui.Widget.new();
me.dialog.set("name", me.title);
if (me.x != nil)
me.dialog.set("x", me.x);
if (me.y != nil)
me.dialog.set("y", me.y);
me.dialog.set("layout", "vbox");
me.dialog.set("default-padding", 0);
var titlebar = me.dialog.addChild("group");
titlebar.set("layout", "hbox");
titlebar.addChild("empty").set("stretch", 1);
if (contains(aircraft_dual_control, "copilot_view")) {
titlebar.addChild("text").set("label", "Pilots online");
} else {
titlebar.addChild("text").set("label", "Copilots online");
}
var w = titlebar.addChild("button");
w.set("pref-width", 16);
w.set("pref-height", 16);
w.set("legend", "");
w.set("default", 0);
w.set("key", "esc");
w.setBinding("nasal", "dual_control_tools.copilot_dialog.destroy(); ");
w.setBinding("dialog-close");
me.dialog.addChild("hrule");
var content = me.dialog.addChild("group");
content.set("layout", "vbox");
content.set("halign", "center");
content.set("default-padding", 5);
# Generate the dialog contents.
me.players = me.find_copilot_players();
var i = 0;
var tmpbase = me.basenode.getNode("dialog", 1);
var selected = me.basenode.getNode("pilot-callsign").getValue();
foreach (var p; me.players) {
var tmp = tmpbase.getNode("b[" ~ i ~ "]", 1);
tmp.setBoolValue(streq(selected, p));
var w = content.addChild("checkbox");
w.node.setValues({"label" : p,
"halign" : "left",
"property" : tmp.getPath()});
w.setBinding
("nasal",
"dual_control_tools.copilot_dialog.select_action(" ~ i ~ ");");
i = i + 1;
}
me.dialog.addChild("hrule");
# Display the dialog.
fgcommand("dialog-new", me.dialog.prop());
fgcommand("dialog-show", me.namenode);
}
############################################################
copilot_dialog.close = func {
fgcommand("dialog-close", me.namenode);
}
############################################################
copilot_dialog.destroy = func {
COPILOT_DLG = 0;
me.close();
foreach(var l; me.listeners)
removelistener(l);
delete(gui.dialog, "\"" ~ me.title ~ "\"");
}
############################################################
copilot_dialog.show = func (copilot_type) {
# print("Showing MPCopilots dialog!");
if (!COPILOT_DLG) {
COPILOT_DLG = int(getprop("/sim/time/elapsed-sec"));
me.init(copilot_type);
me.create();
me._update_(COPILOT_DLG);
}
}
############################################################
copilot_dialog._redraw_ = func {
if (me.dialog != nil) {
me.close();
me.create();
}
}
############################################################
copilot_dialog._update_ = func (id) {
if (COPILOT_DLG != id) return;
me._redraw_();
settimer(func { me._update_(id); }, 4.1);
}
############################################################
copilot_dialog.select_action = func (n) {
var selected = me.basenode.getNode("pilot-callsign").getValue();
var bs = me.basenode.getNode("dialog").getChildren();
# Assumption: There are two true b:s or none. The one not matching selected
# is the new selection.
var i = 0;
me.basenode.getNode("pilot-callsign").setValue("");
foreach (var b; bs) {
if (!b.getValue() and (i == n)) {
b.setValue(1);
me.basenode.getNode("pilot-callsign").setValue(me.players[i]);
} else {
b.setValue(0);
}
i = i + 1;
}
dual_control.main.reset();
me._redraw_();
}
############################################################
# Return a list containing all nearby copilot players of the right type.
copilot_dialog.find_copilot_players = func {
var mpplayers =
props.globals.getNode("/ai/models").getChildren("multiplayer");
var res = [];
foreach (var pilot; mpplayers) {
if ((pilot.getNode("valid") != nil) and
(pilot.getNode("valid").getValue()) and
(pilot.getNode("sim/model/path") != nil)) {
var type = pilot.getNode("sim/model/path").getValue();
if (type == me.copilot_type) {
append(res, pilot.getNode("callsign").getValue());
}
}
}
# debug.dump(res);
return res;
}
###############################################################################

View file

@ -0,0 +1,116 @@
###############################################################################
## $Id$
##
## Nasal for main pilot for dual control over the multiplayer network.
##
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
# Renaming (almost :)
var DCT = dual_control_tools;
var ADC = aircraft_dual_control;
# NOTE: By loading the aircraft specific dual control module
# as <aircraft_dual_control> this file is generic.
# The aircraft specific modul must set the variables
# pilot_type and copilot_type to the name (with full path) of
# main 3d model XML for the pilot and copilot aircraft.
# This module should be loades under the name dual_control.
######################################################################
# Connect new copilot
var process_data = 0;
var connect = func (copilot) {
# Tweak MP/AI filters
copilot.getNode("controls/allow-extrapolation").setBoolValue(0);
copilot.getNode("controls/lag-adjust-system-speed").setValue(5);
process_data = ADC.pilot_connect_copilot(copilot);
print("Dual control ... copilot connected.");
setprop("/sim/messages/copilot", "Hi.");
}
######################################################################
# Main loop singleton class.
var main = {
init : func {
me.loopid = 0;
me.active = 0;
setlistener("/ai/models/model-added", func {
settimer(func { me.activate(); }, 2);
});
settimer(func { me.activate(); }, 5);
print("Pilot dual control ... initialized");
},
reset : func {
if (me.active) {
print("Dual control ... copilot disconnected.");
ADC.pilot_disconnect_copilot();
}
me.active = 0;
me.loopid += 1;
me._loop_(me.loopid);
},
activate : func {
if (!me.active) {
me.reset();
}
},
update : func {
var mpplayers =
props.globals.getNode("/ai/models").getChildren("multiplayer");
var r_callsign = getprop("/sim/remote/pilot-callsign");
foreach (var copilot; mpplayers) {
if ((copilot.getChild("valid").getValue()) and
(copilot.getChild("callsign") != nil) and
(copilot.getChild("callsign").getValue() == r_callsign)) {
if (me.active == 0) {
# Note: sim/model/path tells the 3d XML file of the model.
if ((copilot.getNode("sim/model/path") != nil) and
(copilot.getNode("sim/model/path").getValue() ==
ADC.copilot_type)) {
connect(copilot);
me.active = 1;
} else {
print("Dual control ... copilot rejected - wrong aircraft type.");
me.loopid += 1;
return;
}
}
# Mess with the MP filters. Highly experimental.
if (copilot.getNode("controls/lag-time-offset") != nil) {
var v = copilot.getNode("controls/lag-time-offset").getValue();
copilot.getNode("controls/lag-time-offset").setValue(0.97 * v);
}
foreach (var w; process_data) {
w.update();
}
return;
}
}
if (me.active) {
print("Dual control ... copilot disconnected.");
ADC.pilot_disconnect_copilot();
}
me.loopid += 1;
me.active = 0;
},
_loop_ : func(id) {
id == me.loopid or return;
me.update();
settimer(func { me._loop_(id); }, 0);
}
};
######################################################################
# Initialization.
setlistener("/sim/signals/fdm-initialized", func {
main.init();
});