1
0
Fork 0

emesary.nas add comments, type checks; fix typos; add debug/emesary.deb.nas add fgcommand to use the global transmitter

This commit is contained in:
Henning Stahlke 2020-06-29 10:49:18 +02:00 committed by James Turner
parent 8d785cacbc
commit a13f9b3bb0
5 changed files with 373 additions and 101 deletions

View file

@ -0,0 +1,50 @@
#-------------------------------------------------------------------------------
# emesary.deb.nas - emesary debug helpers
#-------------------------------------------------------------------------------
var _emesaryDebugN = props.getNode("/_debug/emesary/",1);
var _emesaryDebugEnableN = _emesaryDebugN.getNode("enabled",1);
_emesaryDebugEnableN.setBoolValue(_emesaryDebugEnableN.getValue());
var __setup = func {
var debugRecipient = emesary.Recipient.new("Debug");
debugRecipient.Receive = func(ntf) {
_emesaryDebugEnableN.getValue() or return;
if (!isa(ntf, emesary.Notification)) {
logprint(DEV_ALERT, "debugRecipient: argument is not a emesary.Notification!");
return emesary.Transmitter.ReceiptStatus_Fail;
}
# ignore FrameNotification as it would flood the log/console at frame rate
if (ntf.NotificationType != "FrameNotification") {
print("debugRecipient: type=", ntf.NotificationType, " id=", ntf.Ident);
debug.dump(keys(ntf));
# count notifications
if (isstr(ntf.NotificationType)) {
var cnt = _emesaryDebugN.getChild(ntf.NotificationType, 0, 1);
if (isstr(ntf.Ident)) {
cnt = cnt.getNode(ntf.Ident, 1);
}
if (cnt.getValue() == nil) {
cnt.setIntValue(0);
}
cnt.increment();
}
}
return emesary.Transmitter.ReceiptStatus_NotProcessed;
}
emesary.GlobalTransmitter.Register(debugRecipient);
# send a test message
var debugNotification = emesary.Notification.new("debug", "test");
emesary.GlobalTransmitter.NotifyAll(debugNotification);
#add monitoring
emesary._transmitters.addCallback(func (k, v) {
emesary._transmitters.keys2props(_emesaryDebugN);
});
emesary._transmitters.keys2props(_emesaryDebugN);
}
settimer(__setup,0);

View file

