示例#1
0
    def flashing_pressed(self):
        first = False

        if self.flashing_window is None:
            first = True
            self.flashing_window = FlashingWindow(self)

        self.update_flashing_window()
        self.flashing_window.show()
        self.flashing_window.refresh_updates_pressed()

        if first:
            self.flashing_window.refresh_firmware_and_plugin_infos()
示例#2
0
class MainWindow(QMainWindow, Ui_MainWindow):
    callback_enumerate_signal = pyqtSignal(str, str, int, bool)
    
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setupUi(self)
        self.setWindowIcon(QIcon("brickv-icon.png"))
        signal.signal(signal.SIGINT, self.exit_brickv) 
        signal.signal(signal.SIGTERM, self.exit_brickv) 
        
        self.setWindowTitle("Brick Viewer " + config.BRICKV_VERSION)
        
        self.table_view_header = ['Stack ID', 'Device Name', 'UID', 'FW Version', 'Chip Temp.', 'Reset']

        # Remove dummy tab
        self.tab_widget.removeTab(1)
        self.last_tab = 0
        
        self.plugins = [(self, None, None, None)]
        self.ipcon = None
        self.flashing_window = None
        self.advanced_window = None
        self.reset_view()
        self.button_advanced.setDisabled(True)

        self.callback_enumerate_signal.connect(self.callback_enumerate)

        self.tab_widget.currentChanged.connect(self.tab_changed)
        self.connect.pressed.connect(self.connect_pressed)
        self.button_flashing.pressed.connect(self.flashing_pressed)
        self.button_advanced.pressed.connect(self.advanced_pressed)
        self.plugin_manager = PluginManager()

        self.host.setText(config.get_host())
        self.port.setValue(config.get_port())

        self.mtm = None

        self.chip_temp_timer = QTimer()
        self.chip_temp_timer.timeout.connect(self.update_chip_temp)
        self.chip_temp_timer.setInterval(2000)
        self.chip_temp_timer.start()

    def closeEvent(self, event):
        self.exit_brickv()
        
    def exit_brickv(self, signl=None, frme=None):
        config.set_host(str(self.host.text()))
        config.set_port(self.port.value())

        if self.ipcon != None:
            self.reset_view()
            
        if signl != None and frme != None:
            print "Received SIGINT or SIGTERM, shutting down."
            sys.exit()

    def start(self):
        self.update_chip_temp()
        self.chip_temp_timer.start()
    
    def stop(self):
        self.chip_temp_timer.stop()
    
    def destroy(self):
        pass
        
    def tab_changed(self, i):
        self.plugins[i][0].start()
        self.plugins[self.last_tab][0].stop()
        self.last_tab = i
        
    def reset_view(self):
        self.tab_widget.setCurrentIndex(0)
        for i in reversed(range(1, len(self.plugins))):
            try:
                self.plugins[i][0].stop()
                self.plugins[i][0].destroy()
            except AttributeError:
                pass
        
            self.tab_widget.removeTab(i)
            
        self.plugins = [(self, None, None, None)]
        
        self.update_table_view()
        
        if self.ipcon:
            self.ipcon.destroy()
        self.ipcon = None

    def flashing_pressed(self):
        if self.flashing_window is None:
            self.flashing_window = FlashingWindow(self)

        self.update_flashing_window()
        self.flashing_window.show()

    def advanced_pressed(self):
        if self.advanced_window is None:
            self.advanced_window = AdvancedWindow(self)

        self.update_advanced_window()
        self.advanced_window.show()

    def connect_pressed(self):
        if not self.ipcon:
            try:
                self.ipcon = IPConnection(self.host.text(), self.port.value())
                self.ipcon.enumerate(self.callback_enumerate_signal.emit)
                self.connect.setText("Disconnect")
                self.port.setDisabled(True)
                self.host.setDisabled(True)
            except (Error, socket.error):
                self.ipcon = None
                box_head = 'Could not connect'
                box_text = 'Please check host, check port and ' + \
                           'check if brickd is running.'
                QMessageBox.critical(self, box_head, box_text)
        else:
            self.reset_view()
            
            self.connect.setText("Connect")
            self.button_advanced.setDisabled(True)
            self.port.setDisabled(False)
            self.host.setDisabled(False)
        
    def callback_enumerate(self, uid, name, stack_id, is_new):
        if is_new:
            for plugin in self.plugins:
                # Plugin already loaded
                if plugin[3] == uid:
                    return
            plugin = self.plugin_manager.get_plugin_from_name(name, 
                                                              self.ipcon, 
                                                              uid)
            if plugin is not None:
                self.tab_widget.addTab(plugin, name)
                self.plugins.append((plugin, stack_id, name, uid))
        else:
            for i in range(len(self.plugins)):
                if self.plugins[i][3] == uid:
                    self.tab_widget.setCurrentIndex(0)
                    self.plugins[i][0].stop()
                    self.plugins[i][0].destroy()
                    self.tab_widget.removeTab(i)
                    self.plugins.remove(self.plugins[i])
                    self.update_table_view()
                    return
                
        self.update_table_view()
    
    def update_table_view(self):
        data = []
        for p in self.plugins[1:]:
            if p[0] is not None:
                data.append([p[1], p[2], p[3], p[0].version, '', ''])
            
        self.mtm = MainTableModel(self.table_view_header, data)
        self.table_view.setModel(self.mtm)

        for r in range(len(data)):
            p = self.plugins[r + 1]
            if p[0] is not None and ' Brick ' in p[2]:
                button = QPushButton('Reset')
                if p[0].has_reset_device():
                    button.clicked.connect(p[0].reset_device)
                else:
                    button.setDisabled(True)
                self.table_view.setIndexWidget(self.mtm.index(r, 5), button)

        self.update_flashing_window()
        self.update_advanced_window()

    def update_flashing_window(self):
        if self.flashing_window is not None:
            devices = []
            for plugin in self.plugins[1:]:
                if ' Brick ' in plugin[2]:
                    devices.append((plugin[2], plugin[0].device))
            self.flashing_window.set_devices(devices)

    def update_advanced_window(self):
        devices = []
        for plugin in self.plugins[1:]:
            if ' Brick ' in plugin[2]:
                devices.append((plugin[2], plugin[0].device))

        self.button_advanced.setEnabled(len(devices) > 0)

        if self.advanced_window is not None:
            self.advanced_window.set_devices(devices)

    def update_chip_temp(self):
        if self.mtm is None:
            return

        for r in range(len(self.plugins) - 1):
            p = self.plugins[r + 1]
            if p[0] is not None:
                try:
                    self.mtm.setData(self.mtm.index(r, 4), p[0].get_chip_temperature(), Qt.DisplayRole)
                except Error:
                    # abort update here to avoid requesting chtip temp from a
                    # whole disconnected stack
                    return
