1var mode = 0; #current mode 2var displayed_screen = 0; #screenModeAndSettings 3var page = 0; #current page 4var blocked = 0; #boolean: 0 -> possible to cycle pages 5var isOn = 0; #ON/OFF: 0 -> OFF 6var refresh_timer = 0; #avoid multiple settimers 7var freq = 1; #settimer frequency (in sec) 8var screen = []; #array containing all screens 9var line = []; #array containing the displayed lines 10var routes = []; #array containing the preprogrammed tasks 11var alt_unit_full_name = ["Feet", "Meters"]; 12var dist_unit_full_name = ["Nautic Miles", "Kilometers"]; 13var spd_unit_full_name = ["Knots", "KM/H"]; 14var alt_unit_short_name = ["ft", "m"]; 15var dist_unit_short_name = ["nm", "km"]; 16var spd_unit_short_name = ["kt", "km/h"]; 17var spd_unit = 0; 18var dist_unit = 0; 19var alt_unit = 0; 20var startpos = nil; #geo.nas aircraft position 21var waypointindex = 0; #step in actual task 22var thresold_alert = [120, 60, 30, 15]; 23var thresold_alert_index = 1; 24var thresold_next_waypoint = 5; 25NOT_YET_IMPLEMENTED = [ 26 "", 27 " NOT", 28 " YET", 29 "IMPLEMENTED", 30 "" 31]; 32var LINES = 5; #lines in display 33var page_list = [ 34 [0,0,0,0,0,0], #0 ModeAndSettings: 1 page for mode, 5 pages for settings 35 [1,2,3], #1 PositionMain, Odometers, WindInfos 36 [5,4,1,2,3,6,7], #2 AirportMain, NavigationMain, PositionMain, Odometers, WindInfos, AirportInfos, SearchAirport 37 [8,4,1,2,3,9], #3 TurnpointSelect, NavigationMain, PositionMain, Odometers, WindInfos, TurnpointInfos 38 [10,4,1,2,3,11,12], #4 TaskSelect, NavigationMain, PositionMain, Odometers, WindInfos, WaypointInfos, WaypointsList 39 [13] #5 Edit (special mode for editing waypoint, called from other modes) 40]; 41 42 #to ft m 43var alt_conv = [[1.0000,0.3048], #from ft 44 [3.2808,1.0000]]; #from m 45 46 #to nm km m 47var dist_conv = [[1.00000 ,1.852, 1852], #from nm 48 [0.53996 ,1.000, 1000], #from km 49 [0.00053996,0.001, 1.00]]; #from m 50 51var gps_data = props.globals.getNode("/instrumentation/gps",1); 52var scratch = gps_data.getNode("scratch",1); 53var gps_wp = gps_data.getNode("wp",1); 54var route = props.globals.getNode("/autopilot/route-manager/route",1); 55 56#### warps for buttons and knobs ########################################" 57var right_knob = func(dir) { #manage right knob, depends of displayed screen 58 isOn > 0 or return; 59 screen[displayed_screen].right(dir); 60 refresh_display(); 61} 62 63var enter_button = func() { #manage enter button, depends of displayed screen 64 isOn > 0 or return; 65 screen[displayed_screen].enter(); 66 refresh_display(); 67} 68 69var escape_button = func() { #manage escape button, depends of displayed screen 70 isOn > 0 or return; 71 screen[displayed_screen].escape(); 72 refresh_display(); 73} 74 75var start_button = func() { #manage start button, depends of displayed screen 76 isOn > 0 or return; 77 screen[displayed_screen].start(); 78 refresh_display(); 79} 80 81var left_knob = func(dir) { #manage left button, cycle in mode's pages if not blocked 82 isOn > 0 or return; 83 if (blocked == 0) { 84 if (displayed_screen == 13 and dir) { 85 mode = screenEdit.previous_mode; 86 page = screenEdit.previous_page; 87 } 88 page = cycle(size(page_list[mode]), page, dir); 89 displayed_screen = page_list[mode][page]; 90 } 91 refresh_display(); 92} 93 94var select_mode = func(dir) { #manage mode knob, cycle into available modes 95 isOn > 0 or return; 96 blocked = 0; 97 if (displayed_screen != 0) { 98 displayed_screen = 0; #screenModeAndSettings 99 page = 0; 100 mode = 0; 101 } 102 elsif (page == 0) 103 screen[0].mode_ = cycle(size(screen[0].available_modes), screen[0].mode_, dir); 104 refresh_display(); 105} 106 107var power_knob = func() { #manage POWER knob 108 if (arg[0] > 0 and isOn < 11) isOn += 1; 109 elsif (arg[0] < 0 and isOn > 0) isOn -= 1; 110 else return; 111 props.globals.getNode("/instrumentation/zkv500/power",1).setIntValue(isOn); 112 var light = 0; 113 if (isOn > 0 and getprop("instrumentation/gps/serviceable") != 0) 114 light = (isOn - 1)/20; 115 props.globals.getNode("/instrumentation/zkv500/retro-light").setDoubleValue(light); 116 refresh_display(); 117} 118 119### useful funcs ######################################################### 120var display = func () { #display the array line[] 121 for (var i = 0; i < LINES; i += 1) line[i].setValue(arg[0][i]); 122} 123 124var apply_command = func (command) { 125 gps_data.getNode("command").setValue(command); 126} 127 128var browse = func (entries_nbr, index_pointer, index_page,dir) { 129 #browse multipaged entries, returns [pointer in page, page] 130 nl = entries_nbr - (index_page * LINES) >= LINES ? LINES : math.mod(entries_nbr - (index_page * LINES), LINES); 131 if (index_pointer + 1 == nl) { 132 np = int(entries_nbr / LINES) + (math.mod(entries_nbr,LINES) ? 1 : 0); 133 index_page = cycle(np, index_page, dir); 134 } 135 index_pointer = cycle(nl, index_pointer, dir); 136 return [index_pointer, index_page]; 137} 138 139var cycle = func (entries_nbr, actual_entrie, dir) { 140 #cycle through entries, return entry index 141 entries_nbr -= 1; 142 if (dir == 1 and actual_entrie == entries_nbr) return 0; 143 elsif (dir == -1 and actual_entrie == 0) return entries_nbr; 144 else return actual_entrie + dir; 145} 146 147var refresh_display = func(forced = 1) { #refresh displayed lines, settimer if necessary 148 if (!forced) refresh_timer -= 1; 149 screen[displayed_screen].lines(); 150 if (isOn and 0 < displayed_screen and displayed_screen < 5 and !refresh_timer) { 151 refresh_timer += 1; 152 settimer(func { refresh_display(0); }, freq, 1); 153 } 154 waypointAlert(); 155} 156 157var seconds_to_string = func (time) { #converts secs (double) in string "hh:mm:ss" 158 var hh = int(time / 3600); 159 if (hh > 100) return "--:--:--"; 160 var mm = int((time - (hh * 3600)) / 60); 161 var ss = int(time - (hh * 3600 + mm * 60)); 162 return sprintf("%02d:%02d:%02d", hh, mm, ss); 163} 164 165### route management ###################################################### 166var list_routes = func { #load preprogrammed tasks 167 routes = []; 168 var path = getprop("/sim/fg-home") ~ "/Routes"; 169 var s = io.stat(path); 170 if (s != nil and s[11] == "dir") { 171 foreach (var file; directory(path)) 172 if (file[0] != 46) append(routes, file); 173# size(routes) != 0 or return; 174# routes = sort(routes, func(a,b) { 175# num(a[1]) == nil or num(b[1]) == nil ? cmp(a[1], b[1]) : a[1] - b[1]; 176# }); 177# print(size(routes)); 178# foreach (var r; routes) print (r ~ ":" ~ r[0]); 179 } 180 return size(routes); 181} 182 183var add_waypoint = func (ID, name, type, coord) { #add a waypoint to a route 184 var waypoint = gps_data.getNode("route/Waypoint["~screenWaypointsList.n~"]/",1); 185 screenWaypointsList.n += 1; 186 waypoint.getNode("ID",1).setValue(ID); 187 waypoint.getNode("latitude-deg",1).setDoubleValue(coord[0]); 188 waypoint.getNode("longitude-deg",1).setDoubleValue(coord[1]); 189 waypoint.getNode("altitude-ft",1).setDoubleValue(coord[2]*alt_conv[1][0]); 190 waypoint.getNode("name",1).setValue(name); 191 waypoint.getNode("desc",1).setValue("no infos"); 192 waypoint.getNode("waypoint-type",1).setValue(type); 193} 194 195var save_route = func { #save the route 196 screenWaypointsList.n != 0 or return; 197 var first_id = gps_data.getNode("route/Waypoint/ID").getValue(); 198 var last_id = gps_data.getNode("route/Waypoint["~(screenWaypointsList.n - 1)~"]/ID").getValue(); 199 var path = getprop("/sim/fg-home") ~ "/Export/"~first_id~"-"~last_id~".xml"; 200 var args = props.Node.new({ filename : path }); 201 var export = args.getNode("data", 1); 202 props.copy(gps_data.getNode("route"), export); 203 fgcommand("savexml", args); 204} 205 206var Waypoint_to_scratch = func (node) { 207 scratch.getNode("latitude-deg",1).setValue(node.getNode("latitude-deg").getValue()); 208 scratch.getNode("longitude-deg",1).setValue(node.getNode("longitude-deg").getValue()); 209 scratch.getNode("altitude-ft",1).setValue(node.getNode("altitude-ft").getValue()); 210 scratch.getNode("ident").setValue(node.getNode("ID").getValue()); 211 if (node.getNode("name") != nil) 212 scratch.getNode("name",1).setValue(node.getNode("name").getValue()); 213 else 214 scratch.getNode("name",1).setValue(""); 215 if (node.getNode("type") != nil) 216 scratch.getNode("type",1).setValue(node.getNode("waypoint-type").getValue()); 217 else 218 scratch.getNode("type",1).setValue(""); 219} 220 221var waypointAlert = func { #alert pilot about waypoint approach 222 if (mode) { 223 var ttw = getprop("/instrumentation/gps/wp/wp[1]/TTW-sec"); 224 ttw > -1 or return; 225 if (ttw < thresold_alert[thresold_alert_index]) 226 gps_data.getNode("waypoint-alert",1).setBoolValue(1); 227 else 228 gps_data.getNode("waypoint-alert",1).setBoolValue(0); 229 } 230} 231 232### turnpoints management ###################################################### 233var load_bookmarks = func { #load turnpoints 234 var n = 0; 235 gps_data.getNode("bookmarks",1).removeChildren("bookmark"); 236 var file = getprop("/sim/fg-home") ~ "/Export/bookmarks.xml"; 237 var s = io.stat(file); 238 if (s != nil) { 239 fgcommand("loadxml", props.Node.new({ 240 "filename": file, 241 "targetnode": "/instrumentation/gps/bookmarks" 242 })); 243 foreach (var c ;props.globals.getNode("/instrumentation/gps/bookmarks").getChildren("bookmark")) n += 1; 244 } 245 else 246 print(file ~ " not found..."); 247 return n; 248} 249 250var save_bookmarks = func { #save turnpoints 251 var path = getprop("/sim/fg-home") ~ "/Export/bookmarks.xml"; 252 var args = props.Node.new({ filename : path }); 253 var export = args.getNode("data", 1); 254 props.copy(gps_data.getNode("bookmarks"), export); 255 fgcommand("savexml", args); 256} 257 258var add_bookmark = func (ID, name, type, coord) { #add turnpoint 259 var bookmark = gps_data.getNode("bookmarks/bookmark["~screenTurnpointSelect.n~"]/",1); 260 screenTurnpointSelect.n += 1; 261 bookmark.getNode("ID",1).setValue(ID); 262 bookmark.getNode("latitude-deg",1).setDoubleValue(coord[0]); 263 bookmark.getNode("longitude-deg",1).setDoubleValue(coord[1]); 264 bookmark.getNode("altitude-ft",1).setDoubleValue(coord[2]*alt_conv[1][0]); 265 bookmark.getNode("desc",1).setValue("no infos"); 266 bookmark.getNode("name",1).setValue(name); 267 bookmark.getNode("waypoint-type",1).setValue(type); 268 save_bookmarks(); 269} 270 271var EditMode = func (length, title, start_command, numcar = 0) { 272 #special mode for editing simple text 273 screenEdit.previous_mode = mode; 274 screenEdit.previous_page = page; 275 mode = 5; #ID edition 276 page = 0; 277 screenEdit.init(length, title, start_command, numcar); 278} 279 280### initialisation stuff ################################################### 281var load_screens = func { 282 var zkv500_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/zkv500/"; 283 io.load_nasal(zkv500_dir ~ "AirportScreens.nas","zkv500"); 284 io.load_nasal(zkv500_dir ~ "TurnpointScreens.nas","zkv500"); 285 io.load_nasal(zkv500_dir ~ "MainScreens.nas","zkv500"); 286 io.load_nasal(zkv500_dir ~ "TaskScreens.nas","zkv500"); 287} 288 289var organize_screens = func { 290 screen = []; #empty screens 291 append(screen, zkv500.screenModeAndSettings); #0 292 append(screen, zkv500.screenPositionMain); #1 293 append(screen, zkv500.screenOdometers); #2 294 append(screen, zkv500.screenWindInfos); #3 295 append(screen, zkv500.screenNavigationMain); #4 296 append(screen, zkv500.screenAirportMain); #5 297 append(screen, zkv500.screenAirportInfos); #6 298 append(screen, zkv500.screenSearchAirport); #7 299 append(screen, zkv500.screenTurnpointSelect); #8 300 append(screen, zkv500.screenTurnpointInfos); #9 301 append(screen, zkv500.screenTaskSelect); #10 302 append(screen, zkv500.screenWaypointInfos); #11 303 append(screen, zkv500.screenWaypointsList); #12 304 append(screen, zkv500.screenEdit); #13 305} 306 307var init_gps_variables = func { 308 mode = 0; 309 page = 0; 310 displayed_screen = 0; #screenModeAndSettings 311 blocked = 0; #unlock left_knob 312 #isOn = 0; #start OFF 313 startpos = nil; #unset start position 314 waypointindex = 0; #route waypoint index on beginning 315} 316 317var init_gps_props = func { 318 for (var i = 0; i < LINES; i += 1) { 319 append(line, props.globals.getNode("/instrumentation/zkv500/line[" ~ i ~ "]", 1)); 320 line[i].setValue(""); 321 } 322 props.globals.getNode("/instrumentation/zkv500/retro-light",1).setDoubleValue(0); 323 props.globals.getNode("/instrumentation/zkv500/power",1).setIntValue(0); 324 aircraft.light.new("/sim/model/gps/redled", [0.1, 0.1, 0.1, 0.7], "/instrumentation/gps/waypoint-alert"); 325 aircraft.light.new("/sim/model/gps/greenled", [0.6, 0.3], "/instrumentation/gps/message-alert"); 326 startpos = geo.Coord.new(geo.aircraft_position()); 327 screenPositionMain.begin_time = props.globals.getNode("/sim/time/elapsed-sec",1).getValue(); 328 setlistener("/instrumentation/gps/serviceable", func { 329 if (getprop("/instrumentation/gps/serviceable") == 0) 330 setprop("/instrumentation/zkv500/retro-light", 0); 331 elsif (isOn > 0) 332 setprop("/instrumentation/zkv500/retro-light", (isOn - 1)/20); 333 }, 0, 0); 334} 335 336var init = func() { 337 load_screens(); 338 organize_screens(); 339 init_gps_variables(); 340 init_gps_props(); 341 print("GPS... initialized"); 342} 343 344setlistener("/sim/signals/fdm-initialized",init); 345