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:
parent
8d785cacbc
commit
a13f9b3bb0
5 changed files with 373 additions and 101 deletions
50
Nasal/debug/emesary.deb.nas
Normal file
50
Nasal/debug/emesary.deb.nas
Normal 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);
|
|
@ -22,56 +22,101 @@
|
|||
#
|
||||
# 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.
|
||||
|
||||
# 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.
|
||||
var Transmitter =
|
||||
{
|
||||
ReceiptStatus_OK : 0, # Processing completed successfully
|
||||
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_Finished : 3, # Definitive completion - do not send message to any further recipieints
|
||||
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 recipients
|
||||
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_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
|
||||
# _ident: string; name of the transmitter, used in debug messages
|
||||
new: func(_ident)
|
||||
{
|
||||
var new_class = { parents: [Transmitter]};
|
||||
new_class.Recipients = [];
|
||||
new_class.Ident = _ident;
|
||||
new_class.Timestamp = nil;
|
||||
new_class.MaxMilliseconds = 1;
|
||||
if (!isscalar(_ident)) {
|
||||
logprint(LOG_ALERT, "Transmitter.new: argument must be a scalar!")
|
||||
}
|
||||
__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;
|
||||
},
|
||||
|
||||
OverrunDetection: func(max_ms=0){
|
||||
if (max_ms){
|
||||
if (me.Timestamp == nil)
|
||||
if (isnum(max_ms) and max_ms) {
|
||||
if (me.Timestamp == nil)
|
||||
me.Timestamp = maketimestamp();
|
||||
me.MaxMilliseconds = max_ms;
|
||||
#print("Set overrun detection ",me.Ident, " to ", me.MaxMilliseconds);
|
||||
} else {
|
||||
# me.Timestamp = nil;
|
||||
me.MaxMilliseconds = 0;
|
||||
#print("Disable overrun detection ",me.Ident);
|
||||
}
|
||||
}
|
||||
,
|
||||
me.MaxMilliseconds = max_ms;
|
||||
logprint(LOG_INFO, "Set overrun detection ",me.Ident, " to ", me.MaxMilliseconds);
|
||||
return 1;
|
||||
} else {
|
||||
# me.Timestamp = nil;
|
||||
me.MaxMilliseconds = 0;
|
||||
logprint(LOG_INFO, "Disable overrun detection ",me.Ident);
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
# Add a recipient to receive notifications from this transmitter
|
||||
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);
|
||||
return 1;
|
||||
},
|
||||
|
||||
DeleteAllRecipients: func
|
||||
{
|
||||
me.Recipients = [];
|
||||
},
|
||||
|
||||
# Stops a recipient from receiving notifications from this transmitter.
|
||||
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
|
||||
# being fail as Abort means that the message was not and cannot be handled, and
|
||||
# allows for usages such as access controls.
|
||||
# message: hash; Notification passed to the Receive() method of registered recipients
|
||||
NotifyAll: func(message)
|
||||
{
|
||||
if (message == nil){
|
||||
print("Emesary: bad notification nil");
|
||||
if (!isa(message, Notification))
|
||||
{
|
||||
logprint(DEV_ALERT, "Transmitter.NotifyAll: argument must be a Notification!");
|
||||
return Transmitter.ReceiptStatus_NotProcessed;
|
||||
}
|
||||
me._return_status = Transmitter.ReceiptStatus_NotProcessed;
|
||||
|
@ -134,9 +181,12 @@ var Transmitter =
|
|||
foreach(var line; err) {
|
||||
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);
|
||||
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) {
|
||||
recipient.TimeTaken = me.Timestamp.elapsedUSec()/1000.0;
|
||||
|
@ -166,20 +216,26 @@ var Transmitter =
|
|||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (me.MaxMilliseconds and me.TimeTaken > me.MaxMilliseconds ){
|
||||
printf("Overrun: %s ['%s'] %1.2fms max (%d)",me.Ident,message.NotificationType, me.TimeTaken,me.MaxMilliseconds);
|
||||
# print("Overrun: ",me.Ident, "['",message.NotificationType,"']", " ", me.TimeTaken,"ms (max ",me.MaxMilliseconds," ms)");
|
||||
if (me.MaxMilliseconds and me.TimeTaken > me.MaxMilliseconds) {
|
||||
logprint(LOG_WARN, sprintf("Overrun: %s ['%s'] %1.2fms max (%d)",
|
||||
me.Ident, message.NotificationType, me.TimeTaken, me.MaxMilliseconds));
|
||||
foreach (var recipient; me.Recipients) {
|
||||
if (recipient.TimeTaken)
|
||||
printf(" -- Recipient %25s %7.2f ms",recipient.Ident, recipient.TimeTaken);
|
||||
if (recipient.TimeTaken) {
|
||||
logprint(LOG_WARN, sprintf(" -- Recipient %25s %7.2f ms",
|
||||
recipient.Ident, recipient.TimeTaken));
|
||||
}
|
||||
}
|
||||
}
|
||||
return me._return_status;
|
||||
|
@ -222,102 +278,158 @@ var QueuedTransmitter =
|
|||
}
|
||||
};
|
||||
|
||||
#
|
||||
#
|
||||
# Base class for Notifications. By convention a Notification has a type and a value.
|
||||
# SubClasses can add extra properties or methods.
|
||||
# Properties:
|
||||
# Ident : Generic message identity. Can be an ident, or for simple messages a value that needs transmitting.
|
||||
# NotificationType : Notification Type
|
||||
# IsDistinct : non zero if this message supercedes previous messages of this type.
|
||||
# Distinct messages are usually sent often and self contained
|
||||
# (i.e. no relative state changes such as toggle value)
|
||||
# Messages that indicate an event (such as after a pilot action)
|
||||
# will usually be non-distinct. So an example would be gear/up down
|
||||
# or ATC acknowledgements that all need to be transmitted
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Notification - base class
|
||||
# By convention a Notification has a type and a value. Derived classes can add
|
||||
# extra properties or methods.
|
||||
#
|
||||
# NotificationType: Notification Type
|
||||
# Ident: Can be an ident, or for simple messages a value that needs transmitting.
|
||||
# IsDistinct: non zero if this message supercedes previous messages of this type.
|
||||
# Distinct messages are usually sent often and self contained
|
||||
# (i.e. no relative state changes such as toggle value)
|
||||
# Messages that indicate an event (such as after a pilot action)
|
||||
# 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
|
||||
# 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 Notification =
|
||||
{
|
||||
new: func(_type, _ident, _typeid=0)
|
||||
{
|
||||
var new_class = { parents: [Notification]};
|
||||
new_class.Ident = _ident;
|
||||
new_class.NotificationType = _type;
|
||||
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;
|
||||
if (!isscalar(_type)) {
|
||||
logprint(DEV_ALERT, "Notification.new: _type must be a scalar!");
|
||||
return nil;
|
||||
}
|
||||
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;
|
||||
},
|
||||
|
||||
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 =
|
||||
{
|
||||
new: func(_ident)
|
||||
{
|
||||
var new_class = { parents: [Recipient]};
|
||||
if (_ident == nil or _ident == "")
|
||||
{
|
||||
_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;
|
||||
new_class.UniqueId = __emesaryUniqueId;
|
||||
new_class.Receive = func(notification)
|
||||
{
|
||||
# warning if required function not
|
||||
print("Emesary Error: Receive function not implemented in recipient ",me.Ident);
|
||||
return Transmitter.ReceiptStatus_NotProcessed;
|
||||
var new_class = {
|
||||
parents: [Recipient],
|
||||
Ident: _ident,
|
||||
RecipientActive: 1,
|
||||
UniqueId: __emesaryUniqueId,
|
||||
};
|
||||
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
|
||||
# use this transmitters, however other transmitters can be created and merely use the global transmitter to discover each other
|
||||
# Instantiate a Global Transmitter, this is a convenience and a known starting point.
|
||||
# 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");
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
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)
|
||||
~chr(14)~chr(15)~chr(16)~chr(17)~chr(18)~chr(19)~chr(20)~chr(21)~chr(22)~chr(23)~chr(24)~chr(25)
|
||||
~chr(26)~chr(27)~chr(28)~chr(29)~chr(30)~chr(31)~chr(34)
|
||||
~"%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}"
|
||||
~chr(128)~chr(129)~chr(130)~chr(131)~chr(132)~chr(133)~chr(134)~chr(135)~chr(136)~chr(137)~chr(138)
|
||||
~chr(139)~chr(140)~chr(141)~chr(142)~chr(143)~chr(144)~chr(145)~chr(146)~chr(147)~chr(148)~chr(149)
|
||||
~chr(150)~chr(151)~chr(152)~chr(153)~chr(154)~chr(155)~chr(156)~chr(157)~chr(158)~chr(159)~chr(160)
|
||||
~chr(161)~chr(162)~chr(163)~chr(164)~chr(165)~chr(166)~chr(167)~chr(168)~chr(169)~chr(170)~chr(171)
|
||||
~chr(172)~chr(173)~chr(174)~chr(175)~chr(176)~chr(177)~chr(178)~chr(179)~chr(180)~chr(181)~chr(182)
|
||||
~chr(183)~chr(184)~chr(185)~chr(186)~chr(187)~chr(188)~chr(189)~chr(190)~chr(191)~chr(192)~chr(193)
|
||||
~chr(194)~chr(195)~chr(196)~chr(197)~chr(198)~chr(199)~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),
|
||||
#excluded chars 32 (<space>), 33 (!), 35 (#), 36($), 126 (~), 127 (<del>)
|
||||
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)~chr(14)~chr(15)~chr(16)~chr(17)~chr(18)~chr(19)
|
||||
~chr(20)~chr(21)~chr(22)~chr(23)~chr(24)~chr(25)~chr(26)~chr(27)~chr(28)~chr(29)
|
||||
~chr(30)~chr(31) ~chr(34)
|
||||
~"%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}"
|
||||
~chr(128)~chr(129)
|
||||
~chr(130)~chr(131)~chr(132)~chr(133)~chr(134)~chr(135)~chr(136)~chr(137)~chr(138)~chr(139)
|
||||
~chr(140)~chr(141)~chr(142)~chr(143)~chr(144)~chr(145)~chr(146)~chr(147)~chr(148)~chr(149)
|
||||
~chr(150)~chr(151)~chr(152)~chr(153)~chr(154)~chr(155)~chr(156)~chr(157)~chr(158)~chr(159)
|
||||
~chr(160)~chr(161)~chr(162)~chr(163)~chr(164)~chr(165)~chr(166)~chr(167)~chr(168)~chr(169)
|
||||
~chr(170)~chr(171)~chr(172)~chr(173)~chr(174)~chr(175)~chr(176)~chr(177)~chr(178)~chr(179)
|
||||
~chr(180)~chr(181)~chr(182)~chr(183)~chr(184)~chr(185)~chr(186)~chr(187)~chr(188)~chr(189)
|
||||
~chr(190)~chr(191)~chr(192)~chr(193)~chr(194)~chr(195)~chr(196)~chr(197)~chr(198)~chr(199)
|
||||
~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);
|
||||
# 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],
|
||||
|
@ -356,7 +468,7 @@ var BinaryAsciiTransfer =
|
|||
decodeNumeric : func(str, length, factor, pos)
|
||||
{
|
||||
var irange = int(BinaryAsciiTransfer.po2[length]/factor);
|
||||
var power = length - 1;
|
||||
var power = length-1;
|
||||
BinaryAsciiTransfer.retval.value = 0;
|
||||
BinaryAsciiTransfer.retval.pos = pos;
|
||||
|
||||
|
@ -523,6 +635,61 @@ var TransferCoord =
|
|||
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);
|
||||
#for(i=-1;i<=1;i+=0.1)
|
||||
#print ("i ",i, " --> ", (TransferNorm.decode(TransferNorm.encode(i,2), 2,0)).value);
|
||||
|
|
|
@ -41,10 +41,9 @@ var assert = func (condition, message=nil) {
|
|||
# (class) object. Example: isa(someObject, props.Node)
|
||||
#
|
||||
var isa = func(obj, class) {
|
||||
if(ishash(obj) and obj["parents"] != nil) {
|
||||
if (ishash(obj) and obj["parents"] != nil) {
|
||||
foreach(var c; obj.parents) {
|
||||
if(c == class or isa(c, class))
|
||||
return 1;
|
||||
if (c == class or isa(c, class)) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -58,9 +57,8 @@ var isa = func(obj, class) {
|
|||
# tree.
|
||||
#
|
||||
var fgcommand = func(cmd, node=nil) {
|
||||
if(isa(node, props.Node)) node = node._g;
|
||||
elsif(ishash(node))
|
||||
node = props.Node.new(node)._g;
|
||||
if (isa(node, props.Node)) node = node._g;
|
||||
elsif (ishash(node)) node = props.Node.new(node)._g;
|
||||
_fgcommand(cmd, node);
|
||||
}
|
||||
|
||||
|
@ -97,8 +95,9 @@ var abs = func(v) { return v < 0 ? -v : v }
|
|||
# 0 to wrap the interpolated value properly.
|
||||
#
|
||||
var interpolate = func(node, val...) {
|
||||
if (isa(node, props.Node)) node = node._g;
|
||||
elsif (!isscalar(node) and !isghost(node))
|
||||
if (isa(node, props.Node))
|
||||
node = node._g;
|
||||
elsif (!isscalar(node) and !isghost(node))
|
||||
die("bad argument to interpolate()");
|
||||
_interpolate(node, val);
|
||||
}
|
||||
|
@ -189,3 +188,55 @@ settimer(func {
|
|||
if(size(file) > 4 and substr(file, -4) == ".nas")
|
||||
io.load_nasal(path ~ "/" ~ file, substr(file, 0, size(file) - 4));
|
||||
}, 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;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# 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
|
||||
#
|
||||
# Author : Richard Harrison (richard@zaretto.com)
|
||||
|
@ -27,6 +27,7 @@ var AircraftControlNotification_Id = 17;
|
|||
var GeoEventNotification_Id = 18;
|
||||
# event ID 19 reserved for armaments and stores (model defined).
|
||||
var PFDEventNotification_Id = 20;
|
||||
var ArmamentInFlightNotification = 21;
|
||||
|
||||
#
|
||||
# PropertySyncNotificationBase is a wrapper class for allow properties to be synchronized between
|
||||
|
|
|
@ -1383,6 +1383,9 @@ Started September 2000 by David Megginson, david@megginson.com
|
|||
<console>
|
||||
<enabled type="bool">true</enabled>
|
||||
</console>
|
||||
<debug>
|
||||
<enabled type="bool">false</enabled>
|
||||
</debug>
|
||||
<input_helpers>
|
||||
<enabled type="bool">true</enabled>
|
||||
</input_helpers>
|
||||
|
|
Loading…
Add table
Reference in a new issue