def _GetStoplight(self, values, any_values, missing_values, flight_mode): """Get the stoplight according to the values. Args: values: The values to determine stoplights. It is used in overrides of this method. any_values: If False, then the stoplight should be grey. missing_values: If True, then the stoplight should not be green. flight_mode: The current flight mode. Returns: The stoplight corresponding to the value and conditions. """ if not any_values: stoplight = stoplights.STOPLIGHT_UNAVAILABLE elif missing_values: stoplight = stoplights.STOPLIGHT_ERROR else: stoplight = stoplights.STOPLIGHT_NORMAL if values and flight_mode in self._limits: range_stoplight = stoplights.STOPLIGHT_NORMAL for key, (normal_ranges, warning_ranges) in self._limits[ flight_mode].iteritems(): range_stoplight = stoplights.MostSevereStoplight( range_stoplight, stoplights.SetByRanges( values[key], normal_ranges, warning_ranges)) stoplight = stoplights.MostSevereStoplight(stoplight, range_stoplight) return stoplight
def _Filter(self, telemetry, *args): stoplight = stoplights.MostSevereStoplight( stoplights.SetByLimits(telemetry.estimator.gsg_bias.azi, self.gsg_bias_azi_limits), stoplights.SetByLimits(telemetry.estimator.gsg_bias.ele, self.gsg_bias_ele_limits)) message = 'azi: {azi: 3.0f} deg ele: {ele: 3.0f} deg'.format( azi=(180.0 / numpy.pi) * telemetry.estimator.gsg_bias.azi, ele=(180.0 / numpy.pi) * telemetry.estimator.gsg_bias.ele) return message, stoplight
def _PosVelType(self, gps_solution, allowed_pos_types, allowed_vel_types): pos_type = gps_solution.best_xyz.pos_type vel_type = gps_solution.best_xyz.vel_type pos_type_name, pos_stoplight = self._SolutionType( allowed_pos_types, pos_type) vel_type_name, vel_stoplight = self._SolutionType( allowed_vel_types, vel_type) stoplight = stoplights.MostSevereStoplight(pos_stoplight, vel_stoplight) return ('pos: {:>6} vel: {:>6}'.format(pos_type_name, vel_type_name), stoplight)
def _CheckLinkRate(self, direction, rate, freq, link_stat, stoplight, content): """Perform common checks for link rates. Args: direction: Usually it is 'tx' or 'rx'. rate: The packet rate. freq: The frequency of the message. link_stat: The structure holding expected packet rates. stoplight: The stoplight so far. content: A list holding results for various checks. Returns: stoplight: The resuling stoplight. """ expected_packets_per_sec = getattr(link_stat, 'packets_per_sec') if rate is None: result_stoplight = stoplights.STOPLIGHT_UNAVAILABLE content.append({ 'name': '%s rate unavailable.' % direction, 'stoplight': result_stoplight, }) stoplight = stoplights.MostSevereStoplight(stoplight, result_stoplight) elif rate * freq != expected_packets_per_sec: result_stoplight = stoplights.STOPLIGHT_WARNING content.append({ 'name': '%s rate (%.2f) != expected (%.2f)' % (direction, rate * freq, expected_packets_per_sec), 'stoplight': result_stoplight, }) stoplight = stoplights.MostSevereStoplight(stoplight, result_stoplight) return stoplight
def _Filter(self, down_status, up_status): if struct_tree.IsValidElement(down_status): text, down_stoplight = self._HandleStatus( down_status.connected, down_status.rssi) else: text, down_stoplight = '--', stoplights.STOPLIGHT_WARNING result = '%s dBm down, ' % text if struct_tree.IsValidElement(up_status): is_connected = (up_status.links_up & pack_avionics_messages.kTetherCommsLinkJoystick) text, up_stoplight = self._HandleStatus( is_connected, up_status.received_signal_strength) else: text, up_stoplight = '--', stoplights.STOPLIGHT_WARNING result += '%s dBm up' % text stoplight = stoplights.MostSevereStoplight(down_stoplight, up_stoplight) return result, stoplight
def Filter(self, messages): """Select and compute data to show. Args: messages: A struct_tree.StructTree containing a snapshot of messages received. It can be indexed as a nested dict. Indexing returns None if field does not exist. Returns: A PlotData object storing the generated data. """ data = self._GetPlotData() for aio_node in self._node_stats: # Check error flags on all the nodes. message_type = self._GetStatusMessageType(aio_node) if message_type is None: continue # Index string to the ethernet stats. path = self._EthernetStatsPath(message_type, aio_node) error_fields = [ 'rx_fragment_errors', 'rx_alignment_errors', 'rx_fcs_errors', 'rx_symbol_errors', 'rx_jabber_errors', 'rx_in_range_errors', 'tx_dropped_packets' ] # Stoplight showing the status of this AIO node. node_stoplight = stoplights.STOPLIGHT_ANY # Detailed status of this AIO node. content = [] for field in error_fields: # An array of error counts per port, or None if message is unavailable. error_stats = messages['%s.%s' % (path, field)] # Stoplight for this error field. field_stoplight = stoplights.STOPLIGHT_ANY # Indicators for each port. port_stats = {} if error_stats: for port, error_count in enumerate(error_stats): if error_count > 0: port_stoplight = stoplights.STOPLIGHT_WARNING else: port_stoplight = stoplights.STOPLIGHT_NORMAL port_stats[port] = { 'value': error_count, 'stoplight': port_stoplight } # Stoplight of a field indicates the worst case of all subfields. field_stoplight = stoplights.MostSevereStoplight( field_stoplight, port_stoplight) else: field_stoplight = stoplights.STOPLIGHT_UNAVAILABLE # Stoplight of the AIO node indicates the worst case of all fields. node_stoplight = stoplights.MostSevereStoplight( node_stoplight, field_stoplight) content.append({ 'name': field, 'stoplight': field_stoplight, 'fields': port_stats, }) data[self._AioNodeStatsName(aio_node)] = { 'stoplight': node_stoplight, 'content': content, 'node': aio_node, } # Check each link. for link, link_stat in self._link_stats.iteritems(): if not self._IsInterNodeLink(link): # Skip onboard links. continue link_name = self._LinkStatsName(link) if messages: sender_field, sender_freq = self._GetFieldAndFreqFromPortTag( link[0], 'tx_multicast_packet_rate') receiver_field, receiver_freq = self._GetFieldAndFreqFromPortTag( link[1], 'rx_multicast_packet_rate') if sender_field is None or receiver_field is None: # No such link. continue # The stoplight for this link. link_stoplight = stoplights.STOPLIGHT_ANY content = [] # Check individual rates. sender_rate = messages[sender_field] receiver_rate = messages[receiver_field] # Check if the rates match. if sender_rate is not None and receiver_rate is not None: if sender_rate < 0: result_stoplight = stoplights.STOPLIGHT_ERROR content.append({ 'name': 'Invalid tx rate: %.2f' % sender_rate, 'stoplight': result_stoplight }) elif receiver_rate < 0: result_stoplight = stoplights.STOPLIGHT_ERROR content.append({ 'name': 'Invalid rx rate: %.2f' % receiver_rate, 'stoplight': result_stoplight }) elif (abs(sender_rate - receiver_rate) > 1 and abs(sender_rate - receiver_rate) / float(sender_rate + receiver_rate) > 0.1): result_stoplight = stoplights.STOPLIGHT_ERROR content.append({ 'name': 'tx rate (%.2f) != rx rate (%.2f)' % (sender_rate, receiver_rate), 'stoplight': result_stoplight, }) else: # If they differ by no more than one or the difference is less than # 10% of their sum, treat them as equal. if sender_rate == getattr(link_stat, 'packets_per_sec'): result_stoplight = stoplights.STOPLIGHT_NORMAL else: # Equal rates but with unexpected value. result_stoplight = stoplights.STOPLIGHT_WARNING content.append({ 'name': 'tx/rx rate: %.2f/%.2f' % (sender_rate, receiver_rate), 'stoplight': result_stoplight, }) link_stoplight = stoplights.MostSevereStoplight( link_stoplight, result_stoplight) link_stoplight = self._CheckLinkRate('tx', sender_rate, sender_freq, link_stat, link_stoplight, content) link_stoplight = self._CheckLinkRate('rx', receiver_rate, receiver_freq, link_stat, link_stoplight, content) else: link_stoplight = stoplights.STOPLIGHT_UNAVAILABLE content = [] data[link_name] = { 'stoplight': link_stoplight, 'content': content, 'src': self._ParseNetworkConfigTag(link[0]), 'dest': self._ParseNetworkConfigTag(link[1]), } return data
def Filter(self, messages): """Select and compute data to show. Args: messages: A StructTree object, which is a nested dict that can be indexed using a string. Indexing returns None if field does not exist. Returns: A PlotData object storing the generated data. """ data = self._GetPlotData() for message_name, section in self._check_dict.iteritems(): for source, attributes in section.iteritems(): for attribute, attribute_checks in attributes.iteritems(): attribute_data = [] attribute_stoplight = stoplights.STOPLIGHT_ANY is_any_field_available = False for check_item in attribute_checks.List(): # Note a field can be a dict or list, each value will have to be # checked. So there may be multiple checks. The format is: # check_results = [{ # 'name': ..., # 'value': {'stoplight': ..., 'value': ...}, # 'std': {'stoplight': ..., 'value': ...} # }] check_item.Check(*check_item.Populate(messages)) check_results = check_item.GetResults() if not check_results: continue for check in check_results: # Indicate the worst condition across all checks in this field. field_stoplight = check['stoplight'] if field_stoplight is not None: attribute_stoplight = stoplights.MostSevereStoplight( attribute_stoplight, field_stoplight) is_any_field_available = True else: field_stoplight = stoplights.STOPLIGHT_UNAVAILABLE attribute_data.append({ 'name': None, 'fields': {check['name']: check}, 'stoplight': field_stoplight }) # Remove 'name' field because it is never used again. # This saves some traffic from the server to the client. del check['name'] if not is_any_field_available: attribute_stoplight = stoplights.STOPLIGHT_UNAVAILABLE data[self._GetDataName(message_name, source, attribute)] = { 'content': attribute_data, 'stoplight': attribute_stoplight, } # TODO: Add voltage checks for servo, core switch, # and flight computers. # Data for additional indicators not defined in the gradebook. data.loadcell_aio_update_stoplight = stoplights.SetByAioUpdate( messages, 'Loadcell', None, stoplights.STOPLIGHT_NORMAL, stoplights.STOPLIGHT_ERROR, stoplights.STOPLIGHT_UNAVAILABLE) loadcells = ['StarboardA', 'PortA'] for loadcell in loadcells: strains = [] strains.append(messages['Loadcell.Loadcell' + loadcell + '.loadcell_data.strain[0].value']) strains.append(messages['Loadcell.Loadcell' + loadcell + '.loadcell_data.strain[1].value']) data['loadcell_strains_' + loadcell] = strains data['loadcell_timestamp_' + loadcell] = messages[ 'Loadcell.Loadcell' + loadcell + '.capture_info.timestamp'] return data