class Testblock: def __init__(self, testblock_name, metrics): self.testblock_name = testblock_name rospy.Subscriber("/atf/" + self.testblock_name + "/Trigger", Trigger, self.trigger_callback) self.transition = None self.metrics = metrics self.m = StateMachine(self.testblock_name) self.m.add_state(Status.PURGED, self.purged_state) self.m.add_state(Status.ACTIVE, self.active_state) self.m.add_state(Status.PAUSED, self.paused_state) self.m.add_state(Status.FINISHED, self.finished_state, end_state=True) self.m.add_state(Status.ERROR, self.error_state, end_state=True) self.m.set_start(Status.PURGED) self.m.run() def trigger_callback(self, msg): self.transition = msg.trigger def purge(self): for metric in self.metrics: metric.purge() def activate(self): for metric in self.metrics: metric.start() def pause(self): self.stop() def finish(self): self.stop() def exit(self): self.transition = Trigger.ERROR def stop(self): for metric in self.metrics: metric.stop() def get_state(self): return self.m.get_current_state() def purged_state(self): while not rospy.is_shutdown() and self.transition is None: continue if self.transition == Trigger.PURGE: # is already purged new_state = Status.PURGED elif self.transition == Trigger.ACTIVATE: self.activate() new_state = Status.ACTIVE elif self.transition == Trigger.PAUSE: new_state = Status.ERROR elif self.transition == Trigger.FINISH: new_state = Status.ERROR elif self.transition == Trigger.ERROR: new_state = Status.ERROR else: new_state = Status.ERROR self.transition = None return new_state def active_state(self): while not rospy.is_shutdown() and self.transition is None: continue if self.transition == Trigger.PURGE: self.purge() new_state = Status.PURGED elif self.transition == Trigger.ACTIVATE: # is already active new_state = Status.ACTIVE elif self.transition == Trigger.PAUSE: self.pause() new_state = Status.PAUSED elif self.transition == Trigger.FINISH: self.finish() new_state = Status.FINISHED elif self.transition == Trigger.ERROR: new_state = Status.ERROR else: new_state = Status.ERROR self.transition = None return new_state def paused_state(self): while not rospy.is_shutdown() and self.transition is None: continue if self.transition == Trigger.PURGE: self.purge() new_state = Status.PURGED elif self.transition == Trigger.ACTIVATE: self.activate() new_state = Status.ACTIVE elif self.transition == Trigger.PAUSE: # is already paused new_state = Status.PAUSED elif self.transition == Trigger.FINISH: self.finish() new_state = Status.FINISHED elif self.transition == Trigger.ERROR: new_state = Status.ERROR else: new_state = Status.ERROR self.transition = None return new_state def finished_state(self): pass def error_state(self): pass
class ProtocolAnalyzer(Analyzer): """ A protocol analyzer abstraction. Compared with basic analyzer, ProtocolAnalyzer has three built-in functions - State machine dynamics - Profile - Failure flags """ def __init__(self): """ Initialization. Each protocol should provide three initialization methods - Initialize ProfileHierarchy - Initialize StateMachnie - Initialize Failure flags """ Analyzer.__init__(self) self.profile = Profile(self.create_profile_hierarchy()) self.state_machine = StateMachine(self.create_state_machine(), self.init_protocol_state) # update state dynamics self.add_source_callback(self.__update_state) def create_profile_hierarchy(self): """ Declare a protocol-specific ProfileHierarchy returns: ProfileHierarchy based on protocol-specific parameters """ return None def create_state_machine(self): """ Declare a state machine returns: a dictinoary that describes the states and transition conditions """ return None def init_protocol_state(self, msg): """ At bootstrap, determine the protocol's current state :returns: a string of current state """ return None def declare_failure_flag(self): """ Initialize failure flags """ pass def __update_state(self, msg): """ Update states in response to cellular events :param msg: the event (message) from the trace collector. """ # Decode the message to XML format # FIXME: duplicate message decoding, inefficient log_item = msg.data.decode() if len(log_item) < 1: return log_item_dict = dict(log_item) if 'Msg' not in log_item_dict: return # Convert msg to xml format # log_xml = ET.fromstring(log_item_dict['Msg']) try: log_xml = ET.XML(log_item_dict['Msg']) xml_msg = Event(msg.timestamp, msg.type_id, log_xml) self.state_machine.update_state(xml_msg) except Exception as e: # Not an XML message return def get_protocol_state(self): """ Returns protocol's current state :returns: current state_machine """ return self.state_machine.get_current_state()