From 8dafff9933a314d835556097a46b88264f11324b Mon Sep 17 00:00:00 2001 From: Richard Harrison <rjh@zaretto.com> Date: Thu, 16 Nov 2017 02:55:07 +0100 Subject: [PATCH] MFD framework - add support for Emesary Allow a MFD to be controlled via Emesary notifications (notifications.PFDEventNotification); Notification needs to be constructed with the following parameters; 1 - MFD designation (text; name of MFD) 2 - MFD identity (int, id of the MFD within the model). Default 1; same as used when creating the MFD 3 - Event type (PFDEventNotification.SoftKeyPushed, notifications.PFDEventNotification.ChangeMenuText 4 - Event parameter. a) for PFDEventNotification.SoftKeyPushed an int identifying the button b) for notifications.PFDEventNotification.ChangeMenuText a hash array containing the menu ID and the new text (e.g. [{ Id: 1, Text: "NNN"}]) Method obj.PFD.RegisterWithEmesary(emesary.GlobalTransmitter) need to be called to connect the MFD to a transmitter --- Nasal/canvas/MFD_Generic.nas | 62 +++++++++++++++++++++++++++++++++++- Nasal/notifications.nas | 62 ++++++++++++++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/Nasal/canvas/MFD_Generic.nas b/Nasal/canvas/MFD_Generic.nas index 5afe46c8b..7789aec4c 100644 --- a/Nasal/canvas/MFD_Generic.nas +++ b/Nasal/canvas/MFD_Generic.nas @@ -137,7 +137,7 @@ var PFD_Device = # This does not actually create the canvas elements, or parse the SVG, that would typically be done in # a higher level class that contains an instance of this class. # see: http://wiki.flightgear.org/Canvas_MFD_Framework - new : func(svg, num_menu_buttons, button_prefix, _canvas) + new : func(svg, num_menu_buttons, button_prefix, _canvas, designation="MFD") { var obj = {parents : [PFD_Device] }; obj.svg = svg; @@ -146,6 +146,11 @@ var PFD_Device = obj.pages = []; obj.page_index = {}; obj.buttons = setsize([], num_menu_buttons); + obj.transmitter = nil; + + # change after creation if required + obj.device_id = 1; + obj.designation = designation; for(var idx = 0; idx < num_menu_buttons; idx += 1) { @@ -159,9 +164,64 @@ var PFD_Device = obj.buttons[idx].setText(sprintf("M",idx)); } } + obj.Recipient = nil; return obj; }, # + # instead of using the direct call method this allows the use of Emesary (via a specified or default global transmitter) + # example to notify that a softkey has been used. The "1" in the line below is the device ID + # var notification = notifications.PFDEventNotification.new(me.designation, me.DeviceId, notifications.PFDEventNotification.SoftKeyPushed, me.mpcd_button_pushed); + # emesary.GlobalTransmitter.NotifyAll(notification); + # - currently supported is + # 1. setting menu text directly (after page has been loaded) + # notifications.PFDEventNotification.new(me.designation, 1, notifications.PFDEventNotification.ChangeMenuText, [{ Id: 1, Text: "NNN"}]); + # 2. SoftKey selection. + # + # the device ID must match this device ID (to allow for multiple devices). + RegisterWithEmesary : func(transmitter = nil){ + if (transmitter == nil) + transmitter = emesary.GlobalTransmitter; + + if (me.Recipient == nil){ + me.Recipient = emesary.Recipient.new("PFD_"~me.designation); + var pfd_obj = me; + me.Recipient.Receive = func(notification) + { + if (notification.Device_id = pfd_obj.device_id + and notification.NotificationType == notifications.PFDEventNotification.DefaultType) { + if (notification.Event_Id == notifications.PFDEventNotification.SoftKeyPushed + and notification.EventParameter != nil) + { + pfd_obj.notifyButton(notification.EventParameter); + } + else if (notification.Event_Id == notifications.PFDEventNotification.ChangeMenuText + and notification.EventParameter != nil) + { + foreach(var eventMenu; notification.EventParameter) { + foreach (var mi ; pfd_obj.current_page.menus) { + if (pfd_obj.buttons[eventMenu.Id] != nil) { + pfd_obj.buttons[eventMenu.Id].setText(eventMenu.Text); + } + else + printf("PFD_device: Menu for button not found. Menu ID '%s'",mi.menu_id); + } + } + } + return emesary.Transmitter.ReceiptStatus_OK; + } + return emesary.Transmitter.ReceiptStatus_NotProcessed; + }; + transmitter.Register(me.Recipient); + me.transmitter = transmitter; + } + }, + DeRegisterWithEmesary : func(transmitter = nil){ + # remove registration from transmitter; but keep the recipient once it is created. + if (me.transmitter != nil) + me.transmitter.DeRegister(me.Recipient); + me.transmitter = nil; + }, + # # called when a button is pushed - connecting the property to this method is implemented in the outer class notifyButton : func(button_id) { diff --git a/Nasal/notifications.nas b/Nasal/notifications.nas index 79988265e..48dd08a7d 100644 --- a/Nasal/notifications.nas +++ b/Nasal/notifications.nas @@ -25,7 +25,8 @@ var PropertySyncNotificationBase_Id = 16; var AircraftControlNotification_Id = 17; var GeoEventNotification_Id = 18; - +# event ID 19 reserved for armaments and stores (model defined). +var PFDEventNotification_Id = 20; # # PropertySyncNotificationBase is a wrapper class for allow properties to be synchronized between @@ -167,6 +168,8 @@ var GeoEventNotification = new_class.w_fps = getprop("/velocities/wBody-fps"); new_class.IsDistinct = 0; new_class.Callsign = nil; # populated automatically by the incoming bridge when routed + new_class.RemoteCallsign = ""; # associated remote callsign. + new_class.Flags = 0; # 8 bits for whatever. new_class.bridgeProperties = func { @@ -200,6 +203,14 @@ var GeoEventNotification = getValue:func{return emesary.TransferFixedDouble.encode(new_class.w_fps,2,10);}, setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,2,10,pos);new_class.w_fps=dv.value;return dv}, }, + { + getValue:func{return emesary.TransferString.encode(new_class.RemoteCallsign);}, + setValue:func(v,root,pos){var dv=emesary.TransferString.decode(v,pos);new_class.RemoteCallsign=dv.value;return dv}, + }, + { + getValue:func{return emesary.TransferByte.encode(new_class.Flags);}, + setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Flags=dv.value;return dv}, + }, ]; }; return new_class; @@ -210,7 +221,7 @@ var GeoEventNotification = # 1 - Created # 2 - Moved # 3 - Deleted -# 4 - +# 4 - Collision # ---- # Secondary kind (8 bits) # using the first 4 bits as the classification and the second 4 bits as the sub-classification @@ -502,3 +513,50 @@ var GeoEventNotification = # 253 1111 1101 - # 254 1111 1110 - # 255 1111 1111 - + + +# +# +# Use to transmit events that happen at a specific place; can be used to make +# models that are simulated locally (e.g. tankers) appear on other player's MP sessions. +var PFDEventNotification = +{ +# new: +# _ident - the identifier for the notification. not bridged. +# _pfd_id - numeric identification of the PFD within the model +# _event_id - event ID. +# 1 softkey pushed. +# 2 select page by ID +# _event_param - param related to the event ID. implementation specific. +## + SoftKeyPushed : 1, + SelectPageById : 2, + ChangeMenuText : 3, #event parameter contains hash of { Id: , Text: } + DefaultType : "PFDEventNotification", + + new: func(_ident, _device_id,_event_id,_event_parameter_id) + { + var new_class = emesary.Notification.new(PFDEventNotification.DefaultType, _ident, PFDEventNotification_Id); + new_class.Device_Id = _device_id; + new_class.Event_Id = _event_id; + new_class.EventParameter = _event_parameter_id; + + new_class.IsDistinct = 1; # each of these events is unique and needs to be bridged + + new_class.bridgeProperties = func + { + return + [ + { + getValue:func{return emesary.TransferByte.encode(new_class.Event_Id);}, + setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Event_Id=dv.value;return dv}, + }, + { + getValue:func{return emesary.TransferByte.encode(new_class.EventParameter);}, + setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.EventParameter=dv.value;return dv}, + }, + ]; + }; + return new_class; + }, +};