6 Copyright (C) 2009-2014 8 RT-Synthesis Research Group 9 Intelligent Systems Research Institute, 10 National Institute of Advanced Industrial Science and Technology (AIST), 13 Licensed under the Eclipse Public License -v 1.0 (EPL) 14 http://www.opensource.org/licenses/eclipse-1.0.txt 16 Object representing a component node in the tree. 32 from rtctree.utils import build_attr_string, nvlist_to_dict, dict_to_nvlist
39 '''Node representing a component on a name server. 41 Component nodes can occur below name server and directory nodes. They 42 cannot contain any children. 44 Component nodes store all the properties of a component, as well as 45 references to the actual objects and object types used in the component. 47 This node can be made dynamic by setting the 'dynamic' property to True. 48 The following callbacks are available on this node type when it is dynamic: 50 - rtc_status(ec_handle, status) 51 The component's state has changed in the specified execution context. The 52 new status is one of Component.INACTIVE, Component.ACTIVE, 53 Component.ERROR, Component.UNKNOWN and Component.CREATED. 54 - component_profile(items) 55 One or more members of the component's profiles have been updated. The 56 updated items are listed in the "items" argument. 57 - ec_event(ec_handle, event) 58 A change in one of the attached execution contexts has occurred. The 59 event is one of Component.EC_ATTACHED, Component.EC_DETACHED, 60 Component.EC_RATE_CHANGED, Component.EC_STARTUP, and 61 Component.EC_SHUTDOWN. 62 - port_event(port_name, event) 63 A change on the specified port has occurred. The event is one of 64 Component.PORT_ADD, Component.PORT_REMOVE, Component.PORT_CONNECT and 65 Component.PORT_DISCONNECT. 66 - config_event(config_set_name, event) 67 A change in the component's configuration sets has occurred. The event is 68 one of Component.CFG_UPDATE_SET, Component.CFG_UPDATE_PARAM, 69 Component.CFG_UPDATE_PARAM_IN_ACTIVE, Component.CFG_ADD_SET, 70 Component.CFG_REMOVE_SET and Component.CFG_ACTIVATE_SET. 72 A heartbeat was received from the component. The time the beat was 76 def __init__(self, name=None, parent=None, obj=None, *args, **kwargs):
79 @param name Name of this component (i.e. its entry in the path). 80 @param parent The parent node of this node, if any. 81 @param obj The CORBA LightweightRTObject object to wrap. 89 super(Component, self).
__init__(name=name, parent=parent,
91 self.
_set_events([
'rtc_status',
'component_profile',
'ec_event',
92 'port_event',
'config_event',
'heartbeat'])
97 '''Reparse the component's information. 99 This will cause a delayed reparse of most information. This means that 100 a piece of information, such as the list of ports, will be cleared and 101 remain empty until it is next requested, at which point a fresh list 102 will be retrieved from the component. 104 If you only want to reparse a specific piece of information, use one of 105 the reparse_X() methods. 112 '''Delayed reparse configuration sets.''' 116 '''Delayed reparse all execution contexts.''' 121 '''Delayed reparse only owned execution contexts.''' 125 '''Delayed reparse only participating execution contexts.''' 129 '''Delayed reparse ports.''' 133 '''Delayed reparse the component's profile.''' 141 '''The category in which the component belongs.''' 147 '''The component's description.''' 153 '''Instance name of the component.''' 159 '''The name of the component's parent object (typically another 160 component), if it has one. 168 '''The component's extra properties dictionary.''' 174 '''Type name of the component.''' 180 '''The component's vendor.''' 186 '''The component's version.''' 194 '''Add other RT Components to this composite component as members. 196 This component must be a composite component. 205 org.add_members([x.object
for x
in rtcs])
210 '''Remove other RT Components from this composite component. 212 rtcs is a list of components to remove. Each element must be either an 213 rtctree.Component object or a string containing a component's instance 214 name. rtctree.Component objects are more reliable. 216 This component must be a composite component. 222 members = org.get_members()
227 rtc_name = rtc.instance_name
232 org.remove_member(rtc_name)
238 '''The parent component in the composition. 240 None if this component is not a member of a composition. 247 '''Is the component a composite component.''' 248 return self._obj.get_owned_organizations() != []
252 '''Is the component a member of a composite component.''' 253 return self._obj.get_organizations() != []
256 '''Is the given component a member of this composition? 258 rtc may be a Component object or a string containing a component's 259 instance name. Component objects are more reliable. 261 Returns False if the given component is not a member of this 264 Raises NotCompositeError if this component is not a composition. 272 if m.get_component_profile().instance_name == rtc:
276 if m._is_equivalent(rtc.object):
282 '''Member components if this component is composite.''' 288 self.
_members[o.org_id] = o.obj.get_members()
293 '''The organisations of this composition.''' 295 def __init__(self, sdo_id, org_id, members, obj):
303 for org
in self._obj.get_owned_organizations():
304 owner = org.get_owner()
306 sdo_id = owner._narrow(SDOPackage.SDO).get_sdo_id()
309 org_id = org.get_organization_id()
310 members = [m.get_sdo_id()
for m
in org.get_members()]
311 self._orgs.append(Org(sdo_id, org_id, members, org))
316 '''The organisation IDs of this composition.''' 317 return [sdo.get_organization_id()
for sdo
in \
318 self._obj.get_owned_organizations()]
322 '''The organisation IDs of the compositions this RTC belongs to.''' 323 return [sdo.get_organization_id()
for sdo
in \
324 self._obj.get_organizations()
if sdo]
328 '''The SDO IDs of the compositions this RTC belongs to.''' 329 return [sdo.get_owner()._narrow(SDOPackage.SDO).get_sdo_id() \
330 for sdo
in self._obj.get_organizations()
if sdo]
334 '''The organisations this RTC belongs to.''' 342 for sdo
in self._obj.get_organizations():
345 owner = sdo.get_owner()
347 sdo_id = owner._narrow(SDOPackage.SDO).get_sdo_id()
350 org_id = sdo.get_organization_id()
351 self._parent_orgs.append(ParentOrg(sdo_id, org_id))
358 '''Stop the component's execution contexts and finalise it. 360 This will have flow-on effects to any other components using this 361 component's execution contexts and any child components. 363 @return The result of attempting to exit. 367 return self._obj.exit()
370 '''Activate this component in an execution context. 372 @param ec_index The index of the execution context to activate in. 373 This index is into the total array of contexts, that 374 is both owned and participating contexts. If the value 375 of ec_index is greater than the length of 376 @ref owned_ecs, that length is subtracted from 377 ec_index and the result used as an index into 378 @ref participating_ecs. 389 ec.activate_component(self.
_obj)
392 '''Deactivate this component in an execution context. 394 @param ec_index The index of the execution context to deactivate in. 395 This index is into the total array of contexts, that 396 is both owned and participating contexts. If the value 397 of ec_index is greater than the length of 398 @ref owned_ecs, that length is subtracted from 399 ec_index and the result used as an index into 400 @ref participating_ecs. 411 ec.deactivate_component(self.
_obj)
414 '''Make a component exit. 416 This function will make the component exit, shutting down its CORBA 417 object in the process. It will not remove the node from the tree; a 418 reparse is necessary to do that. 424 '''Get a reference to the execution context with the given handle. 426 @param ec_handle The handle of the execution context to look for. 428 @return A reference to the ExecutionContext object corresponding to 430 @raises NoECWithHandleError 435 if ec.handle == ec_handle:
438 if ec.handle == ec_handle:
440 raise NoECWithHandleError
444 '''Get the index of the execution context with the given handle. 446 @param ec_handle The handle of the execution context to look for. 448 @return The index into the owned + participated arrays, suitable for 449 use in methods such as @ref activate_in_ec, or -1 if the EC was not 451 @raises NoECWithHandleError 456 if ec.handle == ec_handle:
459 if ec.handle == ec_handle:
461 raise NoECWithHandleError
464 '''Get the state of this component as an optionally-coloured string. 466 @param add_colour If True, ANSI colour codes will be added to the 468 @return A string describing the state of this component. 473 result =
'Inactive', [
'bold',
'blue']
475 result =
'Active', [
'bold',
'green']
477 result =
'Error', [
'bold',
'white',
'bgred']
479 result =
'Unknown', [
'bold',
'red']
481 result =
'Created', [
'reset']
489 '''Get the state of the component in an execution context as a string. 491 @param ec_index The index of the execution context to check the state 492 in. This index is into the total array of contexts, 493 that is both owned and participating contexts. If the 494 value of ec_index is greater than the length of @ref 495 owned_ecs, that length is subtracted from ec_index and 496 the result used as an index into @ref 509 result =
'Inactive', [
'bold',
'blue']
510 elif state == self.
ACTIVE:
511 result =
'Active', [
'bold',
'green']
512 elif state == self.
ERROR:
513 result =
'Error', [
'bold',
'white',
'bgred']
515 result =
'Unknown', [
'bold',
'red']
517 result =
'Created', [
'reset']
521 supported=add_colour)
526 '''Reset this component in an execution context. 528 @param ec_index The index of the execution context to reset in. This 529 index is into the total array of contexts, that is both 530 owned and participating contexts. If the value of 531 ec_index is greater than the length of @ref owned_ecs, 532 that length is subtracted from ec_index and the result 533 used as an index into @ref participating_ecs. 544 ec.reset_component(self.
_obj)
547 '''Get the state of the component in an execution context. 549 @param ec_index The index of the execution context to check the state 550 in. This index is into the total array of contexts, 551 that is both owned and participating contexts. If the 552 value of ec_index is greater than the length of @ref 553 owned_ecs, that length is subtracted from ec_index and 554 the result used as an index into @ref 568 '''Get the up-to-date state of the component in an execution context. 570 This function will update the state, rather than using the cached 571 value. This may take time, if the component is executing on a remote 574 @param ec_index The index of the execution context to check the state 575 in. This index is into the total array of contexts, 576 that is both owned and participating contexts. If the 577 value of ec_index is greater than the length of @ref 578 owned_ecs, that length is subtracted from ec_index and 579 the result used as an index into @ref 597 '''Is this component alive?''' 599 if self.exec_contexts:
600 for ec
in self.exec_contexts:
601 if self._obj.is_alive(ec):
607 '''The state of each execution context this component owns.''' 621 '''A list of the execution contexts owned by this component.''' 625 self._obj.get_context_handle(ec)) \
626 for ec
in self._obj.get_owned_contexts()]
631 '''The state of each execution context this component is participating 648 '''A list of the execution contexts this component is participating in. 654 self._obj.get_context_handle(ec)) \
655 for ec
in self._obj.get_participating_contexts()]
660 '''The state of this component as a string without colour.''' 665 '''The merged state of all the execution context states, which can be 666 used as the overall state of this component. 668 The order of precedence is: 669 Error > Active > Inactive > Created > Unknown 672 def merge_state(current, new):
673 if new == self.
ERROR:
694 merged_state = merge_state(merged_state, ec_state)
697 merged_state = merge_state(merged_state, ec_state)
702 '''The state of this component as a colourised string.''' 709 '''Disconnect all connections to all ports of this component.''' 715 '''Get a port of this component by name.''' 718 if p.name == port_name:
723 '''Get a port of this component by reference to a CORBA PortService 729 if p.object._is_equivalent(port_ref):
734 '''Check if this component has a port by the given name.''' 741 '''Check if this component has a port by the given reference to a CORBA 752 '''The list of all input ports belonging to this component that are 753 connected to one or more other ports. 756 return [p
for p
in self.
ports \
757 if p.__class__.__name__ ==
'DataInPort' and p.is_connected]
761 '''The list of all output ports belonging to this component that are 762 connected to one or more other ports. 765 return [p
for p
in self.
ports \
766 if p.__class__.__name__ ==
'DataOutPort' \
771 '''The list of all ports belonging to this component that are connected 772 to one or more other ports. 775 return [p
for p
in self.
ports if p.is_connected]
779 '''The list of all service ports belonging to this component that are 780 connected to one or more other ports. 783 return [p
for p
in self.
ports \
784 if p.__class__.__name__ ==
'CorbaPort' and p.is_connected]
788 '''The list of all input ports belonging to this component.''' 789 return [p
for p
in self.
ports if p.__class__.__name__ ==
'DataInPort']
793 '''The list of all output ports belonging to this component.''' 794 return [p
for p
in self.
ports if p.__class__.__name__ ==
'DataOutPort']
798 '''The list of all ports belonging to this component.''' 802 for port
in self._obj.get_ports()]
807 '''The list of all service ports belonging to this component.''' 808 return [p
for p
in self.
ports if p.__class__.__name__ ==
'CorbaPort']
815 '''The time of the last heartbeat. 817 Updated only when the node is dynamic. 824 '''Is this node a component?''' 829 '''Returns the list of logger IDs attached to this component.''' 830 return self._loggers.keys()
834 '''The LightweightRTObject this object wraps.''' 839 '''Add a callback to receive log events from this component. 841 @param cb The callback function to receive log events. It must have the 842 signature cb(name, time, source, level, message), where name is the 843 name of the component the log record came from, time is a 844 floating-point time stamp, source is the name of the logger that 845 provided the log record, level is the log level of the record and 846 message is a text string. 847 @param level The maximum level of log records to receive. 848 @param filters Filter the objects from which to receive log messages. 849 @return An ID for this logger. Use this ID in future operations such as 850 removing this logger. 851 @raises AddLoggerError 856 uuid_val = uuid.uuid4()
857 intf_type = obs._this()._NP_RepositoryId
858 props = {
'logger.log_level': level,
859 'logger.filter': filters}
861 sprof = SDOPackage.ServiceProfile(id=uuid_val.get_bytes(),
862 interface_type=intf_type, service=obs._this(),
864 conf = self.object.get_configuration()
865 res = conf.add_service_profile(sprof)
874 @param cb_id The ID of the logger to remove. 875 @raises NoLoggerError 880 conf = self.object.get_configuration()
881 res = conf.remove_service_profile(cb_id.get_bytes())
888 '''Activate a configuration set by name. 890 @raises NoSuchConfSetError 896 self._conf.activate_configuration_set(set_name)
899 '''Set a configuration set parameter value. 901 @param set_name The name of the configuration set the destination 903 @param param The name of the parameter to set. 904 @param value The new value for the parameter. 905 @raises NoSuchConfSetError, NoSuchConfParamError 911 if not self.
conf_sets[set_name].has_param(param):
913 self.
conf_sets[set_name].set_param(param, value)
914 self._conf.set_configuration_set_values(\
919 '''The currently-active configuration set.''' 929 '''The name of the currently-active configuration set.''' 939 '''The dictionary of configuration sets in this component, if any.''' 950 raise CannotHoldChildrenError
957 cs = self._conf.get_configuration_set(name)
958 self.
_conf_sets[name]._reload(cs, cs.description,
962 cset, param = name.split(
'.')
963 cs = self._conf.get_configuration_set(cset)
965 self.
_conf_sets[cset].set_param(param, data[param])
968 cs = self._conf.get_configuration_set(name)
979 self.
_call_cb(
'config_event', (name, event))
984 uuid_val = uuid.uuid4().get_bytes()
985 intf_type = obs._this()._NP_RepositoryId
987 'heartbeat.interval':
'1.0',
988 'observed_status':
'ALL'})
989 sprof = SDOPackage.ServiceProfile(id=uuid_val,
990 interface_type=intf_type, service=obs._this(),
992 conf = self.object.get_configuration()
993 res = conf.add_service_profile(sprof)
1001 conf = self.object.get_configuration()
1002 res = conf.remove_service_profile(self.
_obs_id)
1014 if ec.handle == ec_handle:
1020 if ec.handle == ec_handle:
1030 self._obj.get_context(ec_handle), ec_handle))
1035 ec, loc =
get_ec(ec_handle)
1042 ec, loc =
get_ec(ec_handle)
1044 ec._set_running(
True)
1046 ec, loc =
get_ec(ec_handle)
1048 ec._set_running(
False)
1050 self.
_call_cb(
'ec_event', (ec_handle, state))
1054 if self._obj.is_alive(ec._obj):
1055 ec_state = ec.get_component_state(self.
_obj)
1056 if ec_state == RTC.ACTIVE_STATE:
1058 elif ec_state == RTC.ERROR_STATE:
1060 elif ec_state == RTC.INACTIVE_STATE:
1075 self.
_conf = self.object.get_configuration()
1077 for cs
in self._conf.get_configuration_sets():
1082 except SDOPackage.NotAvailable:
1088 profile = self._obj.get_component_profile()
1097 profile.parent.get_component_profile().instance_name
1103 def get_port_obj(port_name):
1104 for p_obj
in self._obj.get_ports():
1105 prof = p_obj.get_port_profile()
1106 if prof.name == port_name:
1108 raise ValueError(port_name)
1114 p_obj = get_port_obj(port_name)
1119 self._ports.remove(p)
1123 p.reparse_connections()
1127 p.reparse_connections()
1129 self.
_call_cb(
'port_event', (port_name, event))
1135 self.
_call_cb(
'component_profile', items)
1188 self.
_call_cb(
'rtc_status', (ec_handle, state))
1206 EC_RATE_CHANGED = 13
1219 PORT_DISCONNECT = 24
1224 CFG_UPDATE_PARAM = 32
1232 CFG_ACTIVATE_SET = 36
Execution context object.
def get_ec(self, ec_handle)
def activate_conf_set(self, set_name)
Configuration set management.
def _add_child(self)
Internal API.
def deactivate_in_ec(self, ec_index)
def __init__(self, name=None, parent=None, obj=None, args, kwargs)
def set_conf_set_value(self, set_name, param, value)
def get_state_in_ec_string(self, ec_index, add_colour=True)
def participating_ec_states(self)
def activate_in_ec(self, ec_index)
def add_members(self, rtcs)
Composite component information and management.
def _profile_update(self, items)
def refresh_state_in_ec(self, ec_index)
def add_logger(self, cb, level='NORMAL', filters='ALL')
def disconnect_all(self)
Port management.
def _reset_participating_ec_states(self)
def has_port_by_ref(self, port_ref)
def state_in_ec(self, ec_index)
def category(self)
Component information.
def connected_outports(self)
def parent_organisations(self)
def remove_logger(self, cb_id)
def exit(self)
State management.
def active_conf_set_name(self)
def connected_inports(self)
def connected_svcports(self)
Configuration set object.
def parent_org_sdo_ids(self)
def plain_state_string(self)
def get_state_string(self, add_colour=True)
def _ec_event(self, ec_handle, event)
def _reset_participating_ecs(self)
def _config_event(self, name, event)
def reparse_owned_ecs(self)
def is_composite_member(self)
def remove_members(self, rtcs)
def reparse_participating_ecs(self)
def _port_event(self, port_name, event)
def build_attr_string(attrs, supported=True)
def active_conf_set(self)
def get_port_by_name(self, port_name)
def heartbeat_time(self)
Node functionality.
def reset_in_ec(self, ec_index)
def _get_ec_state(self, ec)
def _set_state_in_ec(self, ec_handle, state)
def has_port_by_name(self, port_name)
def composite_parent(self)
def nvlist_to_dict(nvlist)
def owned_ec_states(self)
def participating_ecs(self)
def _reset_owned_ec_states(self)
def connected_ports(self)
def _parse_configuration(self)
def reparse_conf_sets(self)
def _enable_dynamic(self, enable=True)
def parse_port(port_obj, owner)
API functions.
def _call_cb(self, event, value)
def _set_events(self, events)
def reparse_profile(self)
def _reset_composite(self)
def _reset_conf_sets(self)
def get_port_by_ref(self, port_ref)
def get_ec_index(self, ec_handle)
def _reset_owned_ecs(self)