... | ... |
@@ -97,6 +97,95 @@ displayClass.MFD = { |
97 | 97 |
me.device.knobs.FmsInner = me.device.knobs.NavigateMenu; |
98 | 98 |
me.device.knobs.FmsOuter = me.device.knobs.NavigateMenu; |
99 | 99 |
}, |
100 |
+ 'FLIGHT PLAN CATALOG': func { |
|
101 |
+ var obj_infos = []; |
|
102 |
+ var departure = getprop('/sim/airport/closest-airport-id'); |
|
103 |
+ append(obj_infos, {text: departure ~ ' STORED FLIGHT PLANS', type: 'title'}); |
|
104 |
+ append(obj_infos, {type: 'separator'}); |
|
105 |
+ var idx = 0; |
|
106 |
+ foreach (var file; directory(data.flightplans)) { |
|
107 |
+ var stat = io.stat(data.flightplans ~ '/' ~ file); |
|
108 |
+ if (stat[11] == 'reg' or stat[11] == 'lnk') { |
|
109 |
+ var xml = call(func (path) io.readxml(path), [ data.flightplans ~ '/' ~ file ], me, {}, var errors = []); |
|
110 |
+ if (size(errors)) |
|
111 |
+ continue; |
|
112 |
+ if (xml.getNode('/PropertyList/flight-rules') != nil |
|
113 |
+ and xml.getNode('/PropertyList/flight-type') != nil |
|
114 |
+ and xml.getNode('/PropertyList/departure/airport') != nil |
|
115 |
+ and xml.getNode('/PropertyList/destination/airport') != nil |
|
116 |
+ and xml.getNode('/PropertyList/departure').getValue('airport') == departure) { |
|
117 |
+ append(obj_infos, { |
|
118 |
+ text: sprintf('RWY %s to %s%s', |
|
119 |
+ xml.getNode('/PropertyList/departure').getValue('runway'), |
|
120 |
+ xml.getNode('/PropertyList/destination').getValue('airport'), |
|
121 |
+ xml.getNode('/PropertyList/destination').getValue('runway') != nil ? |
|
122 |
+ '-' ~ xml.getNode('/PropertyList/destination').getValue('runway') : ''), |
|
123 |
+ type: (idx ? 'editable' : 'selected') ~ '|end-of-line', |
|
124 |
+ scrollgroup: idx, |
|
125 |
+ _file: data.flightplans ~ '/' ~ file |
|
126 |
+ }); |
|
127 |
+ var first_wp = last_wp = 0; |
|
128 |
+ forindex (var wp; xml.getNode('/PropertyList/route').getChildren('wp')) { |
|
129 |
+ var ident = xml.getNode('/PropertyList/route').getChild('wp', wp).getValue('ident'); |
|
130 |
+ if (string.match(ident, 'DEP-[0-9]*') |
|
131 |
+ or string.match(ident, sprintf('%s', xml.getNode('/PropertyList/departure').getValue('runway'))) |
|
132 |
+ or string.match(ident, sprintf('%s-[0-9]*', xml.getNode('/PropertyList/departure').getValue('runway')))) { |
|
133 |
+ continue; |
|
134 |
+ } |
|
135 |
+ if (!first_wp) { |
|
136 |
+ first_wp = wp; |
|
137 |
+ continue; |
|
138 |
+ } |
|
139 |
+ if (string.match(ident, 'APP-[0-9]*') |
|
140 |
+ or string.match(ident, sprintf('%s', xml.getNode('/PropertyList/destination').getValue('runway'))) |
|
141 |
+ or string.match(ident, sprintf('%s', xml.getNode('/PropertyList/destination').getValue('airport'))) |
|
142 |
+ or string.match(ident, sprintf('%s-[0-9]*', xml.getNode('/PropertyList/destination').getValue('runway')))) { |
|
143 |
+ last_wp = wp - 1; |
|
144 |
+ break; |
|
145 |
+ } |
|
146 |
+ } |
|
147 |
+ if (last_wp - first_wp > 2) |
|
148 |
+ append(obj_infos, { |
|
149 |
+ text: sprintf(' %s via %s and %s', |
|
150 |
+ utf8.chstr(9658), |
|
151 |
+ xml.getNode('/PropertyList/route').getChild('wp', first_wp + int((last_wp - first_wp)/3)).getValue('ident'), |
|
152 |
+ xml.getNode('/PropertyList/route').getChild('wp', last_wp - int((last_wp - first_wp)/3)).getValue('ident')), |
|
153 |
+ type: 'normal|end-of-line', |
|
154 |
+ scrollgroup: idx |
|
155 |
+ }); |
|
156 |
+ else |
|
157 |
+ append(obj_infos, { |
|
158 |
+ text: sprintf(' %s direct', utf8.chstr(9658)), |
|
159 |
+ type: 'normal|end-of-line', |
|
160 |
+ scrollgroup: idx |
|
161 |
+ }); |
|
162 |
+ idx += 1; |
|
163 |
+ } |
|
164 |
+ } |
|
165 |
+ } |
|
166 |
+ if (!idx) |
|
167 |
+ append(obj_infos, { text: 'no flightplan found', type: 'normal|end-of-line'}); |
|
168 |
+ |
|
169 |
+ var windowId = 'FLIGTH PLAN CATALOG'; |
|
170 |
+ me.device.windows.draw( windowId, obj_infos, {lines: 6, columns: 1, rows: 2} ); |
|
171 |
+ me.device.knobs.FmsInner = me.device.knobs.NavigateMenu; |
|
172 |
+ me.device.knobs.FmsOuter = me.device.knobs.NavigateMenu; |
|
173 |
+ me.device.buttons.CLR = func { |
|
174 |
+ me.device.windows.del(windowId); |
|
175 |
+ me.device.buttons.ENT = func; |
|
176 |
+ me.device.buttons.CLR = func; |
|
177 |
+ me.device.knobs.FmsInner = func; |
|
178 |
+ me.device.knobs.FmsOuter = me.device.knobs.MFD_select_page_group; |
|
179 |
+ } |
|
180 |
+ me.device.buttons.ENT = func (a = 0) { |
|
181 |
+ a or return; |
|
182 |
+ var (id, selected) = split('-', me.device.windows.selected); |
|
183 |
+ var file = me.device.windows.state[id].objects[selected]._file; |
|
184 |
+ me.device.buttons.CLR(); |
|
185 |
+ data.flightplan = flightplan(file); |
|
186 |
+ data.flightplan.activate(); |
|
187 |
+ } |
|
188 |
+ }, |
|
100 | 189 |
}, |
101 | 190 |
NRST : { |
102 | 191 |
'NEAREST AIRPORTS': func { |
... | ... |
@@ -93,6 +93,7 @@ Please report bug at <zkv1000@seb.lautre.net>. |
93 | 93 |
* use of [maketimer()](http://wiki.flightgear.org/Nasal_library#maketimer.28.29) instead of [settimer()](http://wiki.flightgear.org/Nasal_library#settimer.28.29) when possible |
94 | 94 |
* ![][80%] |
95 | 95 |
* Setting pages (MFD): pages/sub-pages selection via FMS knob ![][done], pages content implementation ![][ongoing] |
96 |
+ * Flight plans catalog (display on map doesn't work each time...) |
|
96 | 97 |
* ![][70%] |
97 | 98 |
* ![][60%] |
98 | 99 |
* NOT TESTED: add the posssibility to only use Nasal part of the instrument. This in case of a cockpit which already includes needed objects and animations for screens, knobs and buttons in its config files |
... | ... |
@@ -234,6 +235,14 @@ You can specify the stall AoA in order to display it in the dedicated display. |
234 | 235 |
* If `<stall-aoa>` is not specified or equals to `0` (zero) the AOA display won't be accessible. |
235 | 236 |
* The `<approach-aoa>` is optionnal, if present a blue marker is visible on AOA display (not in real GarminP1000) |
236 | 237 |
|
238 |
+### Flight plans catalog |
|
239 |
+You can specify a directory where to find the flightplans you save. Defaults to `$FG_HOME/Export` |
|
240 |
+ |
|
241 |
+ <flightplans type="string">/absolute/path/to/your/flightplans/location</flightplans> |
|
242 |
+ |
|
243 |
+Only the flightplans set for a departure from your position will be shown, no matter of the name of the file (even extension), each will be parsed to find the ones corresponding to your departure location. |
|
244 |
+The list will show only 6 flightplans, but it's scrollable so you can handle much more. |
|
245 |
+ |
|
237 | 246 |
## 3D models |
238 | 247 |
In the definition of your flightdeck (here are the values for the installation in the Lancair 235 in which I develop the device) |
239 | 248 |
put it everywhere you want to. Note that the path `Aircraft/Instruments-3d/zkv1000` is dependant on the path where the zkv1000 is installed, this can be somewhere like `Aircraft/My-Nice-Aircraft/arbitrary/dirs/zkv1000-or-not`as mentionned earlier in this section. |
... | ... |
@@ -37,6 +37,7 @@ var data = { # set of data common to all devices |
37 | 37 |
lat : 0, |
38 | 38 |
lon : 0, |
39 | 39 |
aoa : 0, |
40 |
+ fpSize : 0, |
|
40 | 41 |
tcas: [], |
41 | 42 |
settings: { |
42 | 43 |
units: { |
... | ... |
@@ -86,6 +87,10 @@ var init_props = func { |
86 | 87 |
zkv.getNode('lightmap',1).setIntValue(0); |
87 | 88 |
if (zkv.getNode('size-factor').getValue() == nil) |
88 | 89 |
zkv.getNode('size-factor',1).setDoubleValue(1.0); |
90 |
+ if (zkv.getValue('flightplans') != nil and io.stat(zkv.getValue('flightplans')) == "dir") |
|
91 |
+ data.flightplans = zkv.getValue('flightplans'); |
|
92 |
+ else |
|
93 |
+ data.flightplans = getprop('/sim/fg-home') ~ '/Export'; |
|
89 | 94 |
|
90 | 95 |
radios = zkv.getNode('radios', 1); |
91 | 96 |
radios.getNode('nav1-selected',1).setIntValue(0); |
... | ... |
@@ -151,6 +156,8 @@ var init_props = func { |
151 | 156 |
afcs.getNode('pit-active-mode-blink',1).setBoolValue(0); |
152 | 157 |
afcs.getNode('route',1); |
153 | 158 |
|
159 |
+ data.flightplans = getprop('/sim/fg-home') ~ '/Export'; |
|
160 |
+ |
|
154 | 161 |
misc = zkv.getNode('misc',1); |
155 | 162 |
misc.getNode('alt-setting-inhg',1).setDoubleValue(getprop('/instrumentation/altimeter/setting-inhg')); |
156 | 163 |
|