def _update(self): logger.debug("Update...") # noinspection PyBroadException try: entry = self._node_monitor.get(self._target_node_id) except Exception: self.setEnabled(False) return self.setEnabled(True) if entry.status: # Status should be always available... self._mode_health_uptime[0].set(uavcan.value_to_constant_name(entry.status, "mode", keep_literal=True)) self._mode_health_uptime[1].set(uavcan.value_to_constant_name(entry.status, "health", keep_literal=True)) self._mode_health_uptime[2].set(datetime.timedelta(days=0, seconds=entry.status.uptime_sec)) self._mode_health_uptime[0].set_background_color(node_mode_to_color(entry.status.mode)) self._mode_health_uptime[1].set_background_color(node_health_to_color(entry.status.health)) vssc = entry.status.vendor_specific_status_code self._vendor_status[0].set(vssc) self._vendor_status[1].set("0x%04x" % vssc) self._vendor_status[2].set( "0b" + bin((vssc >> 8) & 0xFF)[2:].zfill(8) + "_" + bin(vssc & 0xFF)[2:].zfill(8) ) if entry.info: inf = entry.info self._node_id_name[1].set(inf.name.decode()) swver = "%d.%d" % (inf.software_version.major, inf.software_version.minor) if inf.software_version.optional_field_flags & inf.software_version.OPTIONAL_FIELD_FLAG_VCS_COMMIT: swver += ".%08x" % inf.software_version.vcs_commit self._sw_version_crc[0].set(swver) if inf.software_version.optional_field_flags & inf.software_version.OPTIONAL_FIELD_FLAG_IMAGE_CRC: self._sw_version_crc[1].set("0x%016x" % inf.software_version.image_crc) else: self._sw_version_crc[1].clear() self._hw_version_uid[0].set("%d.%d" % (inf.hardware_version.major, inf.hardware_version.minor)) if not all([x == 0 for x in inf.hardware_version.unique_id]): self._hw_version_uid[1].set(" ".join(["%02x" % x for x in inf.hardware_version.unique_id])) else: self._hw_version_uid[1].clear() if len(inf.hardware_version.certificate_of_authenticity): self._cert_of_auth.set(" ".join(["%02x" % x for x in inf.hardware_version.certificate_of_authenticity])) else: self._cert_of_auth.clear() else: self._node_id_name[1].disable() self._sw_version_crc[0].disable() self._sw_version_crc[1].disable() self._hw_version_uid[0].disable() self._hw_version_uid[1].disable() self._cert_of_auth.disable()
def _update(self): logger.debug('Update...') # noinspection PyBroadException try: entry = self._node_monitor.get(self._target_node_id) except Exception: self.setEnabled(False) return self.setEnabled(True) if entry.status: # Status should be always available... self._mode_health_uptime[0].set(uavcan.value_to_constant_name(entry.status, 'mode', keep_literal=True)) self._mode_health_uptime[1].set(uavcan.value_to_constant_name(entry.status, 'health', keep_literal=True)) self._mode_health_uptime[2].set(datetime.timedelta(days=0, seconds=entry.status.uptime_sec)) self._mode_health_uptime[0].set_background_color(node_mode_to_color(entry.status.mode)) self._mode_health_uptime[1].set_background_color(node_health_to_color(entry.status.health)) vssc = entry.status.vendor_specific_status_code self._vendor_status[0].set(vssc) self._vendor_status[1].set('0x%04x' % vssc) self._vendor_status[2].set('0b' + bin((vssc >> 8) & 0xFF)[2:].zfill(8) + '_' + bin(vssc & 0xFF)[2:].zfill(8)) if entry.info: inf = entry.info self._node_id_name[1].set(inf.name.decode()) swver = '%d.%d' % (inf.software_version.major, inf.software_version.minor) if inf.software_version.optional_field_flags & inf.software_version.OPTIONAL_FIELD_FLAG_VCS_COMMIT: swver += '.%08x' % inf.software_version.vcs_commit self._sw_version_crc[0].set(swver) if inf.software_version.optional_field_flags & inf.software_version.OPTIONAL_FIELD_FLAG_IMAGE_CRC: self._sw_version_crc[1].set('0x%016x' % inf.software_version.image_crc) else: self._sw_version_crc[1].clear() self._hw_version_uid[0].set('%d.%d' % (inf.hardware_version.major, inf.hardware_version.minor)) if not all([x == 0 for x in inf.hardware_version.unique_id]): self._hw_version_uid[1].set(' '.join(['%02x' % x for x in inf.hardware_version.unique_id])) else: self._hw_version_uid[1].clear() if len(inf.hardware_version.certificate_of_authenticity): self._cert_of_auth.set(' '.join(['%02x' % x for x in inf.hardware_version.certificate_of_authenticity])) else: self._cert_of_auth.clear() else: self._node_id_name[1].disable() self._sw_version_crc[0].disable() self._sw_version_crc[1].disable() self._hw_version_uid[0].disable() self._hw_version_uid[1].disable() self._cert_of_auth.disable()
def _do_execute_opcode(self, opcode): request = uavcan.protocol.param.ExecuteOpcode.Request(opcode=opcode) opcode_str = uavcan.value_to_constant_name(request, 'opcode', keep_literal=True) if not request_confirmation( 'Confirm opcode execution', 'Do you really want to execute param opcode %s?' % opcode_str, self): return def callback(e): if e is None: self.window().show_message( 'Opcode execution response for %s has timed out', opcode_str) else: self.window().show_message( 'Opcode execution response for %s: %s', opcode_str, e.response) try: self._node.request(request, self._target_node_id, callback, priority=REQUEST_PRIORITY) self.window().show_message('Param opcode %s requested', opcode_str) except Exception as ex: show_error('Node error', 'Could not send param opcode execution request', ex, self)
class LogMessageDisplayWidget(QGroupBox): COLUMNS = [ BasicTable.Column('NID', lambda e: e.transfer.source_node_id), BasicTable.Column('Local Time', lambda e: datetime.datetime.fromtimestamp( e.transfer.ts_real).strftime('%H:%M:%S.%f')[:-3], searchable=False), BasicTable.Column( 'Level', lambda e: (uavcan.value_to_constant_name(e.message.level, 'value'), log_level_to_color(e.message.level))), BasicTable.Column('Source', lambda e: e.message.source), BasicTable.Column('Text', lambda e: e.message.text, resize_mode=QHeaderView.Stretch), ] def __init__(self, parent, node): super(LogMessageDisplayWidget, self).__init__(parent) self.setTitle('Log messages (uavcan.protocol.debug.LogMessage)') self._log_widget = RealtimeLogWidget(self, columns=self.COLUMNS, multi_line_rows=True, started_by_default=True) self._subscriber = node.add_handler(uavcan.protocol.debug.LogMessage, self._log_widget.add_item_async) layout = QVBoxLayout(self) layout.addWidget(self._log_widget, 1) self.setLayout(layout) def close(self): self._subscriber.remove()
def _do_execute_opcode(self, opcode): request = uavcan.protocol.param.ExecuteOpcode.Request(opcode=opcode) opcode_str = uavcan.value_to_constant_name(request, "opcode", keep_literal=True) if not request_confirmation( "Confirm opcode execution", "Do you really want to execute param opcode %s?" % opcode_str, self ): return def callback(e): if e is None: self.window().show_message("Opcode execution response for %s has timed out", opcode_str) else: self.window().show_message("Opcode execution response for %s: %s", opcode_str, e.response) try: self._node.request(request, self._target_node_id, callback, priority=REQUEST_PRIORITY) self.window().show_message("Param opcode %s requested", opcode_str) except Exception as ex: show_error("Node error", "Could not send param opcode execution request", ex, self)
class UWBNodeTable(BasicTable): COLUMNS = [ BasicTable.Column('NID', lambda e: e.node_id), BasicTable.Column('UWB_NID', lambda e: hex(e.status.node_id)), BasicTable.Column('UWB_BID', lambda e: e.status.body_id), BasicTable.Column( 'UWB_SID', lambda e: "UNALLOCATED" if e.status.data_slot_id == 255 else e.status.data_slot_id), BasicTable.Column( 'TX_Type', lambda e: uavcan.value_to_constant_name(e.status, 'type'), QHeaderView.Stretch), BasicTable.Column('Num_Pkt', lambda e: e.status.pkt_cnt), BasicTable.Column( 'P_STATE', lambda e: uavcan.value_to_constant_name(e.status, 'pstate'), QHeaderView.Stretch), BasicTable.Column('Progress', lambda e: e.progress) ] class Row_value: """docstring for Row_value""" def __init__(self, status, progress): self.node_id = status.transfer.source_node_id self.status = status.message self.progress = progress def __init__(self, parent, node, monitor): super(UWBNodeTable, self).__init__(parent, self.COLUMNS, font=get_monospace_font()) self._monitor = monitor self._timer = QTimer(self) self._timer.setSingleShot(False) self._timer.timeout.connect(self._update) self._timer.start(500) self.setMinimumWidth(700) self.progress = {} def selectedBodyID(self): if len(self.selectionModel().selectedRows()) == 0: return None x = self.selectionModel().selectedRows()[0] return int(self.item(x.row(), 2).text(), 0) def _update(self): known_nodes = { e.transfer.source_node_id: e for e in self._monitor.find_all(lambda _: True) } displayed_nodes = set() rows_to_remove = [] # Updating existing entries for row in range(self.rowCount()): nid = int(self.item(row, 0).text(), 0) displayed_nodes.add(nid) if nid not in known_nodes: rows_to_remove.append(row) self.progress.pop(nid, None) else: row_val = UWBNodeTable.Row_value(known_nodes[nid], self.progress[nid]) self.set_row(row, row_val) # Removing nonexistent entries for row in rows_to_remove[:: -1]: # It is important to traverse from end logger.info('Removing row %d', row) self.removeRow(row) # Adding new entries def find_insertion_pos_for_node_id(target_slot_id): for row in range(self.rowCount()): slot_id = int(self.item(row, 1).text(), 0) + int( self.item(row, 2).text(), 0) if slot_id > target_slot_id: return row return self.rowCount() for nid in set(known_nodes.keys()) - displayed_nodes: row = find_insertion_pos_for_node_id( known_nodes[nid].message.data_slot_id + known_nodes[nid].message.body_id) self.insertRow(row) self.progress[nid] = 0 row_val = UWBNodeTable.Row_value(known_nodes[nid], self.progress[nid]) self.set_row(row, row_val) def set_progress(self, nid, progress): try: self.progress[nid] = progress except KeyError: pass
class NodeTable(BasicTable): COLUMNS = [ BasicTable.Column('NID', lambda e: e.node_id), BasicTable.Column('Name', lambda e: e.info.name if e.info else '?', QHeaderView.Stretch), BasicTable.Column( 'Mode', lambda e: (uavcan.value_to_constant_name(e.status, 'mode'), node_mode_to_color(e.status.mode))), BasicTable.Column( 'Health', lambda e: (uavcan.value_to_constant_name( e.status, 'health'), node_health_to_color(e.status.health))), BasicTable.Column( 'Uptime', lambda e: datetime.timedelta(days=0, seconds=e.status.uptime_sec)), BasicTable.Column( 'VSSC', lambda e: '%d 0x%04x' % (e.status.vendor_specific_status_code, e.status. vendor_specific_status_code)) ] info_requested = pyqtSignal([int]) def __init__(self, parent, node): super(NodeTable, self).__init__(parent, self.COLUMNS, font=get_monospace_font()) self.cellDoubleClicked.connect( lambda row, col: self._call_info_requested_callback_on_row(row)) self.on_enter_pressed = self._on_enter self._monitor = uavcan.app.node_monitor.NodeMonitor(node) self._timer = QTimer(self) self._timer.setSingleShot(False) self._timer.timeout.connect(self._update) self._timer.start(500) self.setMinimumWidth(500) @property def monitor(self): return self._monitor def close(self): self._monitor.close() def _call_info_requested_callback_on_row(self, row): nid = int(self.item(row, 0).text()) self.info_requested.emit(nid) def _on_enter(self, list_of_row_col_pairs): unique_rows = set([row for row, _col in list_of_row_col_pairs]) if len(unique_rows) == 1: self._call_info_requested_callback_on_row(list(unique_rows)[0]) def _update(self): known_nodes = { e.node_id: e for e in self._monitor.find_all(lambda _: True) } displayed_nodes = set() rows_to_remove = [] # Updating existing entries for row in range(self.rowCount()): nid = int(self.item(row, 0).text()) displayed_nodes.add(nid) if nid not in known_nodes: rows_to_remove.append(row) else: self.set_row(row, known_nodes[nid]) # Removing nonexistent entries for row in rows_to_remove[:: -1]: # It is important to traverse from end logger.info('Removing row %d', row) self.removeRow(row) # Adding new entries def find_insertion_pos_for_node_id(target_nid): for row in range(self.rowCount()): nid = int(self.item(row, 0).text()) if nid > target_nid: return row return self.rowCount() for nid in set(known_nodes.keys()) - displayed_nodes: row = find_insertion_pos_for_node_id(nid) logger.info('Adding new row %d for node %d', row, nid) self.insertRow(row) self.set_row(row, known_nodes[nid])