示例#3
0
    def flashing_pressed(self):
        if self.flashing_window is None:
            self.flashing_window = FlashingWindow(self)

        self.update_flashing_window()
        self.flashing_window.show()
示例#4
0
class MainWindow(QMainWindow, Ui_MainWindow):
    qtcb_enumerate = pyqtSignal(str, str, 'char', type((0,)), type((0,)), int, int)
    qtcb_connected = pyqtSignal(int)
    qtcb_disconnected = pyqtSignal(int)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setupUi(self)
        self.setWindowIcon(QIcon(os.path.join(ProgramPath.program_path(), "brickv-icon.png")))
        signal.signal(signal.SIGINT, self.exit_brickv)
        signal.signal(signal.SIGTERM, self.exit_brickv)

        self.async_thread = async_start_thread(self)

        self.setWindowTitle("Brick Viewer " + config.BRICKV_VERSION)
        
        self.tree_view_model_labels = ['Name', 'UID', 'FW Version']
        self.tree_view_model = QStandardItemModel()
        self.tree_view.setModel(self.tree_view_model)
        self.set_tree_view_defaults()   

        # Remove dummy tab
        self.tab_widget.removeTab(1)
        self.last_tab = 0

        self.name = '<unknown>'
        self.uid = '<unknown>'
        self.version = (0, 0, 0)

        self.disconnect_times = []

        self.qtcb_enumerate.connect(self.cb_enumerate)
        self.qtcb_connected.connect(self.cb_connected)
        self.qtcb_disconnected.connect(self.cb_disconnected)

        self.ipcon = IPConnection()
        self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
                                     self.qtcb_enumerate.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
                                     self.qtcb_connected.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_DISCONNECTED,
                                     self.qtcb_disconnected.emit)

        self.flashing_window = None
        self.advanced_window = None
        self.delayed_refresh_updates_timer = QTimer()
        self.delayed_refresh_updates_timer.timeout.connect(self.delayed_refresh_updates)
        self.delayed_refresh_updates_timer.setInterval(500)
        self.reset_view()
        self.button_advanced.setDisabled(True)

        self.tab_widget.currentChanged.connect(self.tab_changed)
        self.connect.pressed.connect(self.connect_pressed)
        self.button_flashing.pressed.connect(self.flashing_pressed)
        self.button_advanced.pressed.connect(self.advanced_pressed)
        self.plugin_manager = PluginManager()

        self.combo_host.addItem(config.get_host())
        self.combo_host.addItems(config.get_host_history(HOST_HISTORY_SIZE - 1))
        self.spinbox_port.setValue(config.get_port())

        self.last_host = self.combo_host.currentText()
        self.last_port = self.spinbox_port.value()
        
    def closeEvent(self, event):
        self.exit_brickv()

    def exit_brickv(self, signl=None, frme=None):
        host = str(self.combo_host.currentText())
        history = []

        for i in range(self.combo_host.count()):
            h = str(self.combo_host.itemText(i))

            if h != host and h not in history:
                history.append(h)

        config.set_host(host)
        config.set_host_history(history[:HOST_HISTORY_SIZE - 1])
        config.set_port(self.spinbox_port.value())

        self.reset_view()

        try:
            self.ipcon.disconnect()
        except:
            pass

        if signl != None and frme != None:
            print "Received SIGINT or SIGTERM, shutting down."
            sys.exit()

    def start(self):
        pass

    def stop(self):
        pass

    def destroy(self):
        pass

    def tab_changed(self, i):
        try:
            uid = self.tab_widget.widget(i)._uid
            infos.infos[uid].plugin.start()
        except:
            pass
        
        try:
            uid = self.tab_widget.widget(self.last_tab)._uid
            infos.infos[uid].plugin.stop()
        except:
            pass

        self.last_tab = i

    def reset_view(self):
        self.tab_widget.setCurrentIndex(0)
        
        keys_to_remove = []
        for key in infos.infos:
            if infos.infos[key].type in ('brick', 'bricklet'):
                infos.infos[key].plugin.stop()
                infos.infos[key].plugin.destroy()
                keys_to_remove.append(key)
                
        for key in keys_to_remove:
            try:
                infos.infos.pop(key)
            except:
                pass
                
        for i in reversed(range(1, self.tab_widget.count())):
            self.tab_widget.removeTab(i)

        self.update_tree_view()

    def flashing_pressed(self):
        first = False

        if self.flashing_window is None:
            first = True
            self.flashing_window = FlashingWindow(self)

        self.update_flashing_window()
        self.flashing_window.show()
        self.flashing_window.refresh_updates_pressed()

        if first:
            self.flashing_window.refresh_firmware_and_plugin_infos()

    def advanced_pressed(self):
        if self.advanced_window is None:
            self.advanced_window = AdvancedWindow(self)

        self.update_advanced_window()
        self.advanced_window.show()

    def connect_pressed(self):
        if self.ipcon.get_connection_state() == IPConnection.CONNECTION_STATE_DISCONNECTED:
            try:
                self.last_host = self.combo_host.currentText()
                self.last_port = self.spinbox_port.value()
                self.connect.setDisabled(True)
                self.ipcon.connect(self.last_host, self.last_port)

            except:
                self.connect.setDisabled(False)
                QMessageBox.critical(self, 'Could not connect',
                                     'Please check host, check port and ' +
                                     'check if the Brick Daemon is running')
        else:
            self.reset_view()
            async_next_session()
            self.ipcon.disconnect()

    def create_plugin_container(self, plugin, connected_uid, position):
        container = QWidget()
        container._uid = plugin.uid
        layout = QVBoxLayout(container)
        info = QHBoxLayout()

        # uid
        info.addWidget(QLabel('UID:'))
        label = QLabel('{0}'.format(plugin.uid))
        label.setTextInteractionFlags(Qt.TextSelectableByMouse |
                                      Qt.TextSelectableByKeyboard)
        info.addWidget(label)

        info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # connected uid
        if connected_uid != '0':
            info.addWidget(QLabel('Connected to:'))
            label = QLabel('{0}'.format(connected_uid))
            label.setTextInteractionFlags(Qt.TextSelectableByMouse |
                                          Qt.TextSelectableByKeyboard)
            info.addWidget(label)

            info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # position
        info.addWidget(QLabel('Position:'))
        info.addWidget(QLabel('{0}'.format(position.upper())))

        info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # firmware version
        info.addWidget(QLabel('FW Version:'))
        info.addWidget(QLabel('{0}'.format(plugin.version_str)))

        info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # timeouts
        info.addWidget(QLabel('Timeouts:'))
        label_timeouts = QLabel('0')
        info.addWidget(label_timeouts)

        layout.addLayout(info)

        if plugin.is_brick():
            button = QPushButton('Reset')
            if plugin.has_reset_device():
                button.clicked.connect(plugin.reset_device)
            else:
                button.setDisabled(True)
            info.addSpacerItem(QSpacerItem(40, 20, QSizePolicy.Expanding))
            info.addWidget(button)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        plugin.label_timeouts = label_timeouts
        plugin.layout().setContentsMargins(0, 0, 0, 0)

        layout.addWidget(line)
        layout.addWidget(plugin)

        return container
    
    def tab_for_uid(self, uid):
        for i in range(1, self.tab_widget.count()):
            try:
                widget = self.tab_widget.widget(i)
                if widget._uid == uid:
                    return i
            except:
                pass
                
        return -1

    def cb_enumerate(self, uid, connected_uid, position,
                     hardware_version, firmware_version,
                     device_identifier, enumeration_type):
        if self.ipcon.get_connection_state() != IPConnection.CONNECTION_STATE_CONNECTED:
            # ignore enumerate callbacks that arrived after the connection got closed
            return

        if enumeration_type in [IPConnection.ENUMERATION_TYPE_AVAILABLE,
                                IPConnection.ENUMERATION_TYPE_CONNECTED]:
            if device_identifier == BrickMaster.DEVICE_IDENTIFIER:
                info = infos.BrickMasterInfo()
            elif position in ('a', 'b', 'c', 'd', 'A', 'B', 'C', 'D'):
                position = position.lower()
                info = infos.BrickletInfo()
            else:
                info = infos.BrickInfo()

            if uid in infos.infos:
                info = infos.infos[uid]
            else:
                infos.infos[uid] = info

            for device in infos.infos.values():
                if device.type == 'brick':
                    if info.type == 'bricklet':
                        if device.uid == connected_uid:
                            device.bricklets[position] = info
                if device.type == 'bricklet':
                    if info.type == 'brick':
                        if uid == device.connected_uid:
                            info.bricklets[device.position] = device
                            
            info.uid = uid
            info.connected_uid = connected_uid
            info.position = position
            info.hardware_version = hardware_version
            info.firmware_version_installed = firmware_version
            info.device_identifier = device_identifier
            info.protocol_version = 2
            info.enumeration_type = enumeration_type
            
            for device in infos.infos.values():
                if device.type in ('brick', 'bricklet'):
                    if device.uid == uid and device.plugin != None:
                        return

            plugin = self.plugin_manager.get_plugin(device_identifier, self.ipcon,
                                                    uid, firmware_version)

            if plugin is not None:
                info.plugin = plugin
                if plugin.is_hardware_version_relevant(hardware_version):
                    info.name = '{0} {1}.{2}'.format(plugin.name,
                                                     hardware_version[0],
                                                     hardware_version[1])
                else:
                    info.name = plugin.name
                    
                info.url_part = plugin.get_url_part()
                    
                c = self.create_plugin_container(plugin, connected_uid, position)
                info.plugin_container = c
                self.tab_widget.addTab(c, info.name)
        elif enumeration_type == IPConnection.ENUMERATION_TYPE_DISCONNECTED:
            for device_info in infos.infos.values():
                if device_info.type in ('brick', 'bricklet'):
                    if device_info.uid == uid:
                        try:
                            self.tab_widget.setCurrentIndex(0)
                            if device_info.plugin:
                                device_info.plugin.stop()
                                device_info.plugin.destroy()
                            i = self.tab_for_uid(device_info.uid)
                            self.tab_widget.removeTab(i)
                        except:
                            pass
                    
                if device_info.type == 'brick':
                    for port in device_info.bricklets:
                        if device_info.bricklets[port]:
                            if device_info.bricklets[port].uid == uid:
                                device_info.bricklets[port] = None
    
                try:
                    infos.infos.pop(uid)
                except:
                    pass
            
        self.update_tree_view()

    def cb_connected(self, connect_reason):
        self.update_ui_state()

        if connect_reason == IPConnection.CONNECT_REASON_REQUEST:
            self.ipcon.set_auto_reconnect(True)

            index = self.combo_host.findText(self.last_host)
            if index >= 0:
                self.combo_host.removeItem(index)
            self.combo_host.insertItem(-1, self.last_host)
            self.combo_host.setCurrentIndex(0)

            while self.combo_host.count() > HOST_HISTORY_SIZE:
                self.combo_host.removeItem(self.combo_host.count() - 1)

            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()
        elif connect_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT:
            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()

            QMessageBox.information(self, 'Connection',
                                    'Successfully reconnected!',
                                    QMessageBox.Ok)
        else:
            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()

    def cb_disconnected(self, disconnect_reason):
        if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST or not self.ipcon.get_auto_reconnect():
            self.update_ui_state()
        elif len(self.disconnect_times) >= 3 and self.disconnect_times[-3] < time.time() + 1:
            self.disconnect_times = []
            self.ipcon.set_auto_reconnect(False)
            self.update_ui_state()
            self.reset_view()

            QMessageBox.critical(self, 'Connection',
                                 'Stopped automatic reconnecting due to multiple connection errors in a row.',
                                 QMessageBox.Ok)
        else:
            self.disconnect_times.append(time.time())

            self.connect.setText('Abort Automatic Reconnecting')

            if disconnect_reason == IPConnection.DISCONNECT_REASON_ERROR:
                QMessageBox.critical(self, 'Connection',
                                     'Connection lost, an error occured!\n' +
                                     'Trying to reconnect.',
                                     QMessageBox.Ok)
            elif disconnect_reason == IPConnection.DISCONNECT_REASON_SHUTDOWN:
                QMessageBox.critical(self, 'Connection',
                                     'Connection lost, socket disconnected by server!\n' +
                                     'Trying to reconnect.',
                                     QMessageBox.Ok)

    def set_tree_view_defaults(self):
        self.tree_view_model.setHorizontalHeaderLabels(self.tree_view_model_labels)
        self.tree_view.expandAll()
        self.tree_view.setColumnWidth(0, 260)
        self.tree_view.setColumnWidth(1, 75)
        self.tree_view.setColumnWidth(2, 85)
        self.tree_view.setSortingEnabled(True)
        self.tree_view.header().setSortIndicator(0, Qt.AscendingOrder)

    def update_ui_state(self):
        connection_state = self.ipcon.get_connection_state()

        self.connect.setDisabled(False)

        if connection_state == IPConnection.CONNECTION_STATE_DISCONNECTED:
            self.connect.setText('Connect')
            self.button_advanced.setDisabled(True)
            self.combo_host.setDisabled(False)
            self.spinbox_port.setDisabled(False)
        elif connection_state == IPConnection.CONNECTION_STATE_CONNECTED:
            self.connect.setText("Disconnect")
            self.combo_host.setDisabled(True)
            self.spinbox_port.setDisabled(True)

    def update_tree_view(self):
        self.tree_view_model.clear()
        
        for device_info in sorted(infos.infos.values(), cmp=lambda x, y: cmp(x.name, y.name)):
            if device_info.type == 'brick':
                parent = [QStandardItem(device_info.name), 
                          QStandardItem(device_info.uid), 
                          QStandardItem('.'.join(map(str, device_info.firmware_version_installed)))]
                for item in parent:
                    item.setFlags(item.flags() & ~Qt.ItemIsEditable)

                self.tree_view_model.appendRow(parent)
                for port in sorted(device_info.bricklets):
                    if device_info.bricklets[port] and device_info.bricklets[port].protocol_version == 2:
                        child = [QStandardItem(port.upper() + ': ' +device_info.bricklets[port].name), 
                                 QStandardItem(device_info.bricklets[port].uid),
                                 QStandardItem('.'.join(map(str, device_info.bricklets[port].firmware_version_installed)))]
                        for item in child:
                            item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                        parent[0].appendRow(child)

        self.set_tree_view_defaults()        
        self.update_flashing_window()
        self.update_advanced_window()
        self.delayed_refresh_updates_timer.start()

    def update_flashing_window(self):
        if self.flashing_window is not None:
            self.flashing_window.update_bricks()

    def update_advanced_window(self):
        has_brick = False

        for info in infos.infos.values():
            if info.type == 'brick':
                has_brick = True

        self.button_advanced.setEnabled(has_brick)

        if self.advanced_window is not None:
            self.advanced_window.update_bricks()

    def delayed_refresh_updates(self):
        self.delayed_refresh_updates_timer.stop()

        if self.flashing_window is not None and self.flashing_window.isVisible():
            self.flashing_window.refresh_updates_pressed()