Showing 5 changed files with 125 additions and 2 deletions
+27
Nasal/display.nas
... ...
@@ -152,6 +152,7 @@ var displayClass = {
152 152
                     'PFD-Map',
153 153
                     'PFD-Multilines',
154 154
                     'WindData', 'WindData-OPTN1', 'WindData-OPTN2', 'WindData-OPTN1-HDG', 'WindData-OPTN2-symbol', 'WindData-OPTN2-headwind', 'WindData-OPTN2-crosswind', 'WindData-NODATA',
155
+                    'AOA', 'AOA-needle',
155 156
                 );
156 157
                 append(groups.clip,
157 158
                     'SpeedLint1',
... ...
@@ -186,6 +187,8 @@ var displayClass = {
186 187
                         'AltSmallD' ~ place
187 188
                     );
188 189
                 }
190
+                me.device.data.aoa = 0;
191
+                me.device.data['aoa-auto'] = 0;
189 192
             }
190 193
             else {
191 194
                 if (contains(me.parents[0], 'showEIS'))
... ...
@@ -1146,6 +1149,28 @@ var displayClass = {
1146 1149
     _winddata_optn : 0,
1147 1150
 #}}}
1148 1151
 
1152
+    updateAOA : func {
1153
+# update Angle Of Attack {{{
1154
+        if (me.device.data.aoa == 0)
1155
+            return;
1156
+        var color = [1,1,1];
1157
+        var norm = data.aoa / data['stall-aoa'];
1158
+        if (norm > 1) norm = 1;
1159
+        if (norm > 0.9)
1160
+            color = [1,0,0];
1161
+        elsif (norm > 0.7)
1162
+            color = [1,1,0];
1163
+        elsif (norm < 0) {
1164
+            norm = 0;
1165
+            color = [1,0,0];
1166
+        }
1167
+        me.screenElements['AOA-needle']
1168
+            .setRotation(-norm * math.pi)
1169
+            .setColor(color);
1170
+        settimer(func me.updateAOA(), 0.1);
1171
+    },
1172
+# }}}
1173
+
1149 1174
     updateBRG : func {
1150 1175
 # displays and update BRG1/2 {{{
1151 1176
         foreach (var brg; [1, 2]) {
... ...
@@ -1306,4 +1331,6 @@ var keyMap = {
1306 1331
         },
1307 1332
     },
1308 1333
 };
1334
+if (data['stall-aoa'] == 9999)
1335
+    keyMap.PFD.PFD['AOA/WIND'].texts = ['', 'WIND'];
1309 1336
 #}}}
+44
Nasal/softkeys.nas
... ...
@@ -63,6 +63,50 @@ var softkeysClass = {
63 63
             },
64 64
             PFD: {
65 65
                 'AOA/WIND' : {
66
+                    AOA : {
67
+                        'AOA ON' : func {
68
+                            if (me.device.data['aoa-auto'])
69
+                                return;
70
+                            me.device.data.aoa = ! me.device.data.aoa;
71
+                            me.device.display.screenElements['AOA']
72
+                                .setVisible(me.device.data.aoa);
73
+                            me.device.display.screenElements['AOA-needle']
74
+                                .setVisible(me.device.data.aoa);
75
+                            me.device.display.updateAOA();
76
+                            me.device.display.setSoftKeyColor(5 ,me.device.data.aoa);
77
+                            if (me.device.data.aoa)
78
+                                me.colored['PFDAOA/WINDAOAAOA ON'] = 1;
79
+                            else
80
+                                delete(me.colored, 'PFDAOA/WINDAOAAOA ON');
81
+                        },
82
+                        'AOA AUTO' : func {
83
+                            if (me.device.data.aoa)
84
+                                return;
85
+                            me.device.data['aoa-auto'] = ! me.device.data['aoa-auto'];
86
+                            me.device.display.setSoftKeyColor(6 ,me.device.data['aoa-auto']);
87
+                            if (me.device.data['aoa-auto']) {
88
+                                me.colored['PFDAOA/WINDAOAAOA AUTO'] = 1;
89
+                                if (!contains(me.device.timers, 'aoa'))
90
+                                    me.device.timers.aoa = maketimer(1,
91
+                                            func {
92
+                                                var v = getprop('/gear/gear/position-norm') == 1
93
+                                                    and getprop('/surfaces-positions/flap-pos-norm') != 0;
94
+                                                me.device.display.screenElements['AOA']
95
+                                                    .setVisible(v);
96
+                                                me.device.display.screenElements['AOA-needle']
97
+                                                    .setVisible(v);
98
+                                            }, me);
99
+                                me.device.timers.aoa.start();
100
+                            }
101
+                            else {
102
+                                delete(me.colored, 'PFDAOA/WINDAOAAOA AUTO');
103
+                                me.device.timers.aoa.stop();
104
+                                me.device.data.aoa = 0;
105
+                                me.device.display.screenElements['AOA']
106
+                                    .hide();
107
+                            }
108
+                        },
109
+                    },
66 110
                     WIND : {
67 111
                         OPTN1 : func {
68 112
                             me.device.display._winddata_optn = 1;
+12 -1
README.md
... ...
@@ -75,6 +75,7 @@ Please report bug at <seb.marque@free.fr>.
75 75
   * EIS: separation for aircraft specifics (selected by the zkv1000 config)
76 76
 * ![][90%]
77 77
   * TMR/REF Timer ![][done], Vspeeds ![][done], minimums ![][pending] (don't understand the role of this)
78
+  * angle of attack display (not sure about calculation): specific for each airplane (see Installation instructions below)
78 79
   * Bearing needs some checks to be sure it shows the correct information
79 80
   * XPDR: emergency code depending of the country (eg.: 1200 for US, 7700 for Europe), should be set in settings
80 81
 * ![][80%]
... ...
@@ -95,7 +96,6 @@ Please report bug at <seb.marque@free.fr>.
95 96
 * ![][0%] (TODO list, unsorted)
96 97
   * CDI/GPS: scale depending of the flight phase
97 98
   * recenter the MFD depending of EIS width
98
-  * angle of attack display
99 99
   * Alerts
100 100
   * Flight planning (MFD)
101 101
   * Inset Map (PFD)
... ...
@@ -106,6 +106,8 @@ Please report bug at <seb.marque@free.fr>.
106 106
   * VNAV
107 107
   * scrolling lift in menus
108 108
   * tutorials
109
+  * make any Vspeed available (not only Vx, Vy, Vr and Vglide), depending of their presence in aircraft config
110
+  * [touchable screen](http://wiki.flightgear.org/Canvas_Event_Handling)
109 111
   * many more...
110 112
 
111 113
 # Installation
... ...
@@ -144,6 +146,15 @@ To tells the zkv1000 which kind of engines equip your aircraft, and the associat
144 146
 Defaults to `none`, available entries are the `.nas` files located in `Nasal/EIS/` directory.
145 147
 If you want to add yours, just copy the `Systems/EIS/single-engine.svg`, modify it to fit your needs, and refer to it in a function named `displayClass.showEIS`, another very important function is `displayClass.updateEIS` (example in [zkv1000/Nasal/EIS/single-engine.nas](Nasal/EIS/single-engine.nas))
146 148
 
149
+### Angle Of Attack (AOA)
150
+You can specify the stall AoA in order to display it in the dedicated display.
151
+
152
+        <alerts>
153
+          <stall-aoa>15</stall-aoa>
154
+        </alerts>
155
+
156
+If not specified or equals to 0 (zero) the AOA display won't be accessible.
157
+
147 158
 ## 3D models
148 159
 In the definition of your flightdeck (here are the values for the installation in the Lancair 235 in which I develop the device)
149 160
 put it everywhere you want to
+37
Systems/screen.svg
... ...
@@ -7106,6 +7106,43 @@
7106 7106
          id="Annunciation-bg"
7107 7107
          style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.01803744;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
7108 7108
     </g>
7109
+    <g
7110
+       id="AOA"
7111
+       inkscape:label="AOA">
7112
+      <rect
7113
+         style="opacity:1;fill:#020000;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
7114
+         id="AOA-bg"
7115
+         width="75.831932"
7116
+         height="71.529388"
7117
+         x="158.11763"
7118
+         y="325.3782"
7119
+         inkscape:label="AOA-bg" />
7120
+      <text
7121
+         inkscape:label="AOA-text"
7122
+         id="AOA-text"
7123
+         y="345.68497"
7124
+         x="159.34264"
7125
+         style="font-style:normal;font-weight:normal;font-size:16px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
7126
+         xml:space="preserve"><tspan
7127
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';fill:#ffffff;fill-opacity:1"
7128
+           y="345.68497"
7129
+           x="159.34264"
7130
+           id="tspan5885"
7131
+           sodipodi:role="line">AOA</tspan></text>
7132
+      <path
7133
+         inkscape:label="AOA-needle"
7134
+         inkscape:transform-center-y="17.435497"
7135
+         inkscape:transform-center-x="-0.303765"
7136
+         inkscape:connector-curvature="0"
7137
+         id="AOA-needle"
7138
+         d="m 191.3807,360.58563 0.63375,34.70574 v 0 0"
7139
+         style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.97909927;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
7140
+      <path
7141
+         style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
7142
+         d="m 192.45312,325.95312 v 1 c 12.21842,0 23.48918,6.57015 29.51172,17.20118 6.02255,10.63103 5.86335,23.67799 -0.41796,34.1582 -6.28132,10.48021 -17.71104,16.77019 -29.92579,16.4707 l -0.0254,1 c 12.57316,0.30828 24.34297,-6.1693 30.8086,-16.95703 6.46562,-10.78773 6.6309,-24.22109 0.43164,-35.16406 -6.19926,-10.94297 -17.80588,-17.70899 -30.38282,-17.70899 z"
7143
+         id="AOA-circle"
7144
+         inkscape:connector-curvature="0" />
7145
+    </g>
7109 7146
     <g
7110 7147
        id="Reversionnary"
7111 7148
        inkscape:label="Reversionnary">
+5 -1
zkv1000.nas
... ...
@@ -30,6 +30,7 @@ var data = { # set of data common to all devices
30 30
     wow : 1,
31 31
     lat : 0,
32 32
     lon : 0,
33
+    aoa : 0,
33 34
     timers : {
34 35
         '20Hz': maketimer (
35 36
             0.05,
... ...
@@ -40,6 +41,7 @@ var data = { # set of data common to all devices
40 41
                 data.ias = getprop('/velocities/airspeed-kt');
41 42
                 data.alt = getprop('/instrumentation/altimeter/indicated-altitude-ft');
42 43
                 data.hdg = getprop('/orientation/heading-deg');
44
+                data.aoa = getprop('/orientation/alpha-deg');
43 45
             }
44 46
         ),
45 47
         '1Hz': maketimer (
... ...
@@ -100,6 +102,8 @@ var init_props = func {
100 102
         var speed = getprop('/instrumentation/zkv1000/alerts/' ~ v);
101 103
         data[v] = speed != nil ? speed : 9999;
102 104
     }
105
+    var aoa = getprop('/instrumentation/zkv1000/alerts/stall-aoa');
106
+    data['stall-aoa'] = (aoa == nil or aoa == 0) ? 9999 : aoa;
103 107
 
104 108
     afcs = zkv.getNode('afcs',1);
105 109
     afcs.getNode('fd-bars-visible',1).setBoolValue(0);
... ...
@@ -184,8 +188,8 @@ var load_multikey = func {
184 188
 var zkv1000_init = func {
185 189
     removelistener(init);
186 190
     load_multikey();
187
-    load_nasal();
188 191
     init_props();
192
+    load_nasal();
189 193
     print('zkv1000 loaded');
190 194
 }
191 195