@ -22,56 +22,101 @@
# #
# Copyright © 2016 Richard Harrison Released under GPL V2 # Copyright © 2016 Richard Harrison Released under GPL V2
# #
#---------------------------------------------------------------------------
# Classes in this file:
# Transmitter
# Notification
# Recipient
#---------------------------------------------------------------------------*/ #---------------------------------------------------------------------------*/
var __emesaryUniqueId = 14; # 0-15 are reserved, this way the global transmitter will be 15. var __emesaryUniqueId = 14; # 0-15 are reserved, this way the global transmitter will be 15.
# add registry so we can find a transmitter by name in genericEmesaryGlobalTransmitterTransmit
var _transmitters = Hash.new("transmitters");
var _registerTransmitter = func (key, t) {
_transmitters.set(key, t);
}
var getTransmitter = func (key) {
return _transmitters.get(key);
}
# Transmitters send notifications to all recipients that are registered. # Transmitters send notifications to all recipients that are registered.
var Transmitter = var Transmitter =
{ {
ReceiptStatus_OK : 0, # Processing completed successfully ReceiptStatus_OK : 0, # Processing completed successfully
ReceiptStatus_Fail : 1, # Processing resulted in at least one failure ReceiptStatus_Fail : 1, # Processing resulted in at least one failure
ReceiptStatus_Abort : 2, # Fatal error, stop processing any further recipieints of this message. Implicitly failed. ReceiptStatus_Abort : 2, # Fatal error, stop processing any further recipients of this message. Implicitly failed.
ReceiptStatus_Finished : 3, # Definitive completion - do not send message to any further recipieints ReceiptStatus_Finished : 3, # Definitive completion - do not send message to any further recipients
ReceiptStatus_NotProcessed : 4,# Return value when method doesn't process a message. ReceiptStatus_NotProcessed : 4,# Return value when method doesn't process a message.
ReceiptStatus_Pending : 5, # Message sent with indeterminate return status as processing underway ReceiptStatus_Pending : 5, # Message sent with indeterminate return status as processing underway
ReceiptStatus_PendingFinished : 6,# Message definitively handled, status indeterminate. The message will not be sent any further ReceiptStatus_PendingFinished : 6,# Message definitively handled, status indeterminate. The message will not be sent any further
# create a new transmitter. shouldn't need many of these # create a new transmitter. shouldn't need many of these
# _ident: string; name of the transmitter, used in debug messages
new: func(_ident) new: func(_ident)
{ {
var new_class = { parents: [Transmitter]}; if (!isscalar(_ident)) {
new_class.Recipients = []; logprint(LOG_ALERT, "Transmitter.new: argument must be a scalar!")
new_class.Ident = _ident; }
new_class.Timestamp = nil;
new_class.MaxMilliseconds = 1;
__emesaryUniqueId += 1; __emesaryUniqueId += 1;
new_class.UniqueId = __emesaryUniqueId; var new_class = {
parents : [Transmitter],
Recipients : [],
Ident : _ident,
Timestamp : nil,
MaxMilliseconds : 1,
UniqueId: __emesaryUniqueId,
};
_registerTransmitter(_ident, new_class);
return new_class; return new_class;
}, },
OverrunDetection: func(max_ms=0){ OverrunDetection: func(max_ms=0){
if (max_ms){ if (isnum(max_ms) and max_ms) {
if (me.Timestamp == nil) if (me.Timestamp == nil)
me.Timestamp = maketimestamp(); me.Timestamp = maketimestamp();
me.MaxMilliseconds = max_ms; me.MaxMilliseconds = max_ms;
#print("Set overrun detection ",me.Ident, " to ", me.MaxMilliseconds); logprint(LOG_INFO, "Set overrun detection ",me.Ident, " to ", me.MaxMilliseconds);
} else { return 1;
# me.Timestamp = nil; } else {
me.MaxMilliseconds = 0; # me.Timestamp = nil;
#print("Disable overrun detection ",me.Ident); me.MaxMilliseconds = 0;
} logprint(LOG_INFO, "Disable overrun detection ",me.Ident);
} return 0;
, }
},
# Add a recipient to receive notifications from this transmitter # Add a recipient to receive notifications from this transmitter
Register: func (recipient) Register: func (recipient)
{ {
# not inheriting from Recipient is maybe strange but will not crash
if (!isa(recipient, Recipient))
{
logprint(LOG_INFO, "Transmitter.Register: argument is not a Recipient object");
}
#not having a Receive function is an error
if (!isfunc(recipient["Receive"]))
{
logprint(DEV_ALERT, "Transmitter.Register: Error, argument has no Receive method!");
return 0;
}
foreach (var r; me.Recipients)
{
if (r == recipient) {
logprint(DEV_ALERT, "Transmitter.Register: Recipient already registered!");
return 1;
}
}
append(me.Recipients, recipient); append(me.Recipients, recipient);
return 1;
}, },
DeleteAllRecipients: func DeleteAllRecipients: func
{ {
me.Recipients = []; me.Recipients = [];
}, },
# Stops a recipient from receiving notifications from this transmitter. # Stops a recipient from receiving notifications from this transmitter.
DeRegister: func(todelete_recipient) DeRegister: func(todelete_recipient)
{ {
@ -111,10 +156,12 @@ var Transmitter =
# - Fail > message not handled. A status of Abort from a recipient will result in our status # - Fail > message not handled. A status of Abort from a recipient will result in our status
# being fail as Abort means that the message was not and cannot be handled, and # being fail as Abort means that the message was not and cannot be handled, and
# allows for usages such as access controls. # allows for usages such as access controls.
# message: hash; Notification passed to the Receive() method of registered recipients
NotifyAll: func(message) NotifyAll: func(message)
{ {
if (message == nil){ if (!isa(message, Notification))
print("Emesary: bad notification nil"); {
logprint(DEV_ALERT, "Transmitter.NotifyAll: argument must be a Notification!");
return Transmitter.ReceiptStatus_NotProcessed; return Transmitter.ReceiptStatus_NotProcessed;
} }
me._return_status = Transmitter.ReceiptStatus_NotProcessed; me._return_status = Transmitter.ReceiptStatus_NotProcessed;
@ -134,9 +181,12 @@ var Transmitter =
foreach(var line; err) { foreach(var line; err) {
print(line); print(line);
} }
print("Recipient ",recipient.Ident, " has been removed from transmitter (", me.Ident, ") because of the above error"); logprint(LOG_ALERT, "Recipient ",recipient.Ident,
" has been removed from transmitter (", me.Ident,
") because of the above error");
me.DeRegister(recipient); me.DeRegister(recipient);
return Transmitter.ReceiptStatus_Abort;#need to break the foreach due to having modified what its iterating over. #need to break the foreach due to having modified what its iterating over.
return Transmitter.ReceiptStatus_Abort;
} }
if (me.Timestamp != nil) { if (me.Timestamp != nil) {
recipient.TimeTaken = me.Timestamp.elapsedUSec()/1000.0; recipient.TimeTaken = me.Timestamp.elapsedUSec()/1000.0;
@ -166,20 +216,26 @@ var Transmitter =
} }
elsif(me._rstat == Transmitter.ReceiptStatus_Abort) elsif(me._rstat == Transmitter.ReceiptStatus_Abort)
{ {
# this is a final results, e.g. no more recipients will be
# notified but the result is returned as NotifyAll result.
return Transmitter.ReceiptStatus_Abort; return Transmitter.ReceiptStatus_Abort;
} }
elsif(me._rstat == Transmitter.ReceiptStatus_Finished) elsif(me._rstat == Transmitter.ReceiptStatus_Finished)
{ {
# this is a final results, e.g. no more recipients will be
# notified but the result is returned as NotifyAll result.
return Transmitter.ReceiptStatus_OK; return Transmitter.ReceiptStatus_OK;
} }
} }
} }
if (me.MaxMilliseconds and me.TimeTaken > me.MaxMilliseconds ){ if (me.MaxMilliseconds and me.TimeTaken > me.MaxMilliseconds) {
printf("Overrun: %s ['%s'] %1.2fms max (%d)",me.Ident,message.NotificationType, me.TimeTaken,me.MaxMilliseconds); logprint(LOG_WARN, sprintf("Overrun: %s ['%s'] %1.2fms max (%d)",
# print("Overrun: ",me.Ident, "['",message.NotificationType,"']", " ", me.TimeTaken,"ms (max ",me.MaxMilliseconds," ms)"); me.Ident, message.NotificationType, me.TimeTaken, me.MaxMilliseconds));
foreach (var recipient; me.Recipients) { foreach (var recipient; me.Recipients) {
if (recipient.TimeTaken) if (recipient.TimeTaken) {
printf(" -- Recipient %25s %7.2f ms",recipient.Ident, recipient.TimeTaken); logprint(LOG_WARN, sprintf(" -- Recipient %25s %7.2f ms",
recipient.Ident, recipient.TimeTaken));
}
} }
} }
return me._return_status; return me._return_status;
@ -222,102 +278,158 @@ var QueuedTransmitter =
} }
}; };
#
# #---------------------------------------------------------------------------
# Base class for Notifications. By convention a Notification has a type and a value. # Notification - base class
# SubClasses can add extra properties or methods. # By convention a Notification has a type and a value. Derived classes can add
# Properties: # extra properties or methods.
# Ident : Generic message identity. Can be an ident, or for simple messages a value that needs transmitting. #
# NotificationType : Notification Type # NotificationType: Notification Type
# IsDistinct : non zero if this message supercedes previous messages of this type. # Ident: Can be an ident, or for simple messages a value that needs transmitting.
# Distinct messages are usually sent often and self contained # IsDistinct: non zero if this message supercedes previous messages of this type.
# (i.e. no relative state changes such as toggle value) # Distinct messages are usually sent often and self contained
# Messages that indicate an event (such as after a pilot action) # (i.e. no relative state changes such as toggle value)
# will usually be non-distinct. So an example would be gear/up down # Messages that indicate an event (such as after a pilot action)
# or ATC acknowledgements that all need to be transmitted # will usually be non-distinct. So an example would be gear/up down
# or ATC acknowledgements that all need to be transmitted
# The IsDistinct is important for any messages that are bridged over MP as # The IsDistinct is important for any messages that are bridged over MP as
# only the most recently sent distinct message will be transmitted over MP # only the most recently sent distinct message will be transmitted over MP.
# Example:
# position update, where only current position is relevant -> IsDistinct=1;
# 0 = queue all messages for MP bridging
# 1 = queue only latest message (replace any old message of same type+ident)
#
var TypeIdUnspecified = 1;
var NotificationAutoTypeId = 1; var NotificationAutoTypeId = 1;
var Notification = var Notification =
{ {
new: func(_type, _ident, _typeid=0) new: func(_type, _ident, _typeid=0)
{ {
var new_class = { parents: [Notification]}; if (!isscalar(_type)) {
new_class.Ident = _ident; logprint(DEV_ALERT, "Notification.new: _type must be a scalar!");
new_class.NotificationType = _type; return nil;
new_class.IsDistinct = 1;
new_class.FromIncomingBridge = 0;
new_class.Callsign = nil;
new_class.GetBridgeMessageNotificationTypeKey = func {
return me.NotificationType~"."~me.Ident;
};
if (_typeid == 0)
{
_typeid = NotificationAutoTypeId;
NotificationAutoTypeId = NotificationAutoTypeId + 1;
} }
new_class.TypeId = _typeid; if (!isscalar(_ident)) {
logprint(DEV_ALERT, "Notification.new: _ident is not scalar but ", typeof(_ident));
return nil;
}
if (_typeid == 0) {
NotificationAutoTypeId += 1;
# IDs >= 16 are reserved; see http://wiki.flightgear.org/Emesary_Notifications
if (NotificationAutoTypeId == 16) {
logprint(LOG_ALERT, "Notification: AutoTypeID limit exceeded: "~NotificationAutoTypeId);
return nil;
}
_typeid = NotificationAutoTypeId;
}
var new_class = {
parents: [Notification],
NotificationType: _type,
Ident: _ident,
IsDistinct: 1, #1: MP bridge only latest notification
FromIncomingBridge: 0,
Callsign: nil,
TypeId: _typeid, # used in MP bridged
};
return new_class; return new_class;
}, },
setType: func(_type) {
if (!isscalar(_type)) {
logprint(DEV_ALERT, "Notification.new: _type must be a scalar!");
return nil;
}
me.NotificationType = _type;
return me;
},
setIdent: func(_ident) {
if (!isscalar(_ident)) {
logprint(DEV_ALERT, "Notification.new: _ident is not scalar but ", typeof(_ident));
return nil;
}
me.Ident = _ident;
return me;
},
GetBridgeMessageNotificationTypeKey: func {
return me.NotificationType~"."~me.Ident;
},
}; };
# Inherit or implement class with the same signatures to receive messages. #---------------------------------------------------------------------------
# Recipient - base class for receiving notifications.
#
# You have to implement the Receive method
# The Receive method must return a sensible ReceiptStatus_* code
var Recipient = var Recipient =
{ {
new: func(_ident) new: func(_ident)
{ {
var new_class = { parents: [Recipient]};
if (_ident == nil or _ident == "") if (_ident == nil or _ident == "")
{ {
_ident = id(new_class); _ident = id(new_class);
print("Emesary Error: Ident required when creating a recipient, defaulting to ",_ident); logprint(LOG_WARN, "Emesary Error: Ident required when creating a recipient, defaulting to ", _ident);
} }
Recipient.construct(_ident, new_class);
},
construct: func(_ident, new_class)
{
new_class.Ident = _ident;
new_class.RecipientActive = 1;
__emesaryUniqueId += 1; __emesaryUniqueId += 1;
new_class.UniqueId = __emesaryUniqueId; var new_class = {
new_class.Receive = func(notification) parents: [Recipient],
{ Ident: _ident,
# warning if required function not RecipientActive: 1,
print("Emesary Error: Receive function not implemented in recipient ",me.Ident); UniqueId: __emesaryUniqueId,
return Transmitter.ReceiptStatus_NotProcessed;
}; };
return new_class; return new_class;
}, },
Receive: func(notification)
{
logprint(DEV_ALERT, "Emesary Error: Receive function not implemented in recipient ", me.Ident);
return Transmitter.ReceiptStatus_NotProcessed;
},
setReceive: func(f)
{
if (isfunc(f)) { me.Receive = f; }
else { logprint(DEV_ALERT, "Recipient.addReceive: argument must be a function!"); }
return me;
},
}; };
# #
# Instantiate a Global Transmitter, this is a convenience and a known starting point. Generally most classes will # Instantiate a Global Transmitter, this is a convenience and a known starting point.
# use this transmitters, however other transmitters can be created and merely use the global transmitter to discover each other # Generally most classes will use this transmitters, however other transmitters
# can be created and merely use the global transmitter to discover each other.
var GlobalTransmitter = Transmitter.new("GlobalTransmitter"); var GlobalTransmitter = Transmitter.new("GlobalTransmitter");
# #
# Base method of transferring all numeric based values. # Base method of transferring all numeric based values.
# Using the same techinque as base64 - except this is base248 because we can use a much wider range of characters. # Using the same techinque as base64 - except this is base248 because we can use a much wider range of characters.
# #
var BinaryAsciiTransfer = var BinaryAsciiTransfer =
{ {
alphabet : chr(1)~chr(2)~chr(3)~chr(4)~chr(5)~chr(6)~chr(7)~chr(8)~chr(9)~chr(10)~chr(11)~chr(12)~chr(13) #excluded chars 32 (<space>), 33 (!), 35 (#), 36($), 126 (~), 127 (<del>)
~chr(14)~chr(15)~chr(16)~chr(17)~chr(18)~chr(19)~chr(20)~chr(21)~chr(22)~chr(23)~chr(24)~chr(25) alphabet :
~chr(26)~chr(27)~chr(28)~chr(29)~chr(30)~chr(31)~chr(34) chr(1) ~chr(2) ~chr(3) ~chr(4) ~chr(5) ~chr(6) ~chr(7) ~chr(8) ~chr(9)
~"%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}" ~chr(10)~chr(11)~chr(12)~chr(13)~chr(14)~chr(15)~chr(16)~chr(17)~chr(18)~chr(19)
~chr(128)~chr(129)~chr(130)~chr(131)~chr(132)~chr(133)~chr(134)~chr(135)~chr(136)~chr(137)~chr(138) ~chr(20)~chr(21)~chr(22)~chr(23)~chr(24)~chr(25)~chr(26)~chr(27)~chr(28)~chr(29)
~chr(139)~chr(140)~chr(141)~chr(142)~chr(143)~chr(144)~chr(145)~chr(146)~chr(147)~chr(148)~chr(149) ~chr(30)~chr(31) ~chr(34)
~chr(150)~chr(151)~chr(152)~chr(153)~chr(154)~chr(155)~chr(156)~chr(157)~chr(158)~chr(159)~chr(160) ~"%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}"
~chr(161)~chr(162)~chr(163)~chr(164)~chr(165)~chr(166)~chr(167)~chr(168)~chr(169)~chr(170)~chr(171) ~chr(128)~chr(129)
~chr(172)~chr(173)~chr(174)~chr(175)~chr(176)~chr(177)~chr(178)~chr(179)~chr(180)~chr(181)~chr(182) ~chr(130)~chr(131)~chr(132)~chr(133)~chr(134)~chr(135)~chr(136)~chr(137)~chr(138)~chr(139)
~chr(183)~chr(184)~chr(185)~chr(186)~chr(187)~chr(188)~chr(189)~chr(190)~chr(191)~chr(192)~chr(193) ~chr(140)~chr(141)~chr(142)~chr(143)~chr(144)~chr(145)~chr(146)~chr(147)~chr(148)~chr(149)
~chr(194)~chr(195)~chr(196)~chr(197)~chr(198)~chr(199)~chr(200)~chr(201)~chr(202)~chr(203)~chr(204) ~chr(150)~chr(151)~chr(152)~chr(153)~chr(154)~chr(155)~chr(156)~chr(157)~chr(158)~chr(159)
~chr(205)~chr(206)~chr(207)~chr(208)~chr(209)~chr(210)~chr(211)~chr(212)~chr(213)~chr(214)~chr(215) ~chr(160)~chr(161)~chr(162)~chr(163)~chr(164)~chr(165)~chr(166)~chr(167)~chr(168)~chr(169)
~chr(216)~chr(217)~chr(218)~chr(219)~chr(220)~chr(221)~chr(222)~chr(223)~chr(224)~chr(225)~chr(226) ~chr(170)~chr(171)~chr(172)~chr(173)~chr(174)~chr(175)~chr(176)~chr(177)~chr(178)~chr(179)
~chr(227)~chr(228)~chr(229)~chr(230)~chr(231)~chr(232)~chr(233)~chr(234)~chr(235)~chr(236)~chr(237) ~chr(180)~chr(181)~chr(182)~chr(183)~chr(184)~chr(185)~chr(186)~chr(187)~chr(188)~chr(189)
~chr(238)~chr(239)~chr(240)~chr(241)~chr(242)~chr(243)~chr(244)~chr(245)~chr(246)~chr(247)~chr(248) ~chr(190)~chr(191)~chr(192)~chr(193)~chr(194)~chr(195)~chr(196)~chr(197)~chr(198)~chr(199)
~chr(249)~chr(250)~chr(251)~chr(252)~chr(253)~chr(254)~chr(255), ~chr(200)~chr(201)~chr(202)~chr(203)~chr(204)~chr(205)~chr(206)~chr(207)~chr(208)~chr(209)
~chr(210)~chr(211)~chr(212)~chr(213)~chr(214)~chr(215)~chr(216)~chr(217)~chr(218)~chr(219)
~chr(220)~chr(221)~chr(222)~chr(223)~chr(224)~chr(225)~chr(226)~chr(227)~chr(228)~chr(229)
~chr(230)~chr(231)~chr(232)~chr(233)~chr(234)~chr(235)~chr(236)~chr(237)~chr(238)~chr(239)
~chr(240)~chr(241)~chr(242)~chr(243)~chr(244)~chr(245)~chr(246)~chr(247)~chr(248)~chr(249)
~chr(250)~chr(251)~chr(252)~chr(253)~chr(254)~chr(255),
# base248: powers of 2 (i.e. po2(x) = f(248 ^ x); # base248: powers of 2 (i.e. po2(x) = f(248 ^ x);
# 0 based list so the first item is really[1]; i.e. 124 which is 248/2 as po2 is the magnitude excluding sign # 0 based list so the first item is really[1]; i.e. 124 which is 248/2 as po2 is the magnitude excluding sign
po2: [1, 124, 30752, 7626496, 1891371008, 469060009984, 116326882476032, 28849066854055936], po2: [1, 124, 30752, 7626496, 1891371008, 469060009984, 116326882476032, 28849066854055936],
@ -356,7 +468,7 @@ var BinaryAsciiTransfer =
decodeNumeric : func(str, length, factor, pos) decodeNumeric : func(str, length, factor, pos)
{ {
var irange = int(BinaryAsciiTransfer.po2[length]/factor); var irange = int(BinaryAsciiTransfer.po2[length]/factor);
var power = length - 1; var power = length-1;
BinaryAsciiTransfer.retval.value = 0; BinaryAsciiTransfer.retval.value = 0;
BinaryAsciiTransfer.retval.pos = pos; BinaryAsciiTransfer.retval.pos = pos;
@ -523,6 +635,61 @@ var TransferCoord =
return dv; return dv;
} }
}; };
# genericEmesaryGlobalTransmitterTransmit allowes to use the emesary.GlobalTransmitter via fgcommand
# which in turn allows using it in XML bindings, e.g.
# <binding>
# <command>emesary-transmit</command>
# <type>cockpit-switch</type>
# <ident>eicas-page-select</ident>
# <page>hydraulic</page>
# </binding>
#
var genericEmesaryGlobalTransmitterTransmit = func(node)
{
var transmitter = emesary.GlobalTransmitter;
var t = node.getNode("transmitter",1).getValue();
if (t != nil) {
transmitter = emesary.getTransmitter(t);
if (transmitter == nil) {
logprint(LOG_WARN, "Invalid transmitter "~t);
return;
}
}
var type = node.getNode("type").getValue();
if (type == nil) {
logprint(LOG_WARN, "emesary-transmit requires a type");
return;
}
var ident = node.getNode("ident").getValue();
if (ident == nil) {
logprint(LOG_WARN, "emesary-transmit requires an ident");
return;
}
var typeid = node.getNode("typeid",1).getValue() or 0;
if (typeid == 0) {
typeid = TypeIdUnspecified;
logprint(LOG_WARN, "emesary-transmit using generic typeid ", typeid);
}
var message = emesary.Notification.new(type, ident, typeid);
node.removeChild("type");
node.removeChild("id");
node.removeChild("typeid");
# add remaining nodes to the message hash
var children = node.getValues();
if (children != nil) {
foreach (var key; keys(children)) {
message[key] = children[key];
}
}
transmitter.NotifyAll(message);
};
removecommand("emesary-transmit"); #in case of reload
addcommand("emesary-transmit", genericEmesaryGlobalTransmitterTransmit);
#setprop("/sim/startup/terminal-ansi-colors",0); #setprop("/sim/startup/terminal-ansi-colors",0);
#for(i=-1;i<=1;i+=0.1) #for(i=-1;i<=1;i+=0.1)
#print ("i ",i, " --> ", (TransferNorm.decode(TransferNorm.encode(i,2), 2,0)).value); #print ("i ",i, " --> ", (TransferNorm.decode(TransferNorm.encode(i,2), 2,0)).value);

