Emesary MFD bridge: Difference between revisions
Line 72: | Line 72: | ||
debug.dump( request.response ); | debug.dump( request.response ); | ||
}); | }); | ||
</syntaxhighlight> | |||
<syntaxhighlight lang="nasal"> | |||
var MPCD_Device = | |||
{ | |||
# | |||
# create new MFD device. This is the main interface (from our code) to the MFD device | |||
# Each MFD device will contain the underlying PFD device object, the SVG, and the canvas | |||
# Parameters | |||
# - designation - Flightdeck Legend for this | |||
# - model_element - name of the 3d model element that is to be used for drawing | |||
# - model_index - index of the device | |||
new : func(designation, model_element, model_index=0) | |||
{ | |||
var obj = {parents : [MPCD_Device] }; | |||
obj.designation = designation; | |||
obj.model_element = model_element; | |||
var dev_canvas= canvas.new({ | |||
"name": designation, | |||
"size": [1024,1024], | |||
"view": [740,680], | |||
"mipmapping": 1 | |||
}); | |||
dev_canvas.addPlacement({"node": model_element}); | |||
dev_canvas.setColorBackground(0.003921,0.1764,0, 0); | |||
# Create a group for the parsed elements | |||
obj.PFDsvg = dev_canvas.createGroup(); | |||
var pres = canvas.parsesvg(obj.PFDsvg, "Nasal/MPCD/MPCD_0_0.svg"); | |||
# Parse an SVG file and add the parsed elements to the given group | |||
printf("MPCD : %s Load SVG %s",designation,pres); | |||
obj.PFDsvg.setTranslation (270.0, 197.0); | |||
# | |||
# create the object that will control all of this | |||
obj.num_menu_buttons = 20; | |||
obj.PFD = PFD_Device.new(obj.PFDsvg, obj.num_menu_buttons, "MI_", dev_canvas); | |||
obj.PFD._canvas = dev_canvas; | |||
obj.PFD.designation = designation; | |||
obj.mfd_device_status = 1; | |||
obj.model_index = model_index; # numeric index (1 to 9, left to right) used to connect the buttons in the cockpit to the display | |||
obj.addPages(); | |||
return obj; | |||
}, | |||
addPages : func | |||
{ | |||
me.p1_1 = me.PFD.addPage("Aircraft Menu", "p1_1"); | |||
me.p1_1.update = func | |||
{ | |||
var sec = getprop("instrumentation/clock/indicated-sec"); | |||
me.page1_1.time.setText(getprop("sim/time/gmt-string")~"Z"); | |||
var cdt = getprop("sim/time/gmt"); | |||
if (cdt != nil) | |||
me.page1_1.date.setText(substr(cdt,5,2)~"/"~substr(cdt,8,2)~"/"~substr(cdt,2,2)~"Z"); | |||
}; | |||
me.pjitds_1 = PFD_NavDisplay.new(me.PFD,"Situation", "mpcd-sit", "pjitds_1", "jtids_main"); | |||
# use the radar range as the ND range. | |||
# | |||
# Page 1 is the time display | |||
me.p1_1.update = func | |||
{ | |||
var sec = getprop("instrumentation/clock/indicated-sec"); | |||
me.time.setText(getprop("sim/time/gmt-string")~"Z"); | |||
var cdt = getprop("sim/time/gmt"); | |||
if (cdt != nil) | |||
me.date.setText(substr(cdt,5,2)~"/"~substr(cdt,8,2)~"/"~substr(cdt,2,2)~"Z"); | |||
}; | |||
# | |||
# armament page gun rounds is implemented a little differently as the menu item (1) changes to show | |||
# the contents of the magazine. | |||
me.p1_3.gun_rounds = me.p1_3.addMenuItem(1, sprintf("HIGH\n%dM",getprop("sim/model/f15/systems/gun/rounds")), me.p1_3); | |||
setlistener("sim/model/f15/systems/gun/rounds", func(v) | |||
{ | |||
if (v != nil) { | |||
me.p1_3.gun_rounds.title = sprintf("HIGH\n%dM",v.getValue()); | |||
me.PFD.updateMenus(); | |||
} | |||
} | |||
); | |||
me.PFD.selectPage(me.p1_1); | |||
me.mpcd_button_pushed = 0; | |||
# Connect the buttons - using the provided model index to get the right ones from the model binding | |||
setlistener("sim/model/f15/controls/MPCD/button-pressed", func(v) | |||
{ | |||
if (v != nil) { | |||
if (v.getValue()) | |||
me.mpcd_button_pushed = v.getValue(); | |||
else { | |||
printf("%s: Button %d",me.designation, me.mpcd_button_pushed); | |||
me.PFD.notifyButton(me.mpcd_button_pushed); | |||
me.mpcd_button_pushed = 0; | |||
} | |||
} | |||
} | |||
); | |||
# Set listener on the PFD mode button; this could be an on off switch or by convention | |||
# it will also act as brightness; so 0 is off and anything greater is brightness. | |||
# ranges are not pre-defined; it is probably sensible to use 0..10 as an brightness rather | |||
# than 0..1 as a floating value; but that's just my view. | |||
setlistener("sim/model/f15/controls/PFD/mode"~me.model_index, func(v) | |||
{ | |||
if (v != nil) { | |||
me.mfd_device_status = v.getValue(); | |||
print("MFD Mode ",me.designation," ",me.mfd_device_status); | |||
if (!me.mfd_device_status) | |||
me.PFDsvg.setVisible(0); | |||
else | |||
me.PFDsvg.setVisible(1); | |||
} | |||
} | |||
); | |||
me.mpcd_button_pushed = 0; | |||
me.setupMenus(); | |||
me.PFD.selectPage(me.p1_1); | |||
}, | |||
# Add the menus to each page. | |||
setupMenus : func | |||
{ | |||
}, | |||
update : func | |||
{ | |||
if (me.mfd_device_status) | |||
me.PFD.update(); | |||
},# update | |||
}; | |||
# | |||
# Create the MPCD device | |||
var MPCD = MPCD_Device.new("F15-MPCD", "MPCDImage",0); | |||
var updateMPCD = func () | |||
{ | |||
MPCD.update(); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 18:18, 14 October 2017
This article is a stub. You can help the wiki by expanding it. |
Objective
Document ongoing talks and ideas about using the Emesary framework to provide a sane interfacing mechanism for Canvas based avionics (and lower-level MapStructure building blocks) using Richard's Canvas MFD Framework.
Background
Over time, the NavDisplay code has become a huge mess - it is far from being easily maintainable, yet it is the most widely used Canvas-based MFD in use today, mainly because it is generic and can be easily reused, which is due to it having been designed using just a standalone GUI dialog.
So there are some lessons to be learnt from the whole experience.
Nasal modules
- F-15/Nasal/MPCD/MPCD_main.nas
- F-15/Nasal/MPCD/MPCD_0_0.svg
- fgdata/Nasal/canvas/MFD_Generic.nas
- fgdata/Nasal/emesary.nas
Use Cases
Design Goals
The NavDisplay code is structured to support:
- GUI-based prototyping and design/testing of layers
- truly indenpendent instances (an arbitrary number of them)
- styling of ND layers/components according to aircraft specifics (think Boeing vs. Airbus ND)
- encapsulate aircraft/system specifics (think differences between fdm, autopilot and route manager)
- encourage a modular and reusable design of additions, so that all aircraft developers using the framework can benefit automatically
Implementation
We will be hooking up the Canvas MFD framework to a conventional Canvas GUI dialog, so that a MFD instrument can be shown in a standalone GUI dialog. The next step will involve using the Emesary framework to create custom events and actions.
Instantiating a MFD Dialog
See Howto:Creating a Canvas GUI dialog file for the main article about this subject. |
var (width,height) = (640,480);
var title = 'Canvas MFD/Emesary Bridge';
var window = canvas.Window.new([width,height],"dialog").set('title',title);
##
# the del() function is the destructor of the Window
# which will be called upon termination (dialog closing)
# you can use this to do resource management (clean up timers, listeners or background threads)
#window.del = func()
#{
# print("Cleaning up window:",title,"\n");
# explanation for the call() technique at: http://wiki.flightgear.org/Object_oriented_programming_in_Nasal#Making_safer_base-class_calls
# call(canvas.Window.del, [], me);
#};
# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();
var svgURL = "https://sourceforge.net/p/flightgear/fgaddon/HEAD/tree/trunk/Aircraft/F-15/Nasal/MPCD/MPCD_0_0.svg?format=raw";
var svgFile = http.load(svgURL);
svgFile.done( func(request) {
debug.dump( request.response );
});
var MPCD_Device =
{
#
# create new MFD device. This is the main interface (from our code) to the MFD device
# Each MFD device will contain the underlying PFD device object, the SVG, and the canvas
# Parameters
# - designation - Flightdeck Legend for this
# - model_element - name of the 3d model element that is to be used for drawing
# - model_index - index of the device
new : func(designation, model_element, model_index=0)
{
var obj = {parents : [MPCD_Device] };
obj.designation = designation;
obj.model_element = model_element;
var dev_canvas= canvas.new({
"name": designation,
"size": [1024,1024],
"view": [740,680],
"mipmapping": 1
});
dev_canvas.addPlacement({"node": model_element});
dev_canvas.setColorBackground(0.003921,0.1764,0, 0);
# Create a group for the parsed elements
obj.PFDsvg = dev_canvas.createGroup();
var pres = canvas.parsesvg(obj.PFDsvg, "Nasal/MPCD/MPCD_0_0.svg");
# Parse an SVG file and add the parsed elements to the given group
printf("MPCD : %s Load SVG %s",designation,pres);
obj.PFDsvg.setTranslation (270.0, 197.0);
#
# create the object that will control all of this
obj.num_menu_buttons = 20;
obj.PFD = PFD_Device.new(obj.PFDsvg, obj.num_menu_buttons, "MI_", dev_canvas);
obj.PFD._canvas = dev_canvas;
obj.PFD.designation = designation;
obj.mfd_device_status = 1;
obj.model_index = model_index; # numeric index (1 to 9, left to right) used to connect the buttons in the cockpit to the display
obj.addPages();
return obj;
},
addPages : func
{
me.p1_1 = me.PFD.addPage("Aircraft Menu", "p1_1");
me.p1_1.update = func
{
var sec = getprop("instrumentation/clock/indicated-sec");
me.page1_1.time.setText(getprop("sim/time/gmt-string")~"Z");
var cdt = getprop("sim/time/gmt");
if (cdt != nil)
me.page1_1.date.setText(substr(cdt,5,2)~"/"~substr(cdt,8,2)~"/"~substr(cdt,2,2)~"Z");
};
me.pjitds_1 = PFD_NavDisplay.new(me.PFD,"Situation", "mpcd-sit", "pjitds_1", "jtids_main");
# use the radar range as the ND range.
#
# Page 1 is the time display
me.p1_1.update = func
{
var sec = getprop("instrumentation/clock/indicated-sec");
me.time.setText(getprop("sim/time/gmt-string")~"Z");
var cdt = getprop("sim/time/gmt");
if (cdt != nil)
me.date.setText(substr(cdt,5,2)~"/"~substr(cdt,8,2)~"/"~substr(cdt,2,2)~"Z");
};
#
# armament page gun rounds is implemented a little differently as the menu item (1) changes to show
# the contents of the magazine.
me.p1_3.gun_rounds = me.p1_3.addMenuItem(1, sprintf("HIGH\n%dM",getprop("sim/model/f15/systems/gun/rounds")), me.p1_3);
setlistener("sim/model/f15/systems/gun/rounds", func(v)
{
if (v != nil) {
me.p1_3.gun_rounds.title = sprintf("HIGH\n%dM",v.getValue());
me.PFD.updateMenus();
}
}
);
me.PFD.selectPage(me.p1_1);
me.mpcd_button_pushed = 0;
# Connect the buttons - using the provided model index to get the right ones from the model binding
setlistener("sim/model/f15/controls/MPCD/button-pressed", func(v)
{
if (v != nil) {
if (v.getValue())
me.mpcd_button_pushed = v.getValue();
else {
printf("%s: Button %d",me.designation, me.mpcd_button_pushed);
me.PFD.notifyButton(me.mpcd_button_pushed);
me.mpcd_button_pushed = 0;
}
}
}
);
# Set listener on the PFD mode button; this could be an on off switch or by convention
# it will also act as brightness; so 0 is off and anything greater is brightness.
# ranges are not pre-defined; it is probably sensible to use 0..10 as an brightness rather
# than 0..1 as a floating value; but that's just my view.
setlistener("sim/model/f15/controls/PFD/mode"~me.model_index, func(v)
{
if (v != nil) {
me.mfd_device_status = v.getValue();
print("MFD Mode ",me.designation," ",me.mfd_device_status);
if (!me.mfd_device_status)
me.PFDsvg.setVisible(0);
else
me.PFDsvg.setVisible(1);
}
}
);
me.mpcd_button_pushed = 0;
me.setupMenus();
me.PFD.selectPage(me.p1_1);
},
# Add the menus to each page.
setupMenus : func
{
},
update : func
{
if (me.mfd_device_status)
me.PFD.update();
},# update
};
#
# Create the MPCD device
var MPCD = MPCD_Device.new("F15-MPCD", "MPCDImage",0);
var updateMPCD = func ()
{
MPCD.update();
}
Related
References
|