From 763860f42c173e06d41dd58b08e770787ae610fe Mon Sep 17 00:00:00 2001 From: helijah Date: Mon, 14 Jul 2008 14:40:22 +0000 Subject: [PATCH] - new version with doc by Zakharov --- .../Instruments-3d/zkv500/AirportScreens.nas | 11 +- .../Instruments-3d/zkv500/MainScreens.nas | 58 ++- .../Instruments-3d/zkv500/TaskScreens.nas | 12 +- .../zkv500/TurnpointScreens.nas | 20 +- Aircraft/Instruments-3d/zkv500/ZKV500.nas | 105 ++--- Aircraft/Instruments-3d/zkv500/manual.txt | 389 ++++++++++++++++++ Aircraft/Instruments-3d/zkv500/zkv_dbg.nas | 108 +++++ 7 files changed, 603 insertions(+), 100 deletions(-) create mode 100644 Aircraft/Instruments-3d/zkv500/manual.txt create mode 100644 Aircraft/Instruments-3d/zkv500/zkv_dbg.nas diff --git a/Aircraft/Instruments-3d/zkv500/AirportScreens.nas b/Aircraft/Instruments-3d/zkv500/AirportScreens.nas index be33e2b82..8e4198be1 100644 --- a/Aircraft/Instruments-3d/zkv500/AirportScreens.nas +++ b/Aircraft/Instruments-3d/zkv500/AirportScreens.nas @@ -24,7 +24,7 @@ var screenAirportMain = { me.searched = 0; me.oaci = nil; }, - start : func { #add bookmark, enter turnpoint mode + start : func { #add bookmark, enter turnpoint mode add_bookmark(me.apt.id, me.apt.name, "APT", [me.apt_coord.lat(), me.apt_coord.lon(), me.apt_coord.alt()*alt_conv[1][0]]); @@ -63,10 +63,6 @@ var screenAirportInfos = { page : 0, rwylist: [], right : func { - me.page = 0; - displayed_screen = 4;# screenAirportMain - }, - left : func { np = int(size(me.rwylist) / 4) + (math.mod(size(me.rwylist),4) ? 1 : 0); me.page = cycle(np, me.page, arg[0]); }, @@ -83,7 +79,7 @@ var screenAirportInfos = { screenAirportMain.apt.runways[r].width]); line[0].setValue(sprintf("%s", screenAirportMain.apt.name)); #TODO check length to truncate if too long rwyindex = me.page * 4; - for (var l = 1; l < 5; l += 1) { + for (var l = 1; l < LINES; l += 1) { rwyindex += 1; if (rwyindex < size(me.rwylist)) line[l].setValue(sprintf("%s [%dm / %dm]", @@ -108,13 +104,14 @@ var screenSearchAirport = { var found = screenAirportMain.search(); if (found != 0) { screenAirportMain.searched = 1; + screenEdit.previous_page = 0; return 1; } else return 0; }, lines : func { - EditMode(4, "AIRPORT CODE", "SEARCH", 2, 0); + EditMode(4, "AIRPORT CODE", "SEARCH"); } }; diff --git a/Aircraft/Instruments-3d/zkv500/MainScreens.nas b/Aircraft/Instruments-3d/zkv500/MainScreens.nas index 4de5e9956..fab5a1a57 100644 --- a/Aircraft/Instruments-3d/zkv500/MainScreens.nas +++ b/Aircraft/Instruments-3d/zkv500/MainScreens.nas @@ -1,45 +1,37 @@ var screenModeAndSettings = { # screen for changing the GPS mode and settings help : 0, mode_: 0, + page_: 0, + available_modes : ["POSITION","AIRPORT","TURNPOINT","TASK"], quit_help : func { me.help = 0; me.lines(); }, right : func { if (page == 1) - alt_unit = cycle(2, alt_unit, arg[0]); + alt_unit = cycle(size(alt_unit_full_name), alt_unit, arg[0]); elsif (page == 2) - dist_unit = cycle(2, dist_unit, arg[0]); + dist_unit = cycle(size(dist_unit_full_name), dist_unit, arg[0]); elsif (page == 3) - spd_unit = cycle(2, spd_unit, arg[0]); + spd_unit = cycle(size(spd_unit_full_name), spd_unit, arg[0]); elsif (page == 4) thresold_alert_index = cycle(size(thresold_alert), thresold_alert_index, arg[0]); elsif (page == 5) thresold_next_waypoint = cycle(10, thresold_next_waypoint, arg[0]); }, - changemode : func { - if (page == 0) me.mode_ = cycle(4, me.mode_, arg[0]); - }, enter : func { if (!me.help) { - display ([ - "HERE THERE WILL SEAT", - "A SIMPLE EXPLANATION", - "TEXT ABOUT USE OF GPS", - "PRESS ANY OF THE", - "THREE BUTTONS" - ]); + display (NOT_YET_IMPLEMENTED); me.help = 1; } else me.quit_help(); }, escape : func { if (me.help) me.quit_help(); - else me.dispatch(); }, start : func { if (me.help) me.quit_help(); - else { + else { mode = me.mode_ + 1; page = 0; displayed_screen = page_list[mode][page]; @@ -47,10 +39,7 @@ var screenModeAndSettings = { # screen for changing the GPS mode and settings }, lines : func { if (page == 0) { - if (me.mode_ == 0) mode_str = "POSITION"; - elsif (me.mode_ == 1) mode_str = "AIRPORT"; - elsif (me.mode_ == 2) mode_str = "TURNPOINT"; - else mode_str = "TASK"; + var mode_str = me.available_modes[me.mode_]; l0 = " -- GPS STATUS : --"; l1 = sprintf("MODE: %s", mode_str); } @@ -87,7 +76,7 @@ var screenPositionMain = { # screens for POSITION mode enter : func { var ac = geo.aircraft_position(); me.coord = [ac.lat(), ac.lon(), ac.alt()]; - EditMode(6, "EDIT WAYPOINT ID", "SAVE", mode, page); + EditMode(6, "EDIT WAYPOINT ID", "SAVE"); }, escape : func { }, @@ -257,29 +246,29 @@ var screenNavigationMain = { var screenEdit = { previous_mode: 0, previous_page: 0, - alphanum: ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P", - "Q","R","S","T","U","V","W","X","Y","Z", - "0","1","2","3","4","5","6","7","8","9"], - numeric: ["0","1","2","3","4","5","6","7","8","9","."], + carset: [["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P", + "Q","R","S","T","U","V","W","X","Y","Z", "0","1","2","3","4","5","6","7","8","9"], + ["0","1","2","3","4","5","6","7","8","9","."]], start_command: "", edit_zone: "", edit_title : "", - carset: [], + set: 0, map: [], pointer: 0, value: 0, - init: func (length, title, start_command, backmode, backpage, set = 0) { + init: func (length, title, start_command, set) { + me.map = []; for (var i = 0; i < length; i += 1) append(me.map, "-"); me.edit_title = title; me.start_command = start_command; - me.carset = set != 0 ? me.numeric : me.alphanum; - me.previous_mode = backmode; - me.previous_page = backpage; + me.set = set; + me.pointer = 0; + me.value = 0; left_knob(0); # force display }, right : func { - me.value = cycle(size(me.carset), me.value, arg[0]); - me.map[me.pointer] = me.carset[me.value]; + me.value = cycle(size(me.carset[me.set]), me.value, arg[0]); + me.map[me.pointer] = me.carset[me.set][me.value]; }, enter : func { me.pointer = cycle(size(me.map), me.pointer, 1); @@ -292,7 +281,7 @@ var screenEdit = { me.start_command = ""; me.edit_zone = ""; me.edit_title = ""; - me.carset = []; + me.set = 0; me.map = []; mode = me.previous_mode; page = me.previous_page; @@ -302,7 +291,10 @@ var screenEdit = { var str = ""; for (var i = 0; i < size(me.map); i += 1) str ~= me.map[i] != "-" ? me.map[i] : ""; - if (screen[page_list[me.previous_mode][me.previous_page]].start(str)) me.escape(); + if (screen[page_list[me.previous_mode][me.previous_page]].start(str)) + me.escape(); + else + me.init(size(me.map), me.edit_title, me.start_command, me.set); }, lines : func { me.right(0); #init car diff --git a/Aircraft/Instruments-3d/zkv500/TaskScreens.nas b/Aircraft/Instruments-3d/zkv500/TaskScreens.nas index 2670a52f0..3472ed4b3 100644 --- a/Aircraft/Instruments-3d/zkv500/TaskScreens.nas +++ b/Aircraft/Instruments-3d/zkv500/TaskScreens.nas @@ -54,9 +54,9 @@ var screenTaskSelect = { "" ]); } - else for (var l = 0; l < 5; l += 1) { - if ((me.page * 5 + l) < me.n) { - name = routes[me.page * 5 + l]; + else for (var l = 0; l < LINES; l += 1) { + if ((me.page * LINES + l) < me.n) { + name = routes[me.page * LINES + l]; if (substr(name, -4) == ".xml") name = substr(name, 0, size(name) - 4); name = string.uc(name); line[l].setValue(sprintf("%s %s",me.pointer == l ? ">" : " ", name)); @@ -83,9 +83,9 @@ var screenWaypointsList = { start : func { }, lines : func { - for (var l = 0; l < 5; l += 1) { - if ((me.page * 5 + l) < me.n) { - name = gps_data.getNode("route/Waypoint["~((me.page*5) + l)~"]/ID").getValue(); + for (var l = 0; l < LINES; l += 1) { + if ((me.page * LINES + l) < me.n) { + name = gps_data.getNode("route/Waypoint["~((me.page * LINES) + l)~"]/ID").getValue(); line[l].setValue(sprintf("%s %s",me.pointer == l ? ">" : " ", name)); } else diff --git a/Aircraft/Instruments-3d/zkv500/TurnpointScreens.nas b/Aircraft/Instruments-3d/zkv500/TurnpointScreens.nas index def40874a..6af2a1c0d 100644 --- a/Aircraft/Instruments-3d/zkv500/TurnpointScreens.nas +++ b/Aircraft/Instruments-3d/zkv500/TurnpointScreens.nas @@ -10,7 +10,7 @@ var screenTurnpointSelect = { var t = browse(me.n, me.pointer, me.page, arg[0]); me.pointer = t[0]; me.page = t[1]; - me.selected = me.page*5 + me.pointer; + me.selected = me.page * LINES + me.pointer; }, enter : func { }, @@ -24,10 +24,14 @@ var screenTurnpointSelect = { gps_wp.getNode("wp/ID").setValue("startpos"); var bookmark = gps_data.getNode("bookmarks/bookmark["~me.selected~"]/"); - gps_wp.getNode("wp[1]/latitude-deg",1).setValue(bookmark.getNode("latitude-deg",1).getValue()); - gps_wp.getNode("wp[1]/longitude-deg",1).setValue(bookmark.getNode("longitude-deg",1).getValue()); - gps_wp.getNode("wp[1]/altitude-ft",1).setValue(bookmark.getNode("altitude-ft",1).getValue()); - gps_wp.getNode("wp[1]/ID").setValue(bookmark.getNode("ID",1).getValue()); + gps_wp.getNode("wp[1]/latitude-deg",1).setValue(bookmark.getNode("latitude-deg").getValue()); + gps_wp.getNode("wp[1]/longitude-deg",1).setValue(bookmark.getNode("longitude-deg").getValue()); + gps_wp.getNode("wp[1]/altitude-ft",1).setValue(bookmark.getNode("altitude-ft").getValue()); + gps_wp.getNode("wp[1]/ID").setValue(bookmark.getNode("ID").getValue()); + if (bookmark.getNode("name") != nil) + gps_wp.getNode("wp[1]/name").setValue(bookmark.getNode("name").getValue()); + if (bookmark.getNode("waypoint-type") != nil) + gps_wp.getNode("wp[1]/waypoint-type").setValue(bookmark.getNode("waypoint-type").getValue()); blocked = 0; page = 1; mode = 3; @@ -36,9 +40,9 @@ var screenTurnpointSelect = { lines : func { if (me.loaded != 1) blocked = 1; if (me.n > 0) - for (var l = 0; l < 5; l += 1) { - if ((me.page * 5 + l) < me.n) { - name = gps_data.getNode("bookmarks/bookmark["~((me.page * 5) + l)~"]/ID").getValue(); + for (var l = 0; l < LINES; l += 1) { + if ((me.page * LINES + l) < me.n) { + name = gps_data.getNode("bookmarks/bookmark["~((me.page * LINES) + l)~"]/ID").getValue(); line[l].setValue(sprintf("%s %s",me.pointer == l ? ">" : " ", name)); } else diff --git a/Aircraft/Instruments-3d/zkv500/ZKV500.nas b/Aircraft/Instruments-3d/zkv500/ZKV500.nas index df0806650..d865e71a4 100644 --- a/Aircraft/Instruments-3d/zkv500/ZKV500.nas +++ b/Aircraft/Instruments-3d/zkv500/ZKV500.nas @@ -1,12 +1,12 @@ -var mode = 0; +var mode = 0; #current mode var displayed_screen = 0; #screenModeAndSettings -var page = 0; -var blocked = 0; -var isOn = 0; -var freq = 1; -var screen = []; -var line = []; -var routes = []; +var page = 0; #current page +var blocked = 0; #boolean: 0 -> possible to cycle pages +var isOn = 0; #ON/OFF: 0 -> OFF +var freq = 1; #settimer frequency (in sec) +var screen = []; #array containing all screens +var line = []; #array containing the displayed lines +var routes = []; #array containing the preprogrammed tasks var alt_unit_full_name = ["Feet", "Meters"]; var dist_unit_full_name = ["Nautic Miles", "Kilometers"]; var spd_unit_full_name = ["Knots", "KM/H"]; @@ -16,9 +16,8 @@ var spd_unit_short_name = ["kt", "km/h"]; var spd_unit = 0; var dist_unit = 0; var alt_unit = 0; -#var apt = nil; -var startpos = nil; -var waypointindex = 0; +var startpos = nil; #geo.nas aircraft position +var waypointindex = 0; #step in actual task var thresold_alert = [120, 60, 30, 15]; var thresold_alert_index = 1; var thresold_next_waypoint = 5; @@ -29,7 +28,7 @@ NOT_YET_IMPLEMENTED = [ "IMPLEMENTED", "" ]; -var page = 0; +var LINES = 5; #lines in display var page_list = [ [0,0,0,0,0,0], #0 ModeAndSettings: 1 page for mode, 5 pages for settings [1,2,3], #1 PositionMain, Odometers, WindInfos @@ -52,54 +51,56 @@ var gps_data = props.globals.getNode("/instrumentation/gps",1); var gps_wp = gps_data.getNode("wp",1); #### warps for buttons and knobs ########################################" -var right_knob = func(dir) { +var right_knob = func(dir) { #manage right knob, depends of displayed screen isOn == 1 or return; screen[displayed_screen].right(dir); refresh_display(); } -var enter_button = func() { +var enter_button = func() { #manage enter button, depends of displayed screen isOn == 1 or return; screen[displayed_screen].enter(); refresh_display(); } -var escape_button = func() { +var escape_button = func() { #manage escape button, depends of displayed screen isOn == 1 or return; screen[displayed_screen].escape(); refresh_display(); } -var start_button = func() { +var start_button = func() { #manage start button, depends of displayed screen isOn == 1 or return; screen[displayed_screen].start(); refresh_display(); } -var left_knob = func(dir) { +var left_knob = func(dir) { #manage left button, cycle in mode's pages if not blocked isOn == 1 or return; - page = cycle(size(page_list[mode]), page, dir); - if (blocked == 0) displayed_screen = page_list[mode][page]; + if (blocked == 0) { + page = cycle(size(page_list[mode]), page, dir); + displayed_screen = page_list[mode][page]; + } refresh_display(); } -var select_mode = func(dir) { +var select_mode = func(dir) { #manage mode knob, cycle into available modes isOn == 1 or return; blocked = 0; if (displayed_screen != 0) { displayed_screen = 0; #screenModeAndSettings page = 0; - screen[displayed_screen].changemode(0); + mode = 0; } - else - screen[displayed_screen].changemode(dir); + elsif (page == 0) + screen[0].mode_ = cycle(size(screen[0].available_modes), screen[0].mode_, dir); refresh_display(); } -var switch_ON_OFF = func() { +var switch_ON_OFF = func() { #manage ON/OFF knob if (isOn) { isOn = 0; - for (var i = 0; i < 5; i += 1) line[i].setValue(""); + for (var i = 0; i < LINES; i += 1) line[i].setValue(""); } else { isOn = 1; @@ -111,33 +112,35 @@ var switch_ON_OFF = func() { } ### useful funcs ######################################################### -var display = func () { - for (var i = 0; i < 5; i += 1) line[i].setValue(arg[0][i]); +var display = func () { #display the array line[] + for (var i = 0; i < LINES; i += 1) line[i].setValue(arg[0][i]); } var browse = func (entries_nbr, index_pointer, index_page,dir) { - nl = entries_nbr - (index_page * 5) > 5 ? 5 : math.mod(entries_nbr - (index_page * 5), 5); + #browse multipaged entries, returns [pointer in page, page] + nl = entries_nbr - (index_page * LINES) > LINES ? LINES : math.mod(entries_nbr - (index_page * LINES), LINES); if (index_pointer + 1 == nl) { - np = int(entries_nbr / 5) + (math.mod(entries_nbr,5) ? 1 : 0); + np = int(entries_nbr / LINES) + (math.mod(entries_nbr,LINES) ? 1 : 0); index_page = cycle(np, index_page, dir); } index_pointer = cycle(nl, index_pointer, dir); return [index_pointer, index_page]; } -var cycle = func (entries_nbr, actual_entrie, dir) { +var cycle = func (entries_nbr, actual_entrie, dir) { + #cycle through entries, return entry index entries_nbr -= 1; if (dir == 1 and actual_entrie == entries_nbr) return 0; elsif (dir == -1 and actual_entrie == 0) return entries_nbr; else return actual_entrie + dir; } -var refresh_display = func() { +var refresh_display = func() { #refresh displayed lines, settimer if necessary screen[displayed_screen].lines(); if (isOn and 0 < displayed_screen < 5 ) settimer(func { refresh_display(); }, freq, 1); } -var seconds_to_string = func (time) { +var seconds_to_string = func (time) { #converts secs (double) in string "hh:mm:ss" var hh = int(time / 3600); if (hh > 100) return "--:--:--"; var mm = int((time - (hh * 3600)) / 60); @@ -146,7 +149,7 @@ var seconds_to_string = func (time) { } ### route management ###################################################### -var list_routes = func { +var list_routes = func { #load preprogrammed tasks routes = []; var path = getprop("/sim/fg-home") ~ "/Routes"; var s = io.stat(path); @@ -163,7 +166,7 @@ var list_routes = func { return size(routes); } -var add_waypoint = func (ID, name, type, coord) { +var add_waypoint = func (ID, name, type, coord) { #add a waypoint to a route var waypoint = gps_data.getNode("route/Waypoint["~screenWaypointsList.n~"]/",1); screenWaypointsList.n += 1; waypoint.getNode("ID",1).setValue(ID); @@ -175,7 +178,8 @@ var add_waypoint = func (ID, name, type, coord) { waypoint.getNode("waypoint-type",1).setValue(type); } -var save_route = func { +var save_route = func { #save the route + screenWaypointsList.n != 0 or return; var first_id = gps_data.getNode("route/Waypoint/ID").getValue(); var last_id = gps_data.getNode("route/Waypoint["~(screenWaypointsList.n - 1)~"]/ID").getValue(); var path = getprop("/sim/fg-home") ~ "/Export/"~first_id~"-"~last_id~".xml"; @@ -185,7 +189,7 @@ var save_route = func { fgcommand("savexml", args); } -var waypointAlert = func { +var waypointAlert = func { #alert pilot about waypoint approach mode > 0 or return; var ttw = gps_wp.getNode("wp[1]/TTW",1).getValue(); var ttw_secs = 9999; @@ -197,12 +201,12 @@ var waypointAlert = func { else gps_data.getNode("waypoint-alert",1).setBoolValue(0); - if (mode == 3 and ttw_secs < thresold_next_waypoint) + if (mode == 4 and ttw_secs < thresold_next_waypoint) screenNavigationMain.nextWaypoint(); } ### turnpoints management ###################################################### -var load_bookmarks = func { +var load_bookmarks = func { #load turnpoints var n = 0; gps_data.getNode("bookmarks",1).removeChildren("bookmark"); var file = getprop("/sim/fg-home") ~ "/Export/bookmarks.xml"; @@ -217,7 +221,7 @@ var load_bookmarks = func { return n; } -var save_bookmarks = func { +var save_bookmarks = func { #save turnpoints var path = getprop("/sim/fg-home") ~ "/Export/bookmarks.xml"; var args = props.Node.new({ filename : path }); var export = args.getNode("data", 1); @@ -225,30 +229,39 @@ var save_bookmarks = func { fgcommand("savexml", args); } -var add_bookmark = func (ID, name, type, coord) { +var add_bookmark = func (ID, name, type, coord) { #add turnpoint var bookmark = gps_data.getNode("bookmarks/bookmark["~screenTurnpointSelect.n~"]/",1); screenTurnpointSelect.n += 1; bookmark.getNode("ID",1).setValue(ID); bookmark.getNode("latitude-deg",1).setDoubleValue(coord[0]); bookmark.getNode("longitude-deg",1).setDoubleValue(coord[1]); bookmark.getNode("altitude-ft",1).setDoubleValue(coord[2]*alt_conv[1][0]); - bookmark.getNode("name",1).setValue(name); bookmark.getNode("desc",1).setValue("no infos"); + bookmark.getNode("name",1).setValue(name); bookmark.getNode("waypoint-type",1).setValue(type); save_bookmarks(); } -var EditMode = func (length, start_command, start_func, backmode, backpage, numcar = 0) { - #screenEdit.previous_mode = backmode; - #screenEdit.previous_page = backpage; +var EditMode = func (length, title, start_command, numcar = 0) { + #special mode for editing simple text + screenEdit.previous_mode = mode; + screenEdit.previous_page = page; mode = 5; #ID edition page = 0; - screenEdit.init(length, start_command, start_func, backmode, backpage, numcar = 0); + screenEdit.init(length, title, start_command, numcar); } ### initialisation stuff ################################################### var init = func() { - for (var i = 0; i < 5; i += 1) { + mode = 0; + page = 0; + displayed_screen = 0; #screenModeAndSettings + blocked = 0; #unlock left_knob + isOn = 0; #start OFF + startpos = nil; #unset start position + waypointindex = 0; #route waypoint index on beginning + screen = []; #empty screens + for (var i = 0; i < LINES; i += 1) { append(line, props.globals.getNode("/instrumentation/zkv500/line[" ~ i ~ "]", 1)); line[i].setValue(""); } diff --git a/Aircraft/Instruments-3d/zkv500/manual.txt b/Aircraft/Instruments-3d/zkv500/manual.txt new file mode 100644 index 000000000..6604dd3bf --- /dev/null +++ b/Aircraft/Instruments-3d/zkv500/manual.txt @@ -0,0 +1,389 @@ + ############## GPL + # GPS ZKV500 # Sébastien MARQUE + ############## 2008, Paris (France) + +note that it is still under heavy development, some functions planned haven't +been 100% tested yet... there surely will be bugs or errors (most of the time: +nasal runtime error : props.setValue() with non number, etc.) + + +CONTENTS +========= +1. A bit of history +2. Install onboard + 1. Normal installation + 2. Debugging installation + 3. Without 3D interface +3. Global presentation +4. User's Manual + 1. Powering ON + 2. List of screens + 3. The modes + 4. Editing some text +5. FG integration +6. Examples +7. The future + +1. A BIT OF HISTORY +=================== +Don't search on the market this device, it doesn't exists! :p Indeed I was +looking how to create a GPS device in my favorite aircraft, I found the +nice 3D object in the not less nice Grob-G115, which it was told me it +is intented for the LX5000 gps (http://www.wingsandwheels.com/manuals.htm). + +So I began to write some nasal code, using the C++ implementation of KLN89 +already built-in FG, to fit as much as possible the LX5000 specifications. +But after some tries, I began to create on my own way the interface (which +is much more funny for me than following a manual :)). The ZKV500 was born. +(read ZaKharoV, which is my current nickname, from Proktor Zakharov in Sid +Meyer's Alpha Centauri game :)) +It keeps by default the very nice 3D object from Jon Stockill, a bit modified. +I created also for this device a special font in order to make the LCD diplay +more... lcd-compliant (see Fonts/lcd.README). + +2. INSTALL THE ZKV500 ONBOARD +============================= + + 1. Normal installation + +For now the ZKV500 seats in Aircraft/Instruments-3d/zvk500/, making it easily +available for all aircrafts. To install it, just add these lines in your config +files, inside the section: + + Aircraft/Instruments-3d/zkv500/ZKV500.nas + Aircraft/Instruments-3d/zkv500/MainScreens.nas + Aircraft/Instruments-3d/zkv500/TurnpointScreens.nas + Aircraft/Instruments-3d/zkv500/TaskScreens.nas + Aircraft/Instruments-3d/zkv500/AirportScreens.nas + +[example from Lionceau: Aircraft/Lionceau/lionceau-base.xml] +Please note that is mandatory for namespaces reasons. + +Then in your panel configuration file, just put the 3D model, as usual: + + + Aircraft/Instruments-3d/zkv500/ZKV500.xml + + 0.002 + -0.051 + -0.022 + + +[example from Lionceau: Aircraft/Lionceau/Models/Panel/front-panel.xml] +Your ZKV500 is ready to be powered on! + +The ZKV500 has IO capacities: routes are red from $FGHOME/Routes and +written in $FGHOME/Export, the bookmarks are red and written in +$FGHOME/Export/bookmarks.xml + +An easy way to populate your $FGHOME/Routes directory is a perl script +of my own (see the end of file for an how-to). You can also editing by +hand, the format is simple and conform to the format used by the KLN89 + + + TL + 43.28838900 + 000.04963900 + 0 + NBD + TARBES NDB + Xroads freq: 321 + + + LFCB + 42.800000 + 000.600000 + 2028 + APT + Bagneres de Luchon + In a valley + + +The less easy way is to edit your flightplan direcly from the ZKV500, but +as it has very limited editing capacities, and the search of already-known +waypoints is limited to airports, it is not a really recommended way. + +The $FGHOME/Export/bookmarks.xml file contains favorites points, it has +quite the same format than a route file: + + ... + + LFBT + 43.178643 + -0.006341 + 1179.785445 + Tarbes Ossun Lourdes + no infos + APT + + ... + +The ZKV500 is quite useful to create bookmarks on the fly. + + 2. Debugging installation + +if you want to debug the nasal, you can use the "debugging tool" I've created: + - comment in your aircraft files all gps-related installation + - edit the Aircraft/Instruments-3d/zkv500/*.nas files with your favourite + text editor + - in the Nasal console from FGside type: +var zkv_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/zkv500/"; +io.load_nasal(zkv_dir ~ "zkv_dbg.nas", "zkv_dbg"); +zkv_dbg.reload_zkv_code(); + - click on "Execute" + - find errors + - modify source code then re-click on "Execute" until satisfaction (or death :D) + + 3. Without 3D interface + +if you want to use the zkv500 without the 3D interface and all installation steps +as described above, type in a Nasal console: +var zkv_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/zkv500/"; +io.load_nasal(zkv_dir ~ "zkv_dbg.nas", "zkv_dbg"); +zkv_dbg.test(); + + + +3. GLOBAL PRESENTATION +====================== +The interface is simple: +(http://seb.marque.free.fr/fichiers/flightgear/zkv500/presentation.png) +* 4 knobs turning left (left mouse clic) or right (right mous clic) +* 3 white buttons +* 1 LCD display +* 2 LEDs (red and green) + + enter escape start + button button button +PAGE|------------------------|SELECT +KNOB| |KNOB + | LCD DISPLAY | + | 5 LINES | +MODE| |ON/OFF +KNOB|------------------------|KNOB + red green + led led + +-> PAGE knob allows you to cycle in the different pages available for + each mode. +-> SELECT knob allows yo to navigate in a page, or select element, or + edit some simple text (depending of screen). +-> MODE knob allows you to select a mode, and acces to the ZKV500 settings + you can access this knob at any time, any screen. +-> ON/OFF knob allows you to turn ON and OFF the ZKV500, note it is a knob + because I plan to associate some sounds with the ZKV500, this knob then + could be used to change the volume. + +The goal of each button depends of the displayed screen. + +4. USER'S MANUAL +================ + 1. Powering ON +To power ON, just left click on the ON/OFF knob. Clicking again wil make it +turning OFF. When powered you are on the ModeAndSettings screen. + + 2. Screens list +*** ModeAndSettings *** +From this screen you can change from a mode to another mode (see 4.3 Modes, below) + START...enter in a mode + PAGE....enter in settings pages (cycle) + SELECT..modify settings + +the available settings are: + * units + you can change the displayed unit for altitude, distance and speed. + the units are long named, on other screens only short name wilm be + displayed. + * thresolds + you can change the thresold from when the ZKV500 will alert you about + next waypoint approach, or will load the next waypoint into calculation. + +*** PositionMain *** +This page gives you infos about the aircraft position. +You find it in every modes. + ENTER...save the position as a bookmark (entering in Edit screen) + + LAT: latitude in deg:min:sec + LON: longitude in deg:min:sec + ALT: altitude + HDG: geographic cap (! not magnetic cap, or aircraft heading) + SPD: speed + +*** Odometers *** +This screen gives you odo-values. You can find it in every modes. + ESCAPE...reset odometers, except TRIP + + ODO: travelled distance + TRIP: total travelled distance + TIME: elapsed time from last reset + AVG HDG: average heading + AVG SPD: average speed + +*** WindInfos *** +This screens gives you infos about wind as it should be calculated by the +GPS, indeed, as the calculation is already done elsewhere, it takes the value +from /environnement/* node (btw I don't really know how to calculate correctly +these values). You need to have a airspped > 10kts for having it work. This +screen is available on every modes + + SPEED: windspeed + FROM: the direction where the wind come from (geographic North) + +*** NavigationMain *** +This screen gives the related position of the aircraft about the calcualted +route. It is only available in TURNPOINT and TASK modes. + + ENTER...TURNPOINT mode: add the actual position to the route, + TASK mode: jump to next waypoint + START...save the route (mode TURNPOINT only) + + ID: Id of the waypoint to go [waypoint type] + BRG: bearing from the aircraft to the waypoint (geographic) + DST: remaining distance + XCRS: course error in degree (in distance unit) + TTW: remaining estimated time +The graph represent the position of the aircraft along the leg. Each + means 1°, +the | symbol represents the route, the little aircraft represents... the aircraft. + +*** AirportMain *** +This screen gives infos about the nearest, or a specific searched airport (see +SearcAirport screen, below). It is only reachable from AIRPORT mode. + + ENTER...add the airport to route + ESCAPE..get the nearest airport + START...add airport to bookmarks, and enter TURNPOINT mode, to go directly + + NEAREST or SEARCHED APT: OACI code of airport + ELEV: airport altitude + DIST: distance between aircraft and airport + BRG: bearing from aircraft to airport (geographic) + RWY: best runway calculated from known wind, it is to say not really useful + when airport is very far away... + ETE: estimated time enroute to go + +*** AirportInfos *** +This screen gives infos about the airport (nearest or searched). It is only +reachable from AIRPORT mode. + + SELECT...navigate in the runway list (not yet implemented) + +First line gives the full name of airport +Lines below show the runways with the format + heading (length in meters / width in meters) + +*** SearchAirport *** +This screen allows you to search an airport from OACI code. It is reachable from +AIRPORT mode. +If the search is successful, the AirportMain screen is shown, in other case the text +is erased, and you are invited to retry. + + SELECT...modify letter (from A to Z then 0 to 9, cycled) + ENTER....next step + ESCAPE...back to AirportMain screen, without search + START....search the given OACI code + +*** TurnpointSelect *** +This screen shows a list of already bookmarked gps points. It is only available +in TURNPOINT mode. + + SELECT...navigate through the list (eventually through multiple pages) + START....begin the navigation from actual position to the bookmark + +*** TurnpointInfos *** +This screen is not yet implemented. It will gives infos about the bookmark + +*** TaskSelect *** +This screen allows you to choose a route (if one available). It is only available +in TASK mode. + + SELECT...navigate through the routes list (eventually through multiple pages) + START....load the route, and begins navigation + +*** WaypointInfos *** +Not yet implemented, will give infos about waypoint. Only available in TASK mode. + +*** WaypointsList *** +This screen shows the list of waypoint loaded from a route. + SELECT...navigate through the list + +*** WaypointEdit *** +This screen allows you to name a gps point in order to bookmark it. + + SELECT...cycle letters (from A to Z then 1 to 9) + ENTER....next step + ESCAPE...abort saving bookmark + START....save bookmark + + 3. the 4 modes +*** POSITION *** +The simpliest one, just give information about the aircraft position. You can +save bookmarks from this mode (pressing ENTER in PositionMain screen). + PAGE...cycle through these screens (both ways): +PositionMain, Odometers, WindInfos + +*** AIRPORT *** +Useful to know wher you can put you aircraft safely on the ground, gives other infos +as the best runway, it is possible to search an airport (turn the PAGE knob until +Search airport page), add the airport to a route or as a bookmark (automatically +called by airports ID and name). + PAGE...cycle through these screens (both ways) +AirportMain, NavigationMain, PositionMain, Odometers, WindInfos, AirportInfos, SearchAirport + +*** TURNPOINT *** +Useful mode to join a specific point of interest, or to navigate around. + PAGE...cycle through these screens (both ways) +TurnpointSelect, NavigationMain, PositionMain, Odometers, WindInfos, TurnpointInfos + +*** TASK *** +Most useful mode :). Follow the route to go through long distances, without being +lost at anytime (even with no VOR or NDB near enough to get capted by radios). Or +if you aren't IFR skilled :D +When approaching a waypoint, a red led blink (this can be set in ModeAndSettings screens) +When on the point (idem), it loads autmatically the next point and calculate the leg infos +When the last point is reached, it come back to TaskSelect screen to allow chosing an other +route. + PAGE...cycle through these screens (both ways) +TaskSelect, NavigationMain, PositionMain, Odometers, WindInfos, WaypointInfos, WaypointsList + +5. FG INTEGRATION +================= +You can change the waypoints directly from the property tree (/instrumentation/gps) +or using the GUI (Menu Instruments -> GPS Settings). +Please note that, at this stage of development, I haven't yes set listeners +on the properties, when changing the waypoint, new route is automatically +calculated, but changing them don't call yet the correct mode and page. + +6. PRACTICAL EXAMPLES +===================== + +7. THE FUTURE +============= +The ZKV500 still lacks many features I plan to implement. I stop adding features +for now, as I want it to be the more bug-free possible before creating other bugs. + 1. PLANNED FEATURES +* integrated help +* description pages (waypoints and airports) +* more useful informations +* make use of green led (for which use? surely depends of the above) +* altitude control +* two ways routes (toward and back) + + 2. PLANNED FEATURES LIMITED BY FG "API'S" +* search for VOR/TAC, NDB and FIX capacities + + 2. NOT PLANNED FEATURES +* graphical view of regions + +8. ANNEXES +========== + 1. creating flightplans with ./flightplan +You can get ./flightplan from this link: http://seb.marque.free.fr/fichiers/scripts/perl/flightplan +Make it executable, best to set $FGROOT and $FGHOME to respectives folders +For creating a flightplan from LFPT to LFBD: +$ ./flightplan -d lfpt -a lfbd --wpt +This will write in $FGHOME/Routes a file named lfpt-lfbd.xml, suitable for the +ZKV500 + +Sébastien MARQUE +seb.marque@free.fr + diff --git a/Aircraft/Instruments-3d/zkv500/zkv_dbg.nas b/Aircraft/Instruments-3d/zkv500/zkv_dbg.nas new file mode 100644 index 000000000..671b62ba3 --- /dev/null +++ b/Aircraft/Instruments-3d/zkv500/zkv_dbg.nas @@ -0,0 +1,108 @@ +var dialog = nil; +var namenode = nil; + +var close = func { + zkv500.isOn = 0; + fgcommand("dialog-close", namenode); + delete(gui.dialog, "\"zkv500\""); + dialog = nil; +} + +var _title = func { + var titlebar = dialog.addChild("group"); + titlebar.set("layout", "hbox"); + var wdg = titlebar.addChild("text"); + wdg.set("label", "test zkv500"); + titlebar.addChild("empty").set("stretch", 1); + var wdg = titlebar.addChild("button"); + wdg.node.setValues({"pref-width": 16, "pref-height": 16, legend: "", default: 0}); + wdg.setBinding("nasal", "zkv_dbg.close()"); +} + +var _top_buttons = func { + dialog.addChild("hrule"); + var buttons = dialog.addChild("group"); + buttons.set("layout", "hbox"); + var wdg = buttons.addChild("button"); + wdg.node.setValues({legend: "P", "pref-height": 20}); + wdg.setBinding("nasal", "zkv500.left_knob(1)"); + var wdg = buttons.addChild("button"); + wdg.node.setValues({legend: "en", "pref-height": 20}); + wdg.setBinding("nasal", "zkv500.enter_button()"); + var wdg = buttons.addChild("button"); + wdg.node.setValues({legend: "es", "pref-height": 20}); + wdg.setBinding("nasal", "zkv500.escape_button()"); + var wdg = buttons.addChild("button"); + wdg.node.setValues({legend: "st", "pref-height": 20}); + wdg.setBinding("nasal", "zkv500.start_button()"); + var wdg = buttons.addChild("button"); + wdg.node.setValues({legend: "S", "pref-height": 20}); + wdg.setBinding("nasal", "zkv500.right_knob(1)"); +} + +var _content = func { + dialog.addChild("hrule"); + var content = dialog.addChild("group"); + content.set("layout", "table"); + content.set("default-padding", 0); + for (var i = 0; i < 5; i += 1) { + var line = content.addChild("text"); + line.node.setValues({"row":i,"col":0,"label":" "}); + var line = content.addChild("text"); + line.node.setValues({ + "row": i, + "col": 1, + "property": "/instrumentation/zkv500/line["~i~"]", + "halign": "left", + "live": 1 + }); + var line = content.addChild("text"); + line.node.setValues({"row":i,"col":2,"label":" "}); + } +} + +var _bottom_buttons = func { + dialog.addChild("hrule"); + var buttons = dialog.addChild("group"); + buttons.set("layout", "hbox"); + var wdg = buttons.addChild("button"); + wdg.node.setValues({legend: "M", "pref-height": 20}); + wdg.setBinding("nasal", "zkv500.select_mode(1)"); + buttons.addChild("empty").set("stretch", 1); + var wdg = buttons.addChild("button"); + wdg.node.setValues({legend: "0/1", "pref-height": 20}); + wdg.setBinding("nasal", "zkv500.switch_ON_OFF()"); +} + +var reload_zkv_code = func { + var zkv500_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/zkv500/"; + io.load_nasal(zkv500_dir ~ "ZKV500.nas","zkv500"); + io.load_nasal(zkv500_dir ~ "AirportScreens.nas","zkv500"); + io.load_nasal(zkv500_dir ~ "TurnpointScreens.nas","zkv500"); + io.load_nasal(zkv500_dir ~ "MainScreens.nas","zkv500"); + io.load_nasal(zkv500_dir ~ "TaskScreens.nas","zkv500"); + print("debugger: zkv500 loaded"); + zkv500.isOn = 0; + zkv500.init(); +} + +var test = func { + dialog == nil or close(); + reload_zkv_code(); + + namenode = props.Node.new({"dialog-name" : "zkv500" }); + dialog = gui.Widget.new(); + dialog.set("name", "zkv500"); + + dialog.set("layout", "vbox"); + dialog.set("default-padding", 0); + + _title(); + _top_buttons(); + _content(); + _bottom_buttons(); + + fgcommand("dialog-new", dialog.prop()); + fgcommand("dialog-show", namenode); + print("debugger: zkv500 testing interface loaded"); +}