View file

@ -41,10 +41,9 @@ var assert = func (condition, message=nil) {
# (class) object. Example: isa(someObject, props.Node) # (class) object. Example: isa(someObject, props.Node)
# #
var isa = func(obj, class) { var isa = func(obj, class) {
if(ishash(obj) and obj["parents"] != nil) { if (ishash(obj) and obj["parents"] != nil) {
foreach(var c; obj.parents) { foreach(var c; obj.parents) {
if(c == class or isa(c, class)) if (c == class or isa(c, class)) return 1;
return 1;
} }
} }
return 0; return 0;
@ -58,9 +57,8 @@ var isa = func(obj, class) {
# tree. # tree.
# #
var fgcommand = func(cmd, node=nil) { var fgcommand = func(cmd, node=nil) {
if(isa(node, props.Node)) node = node._g; if (isa(node, props.Node)) node = node._g;
elsif(ishash(node)) elsif (ishash(node)) node = props.Node.new(node)._g;
node = props.Node.new(node)._g;
_fgcommand(cmd, node); _fgcommand(cmd, node);
} }
@ -97,8 +95,9 @@ var abs = func(v) { return v < 0 ? -v : v }
# 0 to wrap the interpolated value properly. # 0 to wrap the interpolated value properly.
# #
var interpolate = func(node, val...) { var interpolate = func(node, val...) {
if (isa(node, props.Node)) node = node._g; if (isa(node, props.Node))
elsif (!isscalar(node) and !isghost(node)) node = node._g;
elsif (!isscalar(node) and !isghost(node))
die("bad argument to interpolate()"); die("bad argument to interpolate()");
_interpolate(node, val); _interpolate(node, val);
} }
@ -189,3 +188,55 @@ settimer(func {
if(size(file) > 4 and substr(file, -4) == ".nas") if(size(file) > 4 and substr(file, -4) == ".nas")
io.load_nasal(path ~ "/" ~ file, substr(file, 0, size(file) - 4)); io.load_nasal(path ~ "/" ~ file, substr(file, 0, size(file) - 4));
}, 0); }, 0);
# simple hash class for developers, allows to add callback on write
Hash = {
class_name: "Hash",
new: func(name) {
var obj = {
parents: [me],
name: name,
_h: {},
_callback: func,
};
return obj;
},
set: func (key, value) {
me._h[key] = value;
me._callback(key, value);
return me;
},
get: func (key) {
return me._h[key];
},
getName: func (key) {
return me.name;
},
getKeys: func () {
return keys(me._h);
},
keys2props: func (p) {
if (!isa(p, props.Node)) {
p = props.getNode(p,1);
}
p = p.getNode(me.name,1);
foreach (var key; keys(me._h)) {
p.getNode(key,1);
}
return;
},
# callback for set()
addCallback: func (f) {
if (isfunc(f)) {
me._callback = f;
}
return me;
},
};

View file

@ -4,7 +4,7 @@
# #
# File Type : Implementation File # File Type : Implementation File
# #
# Description : Messages that are applicable across all models and do not specifically relate to a single sysmte # Description : Messages that are applicable across all models and do not specifically relate to a single system
# : - mostly needed when using the mutiplayer bridge # : - mostly needed when using the mutiplayer bridge
# #
# Author : Richard Harrison (richard@zaretto.com) # Author : Richard Harrison (richard@zaretto.com)
@ -27,6 +27,7 @@ var AircraftControlNotification_Id = 17;
var GeoEventNotification_Id = 18; var GeoEventNotification_Id = 18;
# event ID 19 reserved for armaments and stores (model defined). # event ID 19 reserved for armaments and stores (model defined).
var PFDEventNotification_Id = 20; var PFDEventNotification_Id = 20;
var ArmamentInFlightNotification = 21;
# #
# PropertySyncNotificationBase is a wrapper class for allow properties to be synchronized between # PropertySyncNotificationBase is a wrapper class for allow properties to be synchronized between

View file

@ -1383,6 +1383,9 @@ Started September 2000 by David Megginson, david@megginson.com
<console> <console>
<enabled type="bool">true</enabled> <enabled type="bool">true</enabled>
</console> </console>
<debug>
<enabled type="bool">false</enabled>
</debug>
<input_helpers> <input_helpers>
<enabled type="bool">true</enabled> <enabled type="bool">true</enabled>
</input_helpers> </input_helpers>