Exemplo n.º 1
0
class SolidStateRelayV2(COMCUPluginBase, Ui_SolidStateRelayV2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletSolidStateRelayV2, *args)

        self.setupUi(self)

        self.ssr = self.device

        self.state_combobox.setItemData(0, True)
        self.state_combobox.setItemData(1, False)

        self.monoflop = Monoflop(self.ssr, None, self.state_combobox,
                                 self.cb_state_change_by_monoflop,
                                 self.time_spinbox, None, self)

        self.ssr_button.clicked.connect(self.ssr_clicked)
        self.go_button.clicked.connect(self.go_clicked)

        self.a_pixmap = load_masked_pixmap(
            'plugin_system/plugins/solid_state_relay/relay_a.bmp')
        self.b_pixmap = load_masked_pixmap(
            'plugin_system/plugins/solid_state_relay/relay_b.bmp')

    def get_state_async(self, state):
        width = self.ssr_button.width()

        if self.ssr_button.minimumWidth() < width:
            self.ssr_button.setMinimumWidth(width)

        if state:
            self.ssr_button.setText('Switch Off')
            self.ssr_image.setPixmap(self.a_pixmap)
        else:
            self.ssr_button.setText('Switch On')
            self.ssr_image.setPixmap(self.b_pixmap)

    def start(self):
        async_call(self.ssr.get_state, None, self.get_state_async,
                   self.increase_error_count)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletSolidStateRelayV2.DEVICE_IDENTIFIER

    def ssr_clicked(self):
        width = self.ssr_button.width()

        if self.ssr_button.minimumWidth() < width:
            self.ssr_button.setMinimumWidth(width)

        state = 'On' in self.ssr_button.text().replace('&', '')

        if state:
            self.ssr_button.setText('Switch Off')
            self.ssr_image.setPixmap(self.a_pixmap)
        else:
            self.ssr_button.setText('Switch On')
            self.ssr_image.setPixmap(self.b_pixmap)

        async_call(self.ssr.set_state, state, None, self.increase_error_count)

    def go_clicked(self):
        self.monoflop.trigger()

    def cb_state_change_by_monoflop(self, state):
        if state:
            self.ssr_button.setText('Switch Off')
            self.ssr_image.setPixmap(self.a_pixmap)
        else:
            self.ssr_button.setText('Switch On')
            self.ssr_image.setPixmap(self.b_pixmap)
class IndustrialDigitalOut4V2(COMCUPluginBase, Ui_IndustrialDigitalOut4V2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIndustrialDigitalOut4V2, *args)

        self.setupUi(self)

        self.ido4 = self.device

        self.has_monoflop_abort = None

        self.pixmap_low = load_masked_pixmap('plugin_system/plugins/industrial_digital_out_4_v2/ido4_low.bmp')
        self.pixmap_high = load_masked_pixmap('plugin_system/plugins/industrial_digital_out_4_v2/ido4_high.bmp')

        self.btn_v_c = [self.btn_v_c0, self.btn_v_c1, self.btn_v_c2, self.btn_v_c3]
        self.lbl_s_i_c = [self.lbl_s_i_c0, self.lbl_s_i_c1, self.lbl_s_i_c2, self.lbl_s_i_c3]
        self.cbox_clc_c = [self.cbox_clc_c0, self.cbox_clc_c1, self.cbox_clc_c2, self.cbox_clc_c3]

        # Set initial channel status icon
        for lbl in self.lbl_s_i_c:
            lbl.setPixmap(self.pixmap_low)

        # Register value toggle button slots
        for c, b in enumerate(self.btn_v_c):
            b.clicked.connect(functools.partial(self.btn_v_c_clicked, c))

        # Monoflop
        self.cbox_m_c.currentIndexChanged.connect(self.cbox_m_c_changed)
        self.btn_m_go.clicked.connect(self.btn_m_go_clicked)

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(4):
            self.cbox_m_c.setItemData(i, i)

            monoflop_value = QComboBox()
            monoflop_value.addItem('High', True)
            monoflop_value.addItem('Low', False)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QSpinBox()
            monoflop_time.setRange(1, (1 << 31) - 1)
            monoflop_time.setValue(1000)

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.ido4,
                                 [0, 1, 2, 3],
                                 self.monoflop_values,
                                 self.cb_value_change_by_monoflop,
                                 self.monoflop_times,
                                 None,
                                 self)

        # Channel status LED config
        self.cbox_clc_c0.currentIndexChanged.connect(self.cbox_clc_c0_changed)
        self.cbox_clc_c1.currentIndexChanged.connect(self.cbox_clc_c1_changed)
        self.cbox_clc_c2.currentIndexChanged.connect(self.cbox_clc_c2_changed)
        self.cbox_clc_c3.currentIndexChanged.connect(self.cbox_clc_c3_changed)

    def get_value_async(self, value):
        for i, b in enumerate(self.btn_v_c):
            if value[i]:
                b.setText('Set Low')
                self.lbl_s_i_c[i].setPixmap(self.pixmap_high)
            else:
                b.setText('Set High')
                self.lbl_s_i_c[i].setPixmap(self.pixmap_low)

    def get_channel_led_config_async(self, channel, config):
        if channel == 0:
            self.cbox_clc_c0.setCurrentIndex(config)
        elif channel == 1:
            self.cbox_clc_c1.setCurrentIndex(config)
        elif channel == 2:
            self.cbox_clc_c2.setCurrentIndex(config)
        elif channel == 3:
            self.cbox_clc_c3.setCurrentIndex(config)

    def cbox_clc_c0_changed(self, config):
        self.ido4.set_channel_led_config(0, config)

    def cbox_clc_c1_changed(self, config):
        self.ido4.set_channel_led_config(1, config)

    def cbox_clc_c2_changed(self, config):
        self.ido4.set_channel_led_config(2, config)

    def cbox_clc_c3_changed(self, config):
        self.ido4.set_channel_led_config(3, config)

    def start(self):
        # the firmware version might change between init and start of a Co-MCU
        # Bricklet plugin, because a Co-MCU Bricklet can be restarted without
        # recreating the plugin. therefore, the firmware version has to be checked
        # on every start
        self.has_monoflop_abort = self.firmware_version >= (2, 0, 1)

        async_call(self.ido4.get_value, None, self.get_value_async, self.increase_error_count)

        for channel in range(4):
            async_call(self.ido4.get_channel_led_config, channel, self.get_channel_led_config_async, self.increase_error_count,
                       pass_arguments_to_result_callback=True)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialDigitalOut4V2.DEVICE_IDENTIFIER

    def btn_v_c_clicked(self, channel):
        value = 'High' in self.btn_v_c[channel].text().replace('&', '')

        if value:
            self.btn_v_c[channel].setText('Set Low')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_high)
        else:
            self.btn_v_c[channel].setText('Set High')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_low)

        if not self.has_monoflop_abort and self.monoflop.active(channel):
            # abuse monoflop to set selected value while also aborting an active
            # monoflop, because firmware version < 2.0.1 doesn't abort an active
            # monoflop if the set-value or set-selected-value function is called.
            # this workaround has the disadvantage of shortly inverting the
            # output value before settling on the requested value. that's why it
            # is only used if a monoflop is really active
            async_call(self.ido4.set_monoflop, (channel, not value, 0), None, self.increase_error_count)
        else:
            async_call(self.ido4.set_selected_value, (channel, value), None, self.increase_error_count)

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.btn_v_c[channel].setText('Set Low')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_high)
        else:
            self.btn_v_c[channel].setText('Set High')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_low)

    def cbox_m_c_changed(self):
        channel = self.cbox_m_c.currentIndex()

        if channel < 0:
            return

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

    def btn_m_go_clicked(self):
        channel = self.cbox_m_c.currentIndex()

        if channel < 0:
            return

        self.monoflop.trigger(channel)
Exemplo n.º 3
0
class IndustrialDigitalOut4(PluginBase, Ui_IndustrialDigitalOut4):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletIndustrialDigitalOut4, *args)

        self.setupUi(self)

        self.ido4 = self.device

        self.gnd_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_digital_out_4/dio_gnd.bmp')
        self.vcc_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_digital_out_4/dio_vcc.bmp')

        self.pin_buttons = [self.b0, self.b1, self.b2, self.b3, self.b4, self.b5, self.b6, self.b7, self.b8, self.b9, self.b10, self.b11, self.b12, self.b13, self.b14, self.b15]
        self.pin_button_icons = [self.b0_icon, self.b1_icon, self.b2_icon, self.b3_icon, self.b4_icon, self.b5_icon, self.b6_icon, self.b7_icon, self.b8_icon, self.b9_icon, self.b10_icon, self.b11_icon, self.b12_icon, self.b13_icon, self.b14_icon, self.b15_icon]
        self.pin_button_labels = [self.b0_label, self.b1_label, self.b2_label, self.b3_label, self.b4_label, self.b5_label, self.b6_label, self.b7_label, self.b8_label, self.b9_label, self.b10_label, self.b11_label, self.b12_label, self.b13_label, self.b14_label, self.b15_label]
        self.groups = [self.group0, self.group1, self.group2, self.group3]

        for icon in self.pin_button_icons:
            icon.setPixmap(self.gnd_pixmap)
            icon.show()

        self.lines = [[self.line0, self.line0a, self.line0b, self.line0c],
                      [self.line1, self.line1a, self.line1b, self.line1c],
                      [self.line2, self.line2a, self.line2b, self.line2c],
                      [self.line3, self.line3a, self.line3b, self.line3c]]

        for lines in self.lines:
            for line in lines:
                line.setVisible(False)

        self.available_ports = 0

        for i in range(len(self.pin_buttons)):
            self.pin_buttons[i].clicked.connect(functools.partial(self.pin_button_clicked, i))

        self.monoflop_states = []
        self.monoflop_times = []

        for i in range(16):
            monoflop_state = QComboBox()
            monoflop_state.addItem('High', 1)
            monoflop_state.addItem('Low', 0)

            self.monoflop_states.append(monoflop_state)
            self.monoflop_state_stack.addWidget(monoflop_state)

            monoflop_time = QSpinBox()
            monoflop_time.setRange(1, (1 << 31) - 1)
            monoflop_time.setValue(1000)

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.ido4,
                                 list(range(16)),
                                 self.monoflop_states,
                                 self.cb_state_change_by_monoflop,
                                 self.monoflop_times,
                                 None,
                                 self,
                                 setter_uses_bitmasks=True,
                                 callback_uses_bitmasks=True,
                                 handle_get_monoflop_invalid_parameter_as_abort=True)

        self.set_group.clicked.connect(self.set_group_clicked)

        self.monoflop_pin.currentIndexChanged.connect(self.monoflop_pin_changed)
        self.monoflop_go.clicked.connect(self.monoflop_go_clicked)

    def start(self):
        self.reconfigure_everything()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialDigitalOut4.DEVICE_IDENTIFIER

    def get_value_async(self, value_mask):
        for pin in range(16):
            if value_mask & (1 << pin):
                self.pin_buttons[pin].setText('Switch Low')
                self.pin_button_icons[pin].setPixmap(self.vcc_pixmap)
            else:
                self.pin_buttons[pin].setText('Switch High')
                self.pin_button_icons[pin].setPixmap(self.gnd_pixmap)

    def get_group_async(self, group):
        for i in range(4):
            if group[i] == 'n':
                self.groups[i].setCurrentIndex(0)
            else:
                item = 'Port ' + group[i].upper()
                index = self.groups[i].findText(item, Qt.MatchStartsWith)

                if index == -1:
                    self.groups[i].setCurrentIndex(0)
                else:
                    self.groups[i].setCurrentIndex(index)

        self.monoflop_pin.clear()

        if group[0] == 'n' and group[1] == 'n' and group[2] == 'n' and group[3] == 'n':
            self.show_buttons(0)
            self.hide_buttons(1)
            self.hide_buttons(2)
            self.hide_buttons(3)

            for pin in range(4):
                self.monoflop_pin.addItem('Pin {0}'.format(pin), pin)
        else:
            for i in range(4):
                if group[i] == 'n':
                    self.hide_buttons(i)
                else:
                    for j in range(4):
                        pin = i * 4 + j

                        self.monoflop_pin.addItem('Pin {0}'.format(pin), pin)

                    self.show_buttons(i)

        self.monoflop_pin.setCurrentIndex(0)

        async_call(self.ido4.get_value, None, self.get_value_async, self.increase_error_count)

        self.monoflop.start()

    def get_available_for_group_aysnc(self, available_ports):
        self.available_ports = available_ports

        for i in range(4):
            self.groups[i].clear()
            self.groups[i].addItem('Off')

            for j in range(4):
                if self.available_ports & (1 << j):
                    item = 'Port ' + chr(ord('A') + j)
                    self.groups[i].addItem(item)

        async_call(self.ido4.get_group, None, self.get_group_async, self.increase_error_count)

    def reconfigure_everything(self):
        async_call(self.ido4.get_available_for_group, None, self.get_available_for_group_aysnc, self.increase_error_count)

    def show_buttons(self, num):
        for i in range(num * 4, (num + 1) * 4):
            self.pin_buttons[i].setVisible(True)
            self.pin_button_icons[i].setVisible(True)
            self.pin_button_labels[i].setVisible(True)

        for line in self.lines[num]:
            line.setVisible(True)

    def hide_buttons(self, num):
        for i in range(num * 4, (num + 1) * 4):
            self.pin_buttons[i].setVisible(False)
            self.pin_button_icons[i].setVisible(False)
            self.pin_button_labels[i].setVisible(False)

        for line in self.lines[num]:
            line.setVisible(False)

    def set_group_clicked(self):
        group = ['n', 'n', 'n', 'n']

        for i in range(len(self.groups)):
            text = self.groups[i].currentText()
            if 'Port A' in text:
                group[i] = 'a'
            elif 'Port B' in text:
                group[i] = 'b'
            elif 'Port C' in text:
                group[i] = 'c'
            elif 'Port D' in text:
                group[i] = 'd'

        if group != ['n', 'n', 'n', 'n']:
            abort_group = group
        else:
            abort_group = ['x', 'n', 'n', 'n']

        for i, g in enumerate(abort_group):
            if g == 'n':
                for j in range(4):
                    pin = i * 4 + j

                    # changing grouping doesn't abort active monoflops. manually
                    # abort tracking for monoflops that are out of scope now
                    self.monoflop.abort_tracking(pin)

        self.ido4.set_group(group)
        self.reconfigure_everything()

    def pin_button_clicked(self, button):
        selection = 1 << button
        value = 0

        if 'High' in self.pin_buttons[button].text().replace('&', ''):
            value |= 1 << button
            self.pin_buttons[button].setText('Switch Low')
            self.pin_button_icons[button].setPixmap(self.vcc_pixmap)
        else:
            self.pin_buttons[button].setText('Switch High')
            self.pin_button_icons[button].setPixmap(self.gnd_pixmap)

        async_call(self.ido4.set_selected_values, (selection, value), None, self.increase_error_count)

    def cb_state_change_by_monoflop(self, pin, state):
        if state:
            self.pin_buttons[pin].setText('Switch Low')
            self.pin_button_icons[pin].setPixmap(self.vcc_pixmap)
        else:
            self.pin_buttons[pin].setText('Switch High')
            self.pin_button_icons[pin].setPixmap(self.gnd_pixmap)

    def monoflop_pin_changed(self):
        pin = self.monoflop_pin.currentData()

        if pin == None:
            return

        self.monoflop_time_stack.setCurrentIndex(pin)
        self.monoflop_state_stack.setCurrentIndex(pin)

    def monoflop_go_clicked(self):
        pin = self.monoflop_pin.currentData()

        if pin == None:
            return

        self.monoflop.trigger(pin)
class IndustrialQuadRelayV2(COMCUPluginBase, Ui_IndustrialQuadRelayV2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIndustrialQuadRelayV2, *args)

        self.setupUi(self)

        self.iqr = self.device

        self.open_pixmap = load_masked_pixmap(
            'plugin_system/plugins/industrial_quad_relay/relay_open.bmp')
        self.close_pixmap = load_masked_pixmap(
            'plugin_system/plugins/industrial_quad_relay/relay_close.bmp')

        self.relay_buttons = [self.b0, self.b1, self.b2, self.b3]
        self.relay_button_icons = [
            self.b0_icon, self.b1_icon, self.b2_icon, self.b3_icon
        ]
        self.relay_button_labels = [
            self.b0_label, self.b1_label, self.b2_label, self.b3_label
        ]

        for icon in self.relay_button_icons:
            icon.setPixmap(self.open_pixmap)
            icon.show()

        for i in range(len(self.relay_buttons)):
            self.relay_buttons[i].clicked.connect(
                functools.partial(self.relay_button_clicked, i))

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(4):
            self.monoflop_channel.setItemData(i, i)

            monoflop_value = QComboBox()
            monoflop_value.addItem('On', True)
            monoflop_value.addItem('Off', False)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QSpinBox()
            monoflop_time.setRange(1, (1 << 31) - 1)
            monoflop_time.setValue(1000)

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.iqr, [0, 1, 2, 3], self.monoflop_values,
                                 self.cb_value_change_by_monoflop,
                                 self.monoflop_times, None, self)

        self.monoflop_channel.currentIndexChanged.connect(
            self.monoflop_channel_changed)
        self.monoflop_go.clicked.connect(self.monoflop_go_clicked)

        self.cbox_cs0_cfg.currentIndexChanged.connect(
            self.cbox_cs0_cfg_changed)
        self.cbox_cs1_cfg.currentIndexChanged.connect(
            self.cbox_cs1_cfg_changed)
        self.cbox_cs2_cfg.currentIndexChanged.connect(
            self.cbox_cs2_cfg_changed)
        self.cbox_cs3_cfg.currentIndexChanged.connect(
            self.cbox_cs3_cfg_changed)

    def get_value_async(self, value):
        for button in range(4):
            if value[button]:
                self.relay_buttons[button].setText('Switch Off')
                self.relay_button_icons[button].setPixmap(self.close_pixmap)
            else:
                self.relay_buttons[button].setText('Switch On')
                self.relay_button_icons[button].setPixmap(self.open_pixmap)

    def get_channel_led_config_async(self, idx, cfg):
        if idx == 0:
            self.cbox_cs0_cfg.setCurrentIndex(cfg)
        elif idx == 1:
            self.cbox_cs1_cfg.setCurrentIndex(cfg)
        elif idx == 2:
            self.cbox_cs2_cfg.setCurrentIndex(cfg)
        elif idx == 3:
            self.cbox_cs3_cfg.setCurrentIndex(cfg)

    def cbox_cs0_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(0, idx)

    def cbox_cs1_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(1, idx)

    def cbox_cs2_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(2, idx)

    def cbox_cs3_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(3, idx)

    def start(self):
        async_call(self.iqr.get_value, None, self.get_value_async,
                   self.increase_error_count)

        for channel in range(4):
            async_call(self.iqr.get_channel_led_config,
                       channel,
                       self.get_channel_led_config_async,
                       self.increase_error_count,
                       pass_arguments_to_result_callback=True)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialQuadRelayV2.DEVICE_IDENTIFIER

    def relay_button_clicked(self, button):
        value = 'On' in self.relay_buttons[button].text().replace('&', '')

        if value:
            self.relay_buttons[button].setText('Switch Off')
            self.relay_button_icons[button].setPixmap(self.close_pixmap)
        else:
            self.relay_buttons[button].setText('Switch On')
            self.relay_button_icons[button].setPixmap(self.open_pixmap)

        self.iqr.set_selected_value(button, value)

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.relay_buttons[channel].setText('Switch Off')
            self.relay_button_icons[channel].setPixmap(self.close_pixmap)
        else:
            self.relay_buttons[channel].setText('Switch On')
            self.relay_button_icons[channel].setPixmap(self.open_pixmap)

    def monoflop_channel_changed(self):
        channel = self.monoflop_channel.currentData()

        if channel == None:
            return

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

    def monoflop_go_clicked(self):
        channel = self.monoflop_channel.currentData()

        if channel == None:
            return

        self.monoflop.trigger(channel)
Exemplo n.º 5
0
class IO16V2(COMCUPluginBase, Ui_IO16V2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIO16V2, *args)

        self.setupUi(self)

        self.io = self.device

        self.io.set_response_expected(self.io.FUNCTION_SET_CONFIGURATION, True)

        self.cbe_value = CallbackEmulator(self.io.get_value, None,
                                          self.cb_value,
                                          self.increase_error_count)

        self.config_direction = [None] * 16
        self.config_value = [None] * 16

        self.lbl_st_ch_v = [
            self.lbl_st_ch0_v, self.lbl_st_ch1_v, self.lbl_st_ch2_v,
            self.lbl_st_ch3_v, self.lbl_st_ch4_v, self.lbl_st_ch5_v,
            self.lbl_st_ch6_v, self.lbl_st_ch7_v, self.lbl_st_ch8_v,
            self.lbl_st_ch9_v, self.lbl_st_ch10_v, self.lbl_st_ch11_v,
            self.lbl_st_ch12_v, self.lbl_st_ch13_v, self.lbl_st_ch14_v,
            self.lbl_st_ch15_v
        ]

        self.lbl_st_ch_d = [
            self.lbl_st_ch0_d, self.lbl_st_ch1_d, self.lbl_st_ch2_d,
            self.lbl_st_ch3_d, self.lbl_st_ch4_d, self.lbl_st_ch5_d,
            self.lbl_st_ch6_d, self.lbl_st_ch7_d, self.lbl_st_ch8_d,
            self.lbl_st_ch9_d, self.lbl_st_ch10_d, self.lbl_st_ch11_d,
            self.lbl_st_ch12_d, self.lbl_st_ch13_d, self.lbl_st_ch14_d,
            self.lbl_st_ch15_d
        ]

        self.lbl_st_ch_cfg = [
            self.lbl_st_ch0_cfg, self.lbl_st_ch1_cfg, self.lbl_st_ch2_cfg,
            self.lbl_st_ch3_cfg, self.lbl_st_ch4_cfg, self.lbl_st_ch5_cfg,
            self.lbl_st_ch6_cfg, self.lbl_st_ch7_cfg, self.lbl_st_ch8_cfg,
            self.lbl_st_ch9_cfg, self.lbl_st_ch10_cfg, self.lbl_st_ch11_cfg,
            self.lbl_st_ch12_cfg, self.lbl_st_ch13_cfg, self.lbl_st_ch14_cfg,
            self.lbl_st_ch15_cfg
        ]

        self.lbl_st_ch_monoflop_t = [
            self.lbl_st_ch0_monoflop_t, self.lbl_st_ch1_monoflop_t,
            self.lbl_st_ch2_monoflop_t, self.lbl_st_ch3_monoflop_t,
            self.lbl_st_ch4_monoflop_t, self.lbl_st_ch5_monoflop_t,
            self.lbl_st_ch6_monoflop_t, self.lbl_st_ch7_monoflop_t,
            self.lbl_st_ch8_monoflop_t, self.lbl_st_ch9_monoflop_t,
            self.lbl_st_ch10_monoflop_t, self.lbl_st_ch11_monoflop_t,
            self.lbl_st_ch12_monoflop_t, self.lbl_st_ch13_monoflop_t,
            self.lbl_st_ch14_monoflop_t, self.lbl_st_ch15_monoflop_t
        ]

        self.cbox_cfg_ch_dir.setItemData(0, self.io.DIRECTION_IN)
        self.cbox_cfg_ch_dir.setItemData(1, self.io.DIRECTION_OUT)

        self.cbox_cfg_ch_v.setItemData(0, True)
        self.cbox_cfg_ch_v.setItemData(1, False)

        self.btn_monoflop_go.clicked.connect(self.btn_monoflop_go_clicked)
        self.btn_cfg_ch_save.clicked.connect(self.btn_cfg_ch_save_clicked)
        self.cbox_cfg_ch.currentIndexChanged.connect(self.cbox_cfg_ch_changed)
        self.cbox_cfg_ch_dir.currentIndexChanged.connect(
            self.cbox_cfg_ch_dir_changed)

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(16):
            monoflop_value = QComboBox()
            monoflop_value.addItem('High', 1)
            monoflop_value.addItem('Low', 0)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QDoubleSpinBox()

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(
            self.io,
            list(range(16)),
            self.monoflop_values,
            self.cb_value_change_by_monoflop,
            self.monoflop_times,
            self.lbl_st_ch_monoflop_t,
            self,
            handle_get_monoflop_invalid_parameter_as_abort=True)

    def get_configuration_async(self, channel, direction, value):
        self.config_direction[channel] = direction
        self.config_value[channel] = value

        if direction == self.io.DIRECTION_IN:
            self.lbl_st_ch_d[channel].setText('Input')

            if value:
                self.lbl_st_ch_cfg[channel].setText('Pull-Up')
            else:
                self.lbl_st_ch_cfg[channel].setText('Default')
        else:
            self.lbl_st_ch_d[channel].setText('Output')
            self.lbl_st_ch_cfg[channel].setText('-')

        if None not in self.config_direction:  # got all channel data
            self.cbox_cfg_ch_changed(self.cbox_cfg_ch.currentIndex())

    def start(self):
        self.config_direction = [None] * 16
        self.config_value = [None] * 16

        for channel in range(16):
            async_call(self.io.get_configuration,
                       channel,
                       self.get_configuration_async,
                       self.increase_error_count,
                       pass_arguments_to_result_callback=True,
                       expand_result_tuple_for_callback=True)

        self.cbe_value.set_period(50)

        self.monoflop.start()

    def stop(self):
        self.cbe_value.set_period(0)

        self.monoflop.stop()

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIO16V2.DEVICE_IDENTIFIER

    def cb_value(self, value):
        for i in range(16):
            if value[i]:
                self.lbl_st_ch_v[i].setText('High')
            else:
                self.lbl_st_ch_v[i].setText('Low')

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.lbl_st_ch_v[channel].setText('High')
        else:
            self.lbl_st_ch_v[channel].setText('Low')

    def btn_monoflop_go_clicked(self):
        channel = self.cbox_cfg_ch.currentIndex()

        if channel < 0:
            return

        self.monoflop.trigger(channel)

    def btn_cfg_ch_save_clicked(self):
        channel = self.cbox_cfg_ch.currentIndex()
        direction = self.cbox_cfg_ch_dir.currentData()
        value = self.cbox_cfg_ch_v.currentData()

        if channel < 0 or direction == None or value == None:
            return

        async_call(self.io.set_configuration, (channel, direction, value),
                   None,
                   self.increase_error_count,
                   pass_arguments_to_result_callback=True,
                   expand_arguments_tuple_for_callback=True)
        async_call(self.io.get_configuration,
                   channel,
                   self.get_configuration_async,
                   self.increase_error_count,
                   pass_arguments_to_result_callback=True,
                   expand_result_tuple_for_callback=True)

    def cbox_cfg_ch_changed(self, channel):
        if channel < 0:
            return

        direction = self.config_direction[channel]
        direction_index = self.cbox_cfg_ch_dir.findData(direction)

        self.cbox_cfg_ch_dir.setCurrentIndex(direction_index)
        self.cbox_cfg_ch_dir_changed(direction_index)

        value = self.config_value[channel]
        value_index = self.cbox_cfg_ch_v.findData(value)

        self.cbox_cfg_ch_v.setCurrentIndex(value_index)

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

        self.btn_monoflop_go.setEnabled(direction == self.io.DIRECTION_OUT)

    def cbox_cfg_ch_dir_changed(self, index):
        channel = self.cbox_cfg_ch.currentIndex()
        direction = self.cbox_cfg_ch_dir.currentData()

        if channel < 0 or direction == None:
            return

        self.cbox_cfg_ch_v.clear()

        if direction == self.io.DIRECTION_IN:
            self.lbl_cfg_ch_v.setText('Configuration:')
            self.cbox_cfg_ch_v.addItem('Pull-Up', True)
            self.cbox_cfg_ch_v.addItem('Default', False)
        else:
            self.lbl_cfg_ch_v.setText('Value:')
            self.cbox_cfg_ch_v.addItem('High', True)
            self.cbox_cfg_ch_v.addItem('Low', False)

        value = self.config_value[channel]
        value_index = self.cbox_cfg_ch_v.findData(value)

        self.cbox_cfg_ch_v.setCurrentIndex(value_index)
Exemplo n.º 6
0
class IO4V2(COMCUPluginBase, Ui_IO4V2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIO4V2, *args)

        self.setupUi(self)

        self.io = self.device

        self.has_monoflop_abort_by_set_configuration = None

        self.io.set_response_expected(self.io.FUNCTION_SET_CONFIGURATION, True)

        self.cbe_value = CallbackEmulator(self.io.get_value, None,
                                          self.cb_value,
                                          self.increase_error_count)

        self.config_direction = [None] * 4
        self.config_value = [None] * 4

        self.lbl_st_ch_v = [
            self.lbl_st_ch0_v, self.lbl_st_ch1_v, self.lbl_st_ch2_v,
            self.lbl_st_ch3_v
        ]

        self.lbl_st_ch_d = [
            self.lbl_st_ch0_d, self.lbl_st_ch1_d, self.lbl_st_ch2_d,
            self.lbl_st_ch3_d
        ]

        self.lbl_st_ch_cfg = [
            self.lbl_st_ch0_cfg, self.lbl_st_ch1_cfg, self.lbl_st_ch2_cfg,
            self.lbl_st_ch3_cfg
        ]

        self.lbl_st_ch_monoflop_t = [
            self.lbl_st_ch0_monoflop_t, self.lbl_st_ch1_monoflop_t,
            self.lbl_st_ch2_monoflop_t, self.lbl_st_ch3_monoflop_t
        ]

        self.cbox_cfg_ch_dir.setItemData(0, self.io.DIRECTION_IN)
        self.cbox_cfg_ch_dir.setItemData(1, self.io.DIRECTION_OUT)

        self.cbox_cfg_ch_v.setItemData(0, True)
        self.cbox_cfg_ch_v.setItemData(1, False)

        self.btn_monoflop_go.clicked.connect(self.btn_monoflop_go_clicked)
        self.btn_cfg_ch_save.clicked.connect(self.btn_cfg_ch_save_clicked)
        self.cbox_cfg_ch.currentIndexChanged.connect(self.cbox_cfg_ch_changed)
        self.cbox_cfg_ch_dir.currentIndexChanged.connect(
            self.cbox_cfg_ch_dir_changed)

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(4):
            monoflop_value = QComboBox()
            monoflop_value.addItem('High', 1)
            monoflop_value.addItem('Low', 0)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QSpinBox()
            monoflop_time.setRange(1, (1 << 31) - 1)
            monoflop_time.setValue(1000)

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(
            self.io, [0, 1, 2, 3],
            self.monoflop_values,
            self.cb_value_change_by_monoflop,
            self.monoflop_times,
            self.lbl_st_ch_monoflop_t,
            self,
            handle_get_monoflop_invalid_parameter_as_abort=True)

    def get_configuration_async(self, channel, direction, value):
        self.config_direction[channel] = direction
        self.config_value[channel] = value

        if direction == self.io.DIRECTION_IN:
            self.lbl_st_ch_d[channel].setText('Input')

            if value:
                self.lbl_st_ch_cfg[channel].setText('Pull-Up')
            else:
                self.lbl_st_ch_cfg[channel].setText('Default')
        else:
            self.lbl_st_ch_d[channel].setText('Output')
            self.lbl_st_ch_cfg[channel].setText('-')

        if None not in self.config_direction:  # got all channel data
            self.cbox_cfg_ch_changed(self.cbox_cfg_ch.currentIndex())

    def start(self):
        # the firmware version might change between init and start of a Co-MCU
        # Bricklet plugin, because a Co-MCU Bricklet can be restarted without
        # recreating the plugin. therefore, the firmware version has to be checked
        # on every start
        self.has_monoflop_abort_by_set_configuration = self.firmware_version >= (
            2, 0, 3)

        self.config_direction = [None] * 4
        self.config_value = [None] * 4

        for channel in range(4):
            async_call(self.io.get_configuration,
                       channel,
                       self.get_configuration_async,
                       self.increase_error_count,
                       pass_arguments_to_result_callback=True,
                       expand_result_tuple_for_callback=True)

        self.cbe_value.set_period(50)

        self.monoflop.start()

    def stop(self):
        self.cbe_value.set_period(0)

        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIO4V2.DEVICE_IDENTIFIER

    def cb_value(self, value):
        for i in range(4):
            if value[i]:
                self.lbl_st_ch_v[i].setText('High')
            else:
                self.lbl_st_ch_v[i].setText('Low')

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.lbl_st_ch_v[channel].setText('High')
        else:
            self.lbl_st_ch_v[channel].setText('Low')

    def btn_monoflop_go_clicked(self):
        channel = self.cbox_cfg_ch.currentIndex()

        if channel < 0:
            return

        self.monoflop.trigger(channel)

    def set_configuration_async(self, channel, direction, value):
        if not self.has_monoflop_abort_by_set_configuration and direction == self.io.DIRECTION_OUT and self.monoflop.active(
                channel):
            # the set-configuration function in firmware version < 2.0.3 doesn't
            # abort monoflops, call the set-selected-value that does abort an active monoflop
            async_call(self.io.set_selected_value, (channel, value), None,
                       self.increase_error_count)

    def btn_cfg_ch_save_clicked(self):
        channel = self.cbox_cfg_ch.currentIndex()
        direction = self.cbox_cfg_ch_dir.currentData()
        value = self.cbox_cfg_ch_v.currentData()

        if channel < 0 or direction == None or value == None:
            return

        async_call(self.io.set_configuration, (channel, direction, value),
                   self.set_configuration_async,
                   self.increase_error_count,
                   pass_arguments_to_result_callback=True,
                   expand_arguments_tuple_for_callback=True)
        async_call(self.io.get_configuration,
                   channel,
                   self.get_configuration_async,
                   self.increase_error_count,
                   pass_arguments_to_result_callback=True,
                   expand_result_tuple_for_callback=True)

    def cbox_cfg_ch_changed(self, channel):
        if channel < 0:
            return

        direction = self.config_direction[channel]
        direction_index = self.cbox_cfg_ch_dir.findData(direction)

        self.cbox_cfg_ch_dir.setCurrentIndex(direction_index)
        self.cbox_cfg_ch_dir_changed(direction_index)

        value = self.config_value[channel]
        value_index = self.cbox_cfg_ch_v.findData(value)

        self.cbox_cfg_ch_v.setCurrentIndex(value_index)

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

        self.btn_monoflop_go.setEnabled(direction == self.io.DIRECTION_OUT)

    def cbox_cfg_ch_dir_changed(self, index):
        channel = self.cbox_cfg_ch.currentIndex()
        direction = self.cbox_cfg_ch_dir.currentData()

        if channel < 0 or direction == None:
            return

        self.cbox_cfg_ch_v.clear()

        if direction == self.io.DIRECTION_IN:
            self.lbl_cfg_ch_v.setText('Configuration:')
            self.cbox_cfg_ch_v.addItem('Pull-Up', True)
            self.cbox_cfg_ch_v.addItem('Default', False)
        else:
            self.lbl_cfg_ch_v.setText('Value:')
            self.cbox_cfg_ch_v.addItem('High', True)
            self.cbox_cfg_ch_v.addItem('Low', False)

        value = self.config_value[channel]
        value_index = self.cbox_cfg_ch_v.findData(value)

        self.cbox_cfg_ch_v.setCurrentIndex(value_index)
Exemplo n.º 7
0
class SolidStateRelayV2(COMCUPluginBase, Ui_SolidStateRelayV2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletSolidStateRelayV2, *args)

        self.setupUi(self)

        self.ssr = self.device

        self.state_combobox.setItemData(0, True)
        self.state_combobox.setItemData(1, False)

        self.monoflop = Monoflop(self.ssr,
                                 None,
                                 self.state_combobox,
                                 self.cb_state_change_by_monoflop,
                                 self.time_spinbox,
                                 None,
                                 self)

        self.ssr_button.clicked.connect(self.ssr_clicked)
        self.go_button.clicked.connect(self.go_clicked)

        self.a_pixmap = load_masked_pixmap('plugin_system/plugins/solid_state_relay/relay_a.bmp')
        self.b_pixmap = load_masked_pixmap('plugin_system/plugins/solid_state_relay/relay_b.bmp')

    def get_state_async(self, state):
        width = self.ssr_button.width()

        if self.ssr_button.minimumWidth() < width:
            self.ssr_button.setMinimumWidth(width)

        if state:
            self.ssr_button.setText('Switch Off')
            self.ssr_image.setPixmap(self.a_pixmap)
        else:
            self.ssr_button.setText('Switch On')
            self.ssr_image.setPixmap(self.b_pixmap)

    def start(self):
        async_call(self.ssr.get_state, None, self.get_state_async, self.increase_error_count)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletSolidStateRelayV2.DEVICE_IDENTIFIER

    def ssr_clicked(self):
        width = self.ssr_button.width()

        if self.ssr_button.minimumWidth() < width:
            self.ssr_button.setMinimumWidth(width)

        state = 'On' in self.ssr_button.text().replace('&', '')

        if state:
            self.ssr_button.setText('Switch Off')
            self.ssr_image.setPixmap(self.a_pixmap)
        else:
            self.ssr_button.setText('Switch On')
            self.ssr_image.setPixmap(self.b_pixmap)

        async_call(self.ssr.set_state, state, None, self.increase_error_count)

    def go_clicked(self):
        self.monoflop.trigger()

    def cb_state_change_by_monoflop(self, state):
        if state:
            self.ssr_button.setText('Switch Off')
            self.ssr_image.setPixmap(self.a_pixmap)
        else:
            self.ssr_button.setText('Switch On')
            self.ssr_image.setPixmap(self.b_pixmap)
Exemplo n.º 8
0
class IndustrialDualRelay(COMCUPluginBase, Ui_IndustrialDualRelay):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIndustrialDualRelay, *args)

        self.setupUi(self)

        self.idr = self.device

        self.value0_combobox.setItemData(0, True)
        self.value0_combobox.setItemData(1, False)

        self.value1_combobox.setItemData(0, True)
        self.value1_combobox.setItemData(1, False)

        self.monoflop = Monoflop(self.idr,
                                 [0, 1],
                                 [self.value0_combobox, self.value1_combobox],
                                 self.cb_value_change_by_monoflop,
                                 [self.time0_spinbox, self.time1_spinbox],
                                 None,
                                 self)

        self.ch0_button.clicked.connect(self.ch0_clicked)
        self.ch1_button.clicked.connect(self.ch1_clicked)

        self.go0_button.clicked.connect(self.go0_clicked)
        self.go1_button.clicked.connect(self.go1_clicked)

        self.a0_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_dual_relay/channel0_a.bmp')
        self.a1_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_dual_relay/channel1_a.bmp')
        self.b0_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_dual_relay/channel0_b.bmp')
        self.b1_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_dual_relay/channel1_b.bmp')

    def get_value_async(self, value):
        width = self.ch0_button.width()

        if self.ch0_button.minimumWidth() < width:
            self.ch0_button.setMinimumWidth(width)

        width = self.ch1_button.width()

        if self.ch1_button.minimumWidth() < width:
            self.ch1_button.setMinimumWidth(width)

        ch0, ch1 = value

        if ch0:
            self.ch0_button.setText('Switch Off')
            self.ch0_image.setPixmap(self.a0_pixmap)
        else:
            self.ch0_button.setText('Switch On')
            self.ch0_image.setPixmap(self.b0_pixmap)

        if ch1:
            self.ch1_button.setText('Switch Off')
            self.ch1_image.setPixmap(self.a1_pixmap)
        else:
            self.ch1_button.setText('Switch On')
            self.ch1_image.setPixmap(self.b1_pixmap)

    def start(self):
        async_call(self.idr.get_value, None, self.get_value_async, self.increase_error_count)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialDualRelay.DEVICE_IDENTIFIER

    def ch0_clicked(self):
        width = self.ch0_button.width()

        if self.ch0_button.minimumWidth() < width:
            self.ch0_button.setMinimumWidth(width)

        value = 'On' in self.ch0_button.text().replace('&', '')

        if value:
            self.ch0_button.setText('Switch Off')
            self.ch0_image.setPixmap(self.a0_pixmap)
        else:
            self.ch0_button.setText('Switch On')
            self.ch0_image.setPixmap(self.b0_pixmap)

        async_call(self.idr.set_selected_value, (0, value), None, self.increase_error_count)

    def ch1_clicked(self):
        width = self.ch1_button.width()

        if self.ch1_button.minimumWidth() < width:
            self.ch1_button.setMinimumWidth(width)

        value = 'On' in self.ch1_button.text().replace('&', '')

        if value:
            self.ch1_button.setText('Switch Off')
            self.ch1_image.setPixmap(self.a1_pixmap)
        else:
            self.ch1_button.setText('Switch On')
            self.ch1_image.setPixmap(self.b1_pixmap)

        async_call(self.idr.set_selected_value, (1, value), None, self.increase_error_count)

    def go0_clicked(self):
        self.monoflop.trigger(0)

    def go1_clicked(self):
        self.monoflop.trigger(1)

    def cb_value_change_by_monoflop(self, channel, value):
        if channel == 0:
            if value:
                self.ch0_button.setText('Switch Off')
                self.ch0_image.setPixmap(self.a0_pixmap)
            else:
                self.ch0_button.setText('Switch On')
                self.ch0_image.setPixmap(self.b0_pixmap)
        elif channel == 1:
            if value:
                self.ch1_button.setText('Switch Off')
                self.ch1_image.setPixmap(self.a1_pixmap)
            else:
                self.ch1_button.setText('Switch On')
                self.ch1_image.setPixmap(self.b1_pixmap)
Exemplo n.º 9
0
class DualRelay(PluginBase, Ui_DualRelay):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletDualRelay, *args)

        self.setupUi(self)

        self.dr = self.device

        self.state1_combobox.setItemData(0, True)
        self.state1_combobox.setItemData(1, False)

        self.state2_combobox.setItemData(0, True)
        self.state2_combobox.setItemData(1, False)

        self.monoflop = Monoflop(self.dr, [1, 2],
                                 [self.state1_combobox, self.state2_combobox],
                                 self.cb_state_change_by_monoflop,
                                 [self.time1_spinbox, self.time2_spinbox],
                                 None, self)

        self.dr1_button.clicked.connect(self.dr1_clicked)
        self.dr2_button.clicked.connect(self.dr2_clicked)

        self.go1_button.clicked.connect(self.go1_clicked)
        self.go2_button.clicked.connect(self.go2_clicked)

        self.a1_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_a1.bmp')
        self.a2_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_a2.bmp')
        self.b1_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_b1.bmp')
        self.b2_pixmap = load_masked_pixmap(
            'plugin_system/plugins/dual_relay/relay_b2.bmp')

    def get_state_async(self, dr1, dr2):
        width = self.dr1_button.width()

        if self.dr1_button.minimumWidth() < width:
            self.dr1_button.setMinimumWidth(width)

        width = self.dr2_button.width()

        if self.dr2_button.minimumWidth() < width:
            self.dr2_button.setMinimumWidth(width)

        if dr1:
            self.dr1_button.setText('Switch Off')
            self.dr1_image.setPixmap(self.a1_pixmap)
        else:
            self.dr1_button.setText('Switch On')
            self.dr1_image.setPixmap(self.b1_pixmap)

        if dr2:
            self.dr2_button.setText('Switch Off')
            self.dr2_image.setPixmap(self.a2_pixmap)
        else:
            self.dr2_button.setText('Switch On')
            self.dr2_image.setPixmap(self.b2_pixmap)

    def start(self):
        async_call(self.dr.get_state,
                   None,
                   self.get_state_async,
                   self.increase_error_count,
                   expand_result_tuple_for_callback=True)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletDualRelay.DEVICE_IDENTIFIER

    def dr1_clicked(self):
        width = self.dr1_button.width()

        if self.dr1_button.minimumWidth() < width:
            self.dr1_button.setMinimumWidth(width)

        state = 'On' in self.dr1_button.text().replace('&', '')

        if state:
            self.dr1_button.setText('Switch Off')
            self.dr1_image.setPixmap(self.a1_pixmap)
        else:
            self.dr1_button.setText('Switch On')
            self.dr1_image.setPixmap(self.b1_pixmap)

        async_call(self.dr.set_selected_state, (1, state), None,
                   self.increase_error_count)

    def dr2_clicked(self):
        width = self.dr2_button.width()

        if self.dr2_button.minimumWidth() < width:
            self.dr2_button.setMinimumWidth(width)

        state = 'On' in self.dr2_button.text().replace('&', '')

        if state:
            self.dr2_button.setText('Switch Off')
            self.dr2_image.setPixmap(self.a2_pixmap)
        else:
            self.dr2_button.setText('Switch On')
            self.dr2_image.setPixmap(self.b2_pixmap)

        async_call(self.dr.set_selected_state, (2, state), None,
                   self.increase_error_count)

    def go1_clicked(self):
        self.monoflop.trigger(1)

    def go2_clicked(self):
        self.monoflop.trigger(2)

    def cb_state_change_by_monoflop(self, relay, state):
        if relay == 1:
            if state:
                self.dr1_button.setText('Switch Off')
                self.dr1_image.setPixmap(self.a1_pixmap)
            else:
                self.dr1_button.setText('Switch On')
                self.dr1_image.setPixmap(self.b1_pixmap)
        elif relay == 2:
            if state:
                self.dr2_button.setText('Switch Off')
                self.dr2_image.setPixmap(self.a2_pixmap)
            else:
                self.dr2_button.setText('Switch On')
                self.dr2_image.setPixmap(self.b2_pixmap)
Exemplo n.º 10
0
class DualRelay(PluginBase, Ui_DualRelay):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletDualRelay, *args)

        self.setupUi(self)

        self.dr = self.device

        self.state1_combobox.setItemData(0, True)
        self.state1_combobox.setItemData(1, False)

        self.state2_combobox.setItemData(0, True)
        self.state2_combobox.setItemData(1, False)

        self.monoflop = Monoflop(self.dr,
                                 [1, 2],
                                 [self.state1_combobox, self.state2_combobox],
                                 self.cb_state_change_by_monoflop,
                                 [self.time1_spinbox, self.time2_spinbox],
                                 None,
                                 self)

        self.dr1_button.clicked.connect(self.dr1_clicked)
        self.dr2_button.clicked.connect(self.dr2_clicked)

        self.go1_button.clicked.connect(self.go1_clicked)
        self.go2_button.clicked.connect(self.go2_clicked)

        self.a1_pixmap = load_masked_pixmap('plugin_system/plugins/dual_relay/relay_a1.bmp')
        self.a2_pixmap = load_masked_pixmap('plugin_system/plugins/dual_relay/relay_a2.bmp')
        self.b1_pixmap = load_masked_pixmap('plugin_system/plugins/dual_relay/relay_b1.bmp')
        self.b2_pixmap = load_masked_pixmap('plugin_system/plugins/dual_relay/relay_b2.bmp')

    def get_state_async(self, dr1, dr2):
        width = self.dr1_button.width()

        if self.dr1_button.minimumWidth() < width:
            self.dr1_button.setMinimumWidth(width)

        width = self.dr2_button.width()

        if self.dr2_button.minimumWidth() < width:
            self.dr2_button.setMinimumWidth(width)

        if dr1:
            self.dr1_button.setText('Switch Off')
            self.dr1_image.setPixmap(self.a1_pixmap)
        else:
            self.dr1_button.setText('Switch On')
            self.dr1_image.setPixmap(self.b1_pixmap)

        if dr2:
            self.dr2_button.setText('Switch Off')
            self.dr2_image.setPixmap(self.a2_pixmap)
        else:
            self.dr2_button.setText('Switch On')
            self.dr2_image.setPixmap(self.b2_pixmap)

    def start(self):
        async_call(self.dr.get_state, None, self.get_state_async, self.increase_error_count,
                   expand_result_tuple_for_callback=True)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletDualRelay.DEVICE_IDENTIFIER

    def dr1_clicked(self):
        width = self.dr1_button.width()

        if self.dr1_button.minimumWidth() < width:
            self.dr1_button.setMinimumWidth(width)

        state = 'On' in self.dr1_button.text().replace('&', '')

        if state:
            self.dr1_button.setText('Switch Off')
            self.dr1_image.setPixmap(self.a1_pixmap)
        else:
            self.dr1_button.setText('Switch On')
            self.dr1_image.setPixmap(self.b1_pixmap)

        async_call(self.dr.set_selected_state, (1, state), None, self.increase_error_count)

    def dr2_clicked(self):
        width = self.dr2_button.width()

        if self.dr2_button.minimumWidth() < width:
            self.dr2_button.setMinimumWidth(width)

        state = 'On' in self.dr2_button.text().replace('&', '')

        if state:
            self.dr2_button.setText('Switch Off')
            self.dr2_image.setPixmap(self.a2_pixmap)
        else:
            self.dr2_button.setText('Switch On')
            self.dr2_image.setPixmap(self.b2_pixmap)

        async_call(self.dr.set_selected_state, (2, state), None, self.increase_error_count)

    def go1_clicked(self):
        self.monoflop.trigger(1)

    def go2_clicked(self):
        self.monoflop.trigger(2)

    def cb_state_change_by_monoflop(self, relay, state):
        if relay == 1:
            if state:
                self.dr1_button.setText('Switch Off')
                self.dr1_image.setPixmap(self.a1_pixmap)
            else:
                self.dr1_button.setText('Switch On')
                self.dr1_image.setPixmap(self.b1_pixmap)
        elif relay == 2:
            if state:
                self.dr2_button.setText('Switch Off')
                self.dr2_image.setPixmap(self.a2_pixmap)
            else:
                self.dr2_button.setText('Switch On')
                self.dr2_image.setPixmap(self.b2_pixmap)
Exemplo n.º 11
0
class IndustrialDigitalOut4V2(COMCUPluginBase, Ui_IndustrialDigitalOut4V2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIndustrialDigitalOut4V2, *args)

        self.setupUi(self)

        self.ido4 = self.device

        self.has_monoflop_abort = None

        self.pixmap_low = load_masked_pixmap(
            'plugin_system/plugins/industrial_digital_out_4_v2/ido4_low.bmp')
        self.pixmap_high = load_masked_pixmap(
            'plugin_system/plugins/industrial_digital_out_4_v2/ido4_high.bmp')

        self.btn_v_c = [
            self.btn_v_c0, self.btn_v_c1, self.btn_v_c2, self.btn_v_c3
        ]
        self.lbl_s_i_c = [
            self.lbl_s_i_c0, self.lbl_s_i_c1, self.lbl_s_i_c2, self.lbl_s_i_c3
        ]
        self.cbox_clc_c = [
            self.cbox_clc_c0, self.cbox_clc_c1, self.cbox_clc_c2,
            self.cbox_clc_c3
        ]

        # Set initial channel status icon
        for lbl in self.lbl_s_i_c:
            lbl.setPixmap(self.pixmap_low)

        # Register value toggle button slots
        for c, b in enumerate(self.btn_v_c):
            b.clicked.connect(functools.partial(self.btn_v_c_clicked, c))

        # Monoflop
        self.cbox_m_c.currentIndexChanged.connect(self.cbox_m_c_changed)
        self.btn_m_go.clicked.connect(self.btn_m_go_clicked)

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(4):
            self.cbox_m_c.setItemData(i, i)

            monoflop_value = QComboBox()
            monoflop_value.addItem('High', True)
            monoflop_value.addItem('Low', False)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QDoubleSpinBox()

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.ido4, [0, 1, 2, 3], self.monoflop_values,
                                 self.cb_value_change_by_monoflop,
                                 self.monoflop_times, None, self)

        # Channel status LED config
        self.cbox_clc_c0.currentIndexChanged.connect(self.cbox_clc_c0_changed)
        self.cbox_clc_c1.currentIndexChanged.connect(self.cbox_clc_c1_changed)
        self.cbox_clc_c2.currentIndexChanged.connect(self.cbox_clc_c2_changed)
        self.cbox_clc_c3.currentIndexChanged.connect(self.cbox_clc_c3_changed)

    def get_value_async(self, value):
        for i, b in enumerate(self.btn_v_c):
            if value[i]:
                b.setText('Set Low')
                self.lbl_s_i_c[i].setPixmap(self.pixmap_high)
            else:
                b.setText('Set High')
                self.lbl_s_i_c[i].setPixmap(self.pixmap_low)

    def get_channel_led_config_async(self, channel, config):
        if channel == 0:
            self.cbox_clc_c0.setCurrentIndex(config)
        elif channel == 1:
            self.cbox_clc_c1.setCurrentIndex(config)
        elif channel == 2:
            self.cbox_clc_c2.setCurrentIndex(config)
        elif channel == 3:
            self.cbox_clc_c3.setCurrentIndex(config)

    def cbox_clc_c0_changed(self, config):
        self.ido4.set_channel_led_config(0, config)

    def cbox_clc_c1_changed(self, config):
        self.ido4.set_channel_led_config(1, config)

    def cbox_clc_c2_changed(self, config):
        self.ido4.set_channel_led_config(2, config)

    def cbox_clc_c3_changed(self, config):
        self.ido4.set_channel_led_config(3, config)

    def start(self):
        # the firmware version might change between init and start of a Co-MCU
        # Bricklet plugin, because a Co-MCU Bricklet can be restarted without
        # recreating the plugin. therefore, the firmware version has to be checked
        # on every start
        self.has_monoflop_abort = self.firmware_version >= (2, 0, 1)

        async_call(self.ido4.get_value, None, self.get_value_async,
                   self.increase_error_count)

        for channel in range(4):
            async_call(self.ido4.get_channel_led_config,
                       channel,
                       self.get_channel_led_config_async,
                       self.increase_error_count,
                       pass_arguments_to_result_callback=True)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialDigitalOut4V2.DEVICE_IDENTIFIER

    def btn_v_c_clicked(self, channel):
        value = 'High' in self.btn_v_c[channel].text().replace('&', '')

        if value:
            self.btn_v_c[channel].setText('Set Low')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_high)
        else:
            self.btn_v_c[channel].setText('Set High')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_low)

        if not self.has_monoflop_abort and self.monoflop.active(channel):
            # abuse monoflop to set selected value while also aborting an active
            # monoflop, because firmware version < 2.0.1 doesn't abort an active
            # monoflop if the set-value or set-selected-value function is called.
            # this workaround has the disadvantage of shortly inverting the
            # output value before settling on the requested value. that's why it
            # is only used if a monoflop is really active
            async_call(self.ido4.set_monoflop, (channel, not value, 0), None,
                       self.increase_error_count)
        else:
            async_call(self.ido4.set_selected_value, (channel, value), None,
                       self.increase_error_count)

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.btn_v_c[channel].setText('Set Low')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_high)
        else:
            self.btn_v_c[channel].setText('Set High')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_low)

    def cbox_m_c_changed(self):
        channel = self.cbox_m_c.currentIndex()

        if channel < 0:
            return

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

    def btn_m_go_clicked(self):
        channel = self.cbox_m_c.currentIndex()

        if channel < 0:
            return

        self.monoflop.trigger(channel)
Exemplo n.º 12
0
Arquivo: io4.py Projeto: fk0815/brickv
class IO4(PluginBase, Ui_IO4):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletIO4, *args)

        self.setupUi(self)

        self.io = self.device

        self.cbe_value = CallbackEmulator(self, self.io.get_value, None,
                                          self.cb_value,
                                          self.increase_error_count)

        self.port_value = [self.av0, self.av1, self.av2, self.av3]
        self.port_direction = [self.ad0, self.ad1, self.ad2, self.ad3]
        self.port_config = [self.ac0, self.ac1, self.ac2, self.ac3]
        self.port_time = [self.at0, self.at1, self.at2, self.at3]

        self.save_button.clicked.connect(self.save_clicked)
        self.pin_box.currentIndexChanged.connect(self.pin_changed)
        self.direction_box.currentIndexChanged.connect(self.direction_changed)
        self.debounce_save.clicked.connect(self.debounce_save_clicked)
        self.go_button.clicked.connect(self.go_clicked)

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(4):
            monoflop_value = QComboBox()
            monoflop_value.addItem('High', 1)
            monoflop_value.addItem('Low', 0)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QDoubleSpinBox()

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.io, [0, 1, 2, 3],
                                 self.monoflop_values,
                                 self.cb_value_change_by_monoflop,
                                 self.monoflop_times,
                                 self.port_time,
                                 self,
                                 setter_uses_bitmasks=True,
                                 callback_uses_bitmasks=True)

        self.pin_changed(0)

    def init_async(self):
        self.init_value = 0
        self.init_dir = 0
        self.init_config = 0

        def get_port_async(value):
            self.init_value = value
            next(self.init_async_generator)

        def get_port_configuration_async(conf):
            self.init_dir, self.init_config = conf
            next(self.init_async_generator)

        def get_debounce_period_async(debounce_period):
            self.debounce_edit.setText(str(debounce_period))
            self.pin_changed(0)

        async_call(self.io.get_value, None, get_port_async,
                   self.increase_error_count)
        yield

        async_call(self.io.get_configuration, None,
                   get_port_configuration_async, self.increase_error_count)
        yield

        self.init_values(self.init_value, self.init_dir, self.init_config)

        async_call(self.io.get_debounce_period, None,
                   get_debounce_period_async, self.increase_error_count)

    def start(self):
        self.init_async_generator = self.init_async()
        next(self.init_async_generator)

        self.cbe_value.set_period(50)

        self.monoflop.start()

    def stop(self):
        self.cbe_value.set_period(0)

        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIO4.DEVICE_IDENTIFIER

    def init_values(self, value, direction, config):
        for i in range(4):
            if direction & (1 << i):
                self.port_direction[i].setText('Input')

                if config & (1 << i):
                    self.port_config[i].setText('Pull-Up')
                else:
                    self.port_config[i].setText('Default')
            else:
                self.port_direction[i].setText('Output')
                self.port_config[i].setText('-')

            if value & (1 << i):
                self.port_value[i].setText('High')
            else:
                self.port_value[i].setText('Low')

        self.update_monoflop_ui_state()

    def update_monoflop_ui_state(self):
        pin = int(self.pin_box.currentText())

        self.go_button.setEnabled(
            self.port_direction[pin].text().replace('&', '') == 'Output')

    def save_clicked(self):
        pin = int(self.pin_box.currentText())
        direction = self.direction_box.currentText()[0].lower()

        if direction == 'o':
            value = self.value_box.currentText() == 'High'
            self.port_value[pin].setText(self.value_box.currentText())
        else:
            value = self.value_box.currentText() == 'Pull-Up'

        async_call(self.io.set_configuration, (1 << pin, direction, value),
                   None, self.increase_error_count)

        self.port_direction[pin].setText(self.direction_box.currentText())

        if direction == 'i':
            self.port_config[pin].setText(self.value_box.currentText())
        else:
            self.port_config[pin].setText('-')

        self.update_monoflop_ui_state()

    def cb_value(self, value):
        for i in range(4):
            if value & (1 << i):
                self.port_value[i].setText('High')
            else:
                self.port_value[i].setText('Low')

    def pin_changed(self, pin):
        if self.port_direction[pin].text().replace('&', '') == 'Input':
            index = 0
        else:
            index = 1

        self.direction_box.setCurrentIndex(index)
        self.direction_changed(index)

        self.monoflop_time_stack.setCurrentIndex(pin)
        self.monoflop_value_stack.setCurrentIndex(pin)

        self.update_monoflop_ui_state()

    def direction_changed(self, direction):
        pin = int(self.pin_box.currentText())

        self.value_box.clear()

        if direction == 1:
            self.value_label.setText('Value:')
            self.value_box.addItem('High')
            self.value_box.addItem('Low')

            if self.port_value[pin].text().replace('&', '') == 'High':
                self.value_box.setCurrentIndex(0)
            else:
                self.value_box.setCurrentIndex(1)
        else:
            self.value_label.setText('Config:')
            self.value_box.addItem('Pull-Up')
            self.value_box.addItem('Default')

            if self.port_config[pin].text().replace('&', '') == 'Pull-Up':
                self.value_box.setCurrentIndex(0)
            else:
                self.value_box.setCurrentIndex(1)

        self.update_monoflop_ui_state()

    def debounce_save_clicked(self):
        debounce = int(self.debounce_edit.text())

        async_call(self.io.set_debounce_period, debounce, None,
                   self.increase_error_count)

    def go_clicked(self):
        pin = int(self.pin_box.currentText())

        self.monoflop.trigger(pin)

    def cb_value_change_by_monoflop(self, pin, value):
        if value:
            self.port_value[pin].setText('High')
        else:
            self.port_value[pin].setText('Low')

        self.port_config[pin].setText('-')

        selected_pin = int(self.pin_box.currentText())

        if pin == selected_pin:
            if value:
                self.value_box.setCurrentIndex(0)
            else:
                self.value_box.setCurrentIndex(1)
Exemplo n.º 13
0
class IndustrialQuadRelayV2(COMCUPluginBase, Ui_IndustrialQuadRelayV2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIndustrialQuadRelayV2, *args)

        self.setupUi(self)

        self.iqr = self.device

        self.open_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_quad_relay/relay_open.bmp')
        self.close_pixmap = load_masked_pixmap('plugin_system/plugins/industrial_quad_relay/relay_close.bmp')

        self.relay_buttons = [self.b0, self.b1, self.b2, self.b3]
        self.relay_button_icons = [self.b0_icon, self.b1_icon, self.b2_icon, self.b3_icon]
        self.relay_button_labels = [self.b0_label, self.b1_label, self.b2_label, self.b3_label]

        for icon in self.relay_button_icons:
            icon.setPixmap(self.open_pixmap)
            icon.show()

        for i in range(len(self.relay_buttons)):
            self.relay_buttons[i].clicked.connect(functools.partial(self.relay_button_clicked, i))

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(4):
            self.monoflop_channel.setItemData(i, i)

            monoflop_value = QComboBox()
            monoflop_value.addItem('On', True)
            monoflop_value.addItem('Off', False)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QSpinBox()
            monoflop_time.setRange(1, (1 << 31) - 1)
            monoflop_time.setValue(1000)

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.iqr,
                                 [0, 1, 2, 3],
                                 self.monoflop_values,
                                 self.cb_value_change_by_monoflop,
                                 self.monoflop_times,
                                 None,
                                 self)

        self.monoflop_channel.currentIndexChanged.connect(self.monoflop_channel_changed)
        self.monoflop_go.clicked.connect(self.monoflop_go_clicked)

        self.cbox_cs0_cfg.currentIndexChanged.connect(self.cbox_cs0_cfg_changed)
        self.cbox_cs1_cfg.currentIndexChanged.connect(self.cbox_cs1_cfg_changed)
        self.cbox_cs2_cfg.currentIndexChanged.connect(self.cbox_cs2_cfg_changed)
        self.cbox_cs3_cfg.currentIndexChanged.connect(self.cbox_cs3_cfg_changed)

    def get_value_async(self, value):
        for button in range(4):
            if value[button]:
                self.relay_buttons[button].setText('Switch Off')
                self.relay_button_icons[button].setPixmap(self.close_pixmap)
            else:
                self.relay_buttons[button].setText('Switch On')
                self.relay_button_icons[button].setPixmap(self.open_pixmap)

    def get_channel_led_config_async(self, idx, cfg):
        if idx == 0:
            self.cbox_cs0_cfg.setCurrentIndex(cfg)
        elif idx == 1:
            self.cbox_cs1_cfg.setCurrentIndex(cfg)
        elif idx == 2:
            self.cbox_cs2_cfg.setCurrentIndex(cfg)
        elif idx == 3:
            self.cbox_cs3_cfg.setCurrentIndex(cfg)

    def cbox_cs0_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(0, idx)

    def cbox_cs1_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(1, idx)

    def cbox_cs2_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(2, idx)

    def cbox_cs3_cfg_changed(self, idx):
        self.iqr.set_channel_led_config(3, idx)

    def start(self):
        async_call(self.iqr.get_value, None, self.get_value_async, self.increase_error_count)

        for channel in range(4):
            async_call(self.iqr.get_channel_led_config, channel, self.get_channel_led_config_async, self.increase_error_count,
                       pass_arguments_to_result_callback=True)

        self.monoflop.start()

    def stop(self):
        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialQuadRelayV2.DEVICE_IDENTIFIER

    def relay_button_clicked(self, button):
        value = 'On' in self.relay_buttons[button].text().replace('&', '')

        if value:
            self.relay_buttons[button].setText('Switch Off')
            self.relay_button_icons[button].setPixmap(self.close_pixmap)
        else:
            self.relay_buttons[button].setText('Switch On')
            self.relay_button_icons[button].setPixmap(self.open_pixmap)

        self.iqr.set_selected_value(button, value)

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.relay_buttons[channel].setText('Switch Off')
            self.relay_button_icons[channel].setPixmap(self.close_pixmap)
        else:
            self.relay_buttons[channel].setText('Switch On')
            self.relay_button_icons[channel].setPixmap(self.open_pixmap)

    def monoflop_channel_changed(self):
        channel = self.monoflop_channel.currentData()

        if channel == None:
            return

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

    def monoflop_go_clicked(self):
        channel = self.monoflop_channel.currentData()

        if channel == None:
            return

        self.monoflop.trigger(channel)
Exemplo n.º 14
0
class IO16V2(COMCUPluginBase, Ui_IO16V2):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIO16V2, *args)

        self.setupUi(self)

        self.io = self.device

        self.io.set_response_expected(self.io.FUNCTION_SET_CONFIGURATION, True)

        self.cbe_value = CallbackEmulator(self.io.get_value,
                                          None,
                                          self.cb_value,
                                          self.increase_error_count)

        self.config_direction = [None] * 16
        self.config_value = [None] * 16

        self.lbl_st_ch_v = [self.lbl_st_ch0_v,
                            self.lbl_st_ch1_v,
                            self.lbl_st_ch2_v,
                            self.lbl_st_ch3_v,
                            self.lbl_st_ch4_v,
                            self.lbl_st_ch5_v,
                            self.lbl_st_ch6_v,
                            self.lbl_st_ch7_v,
                            self.lbl_st_ch8_v,
                            self.lbl_st_ch9_v,
                            self.lbl_st_ch10_v,
                            self.lbl_st_ch11_v,
                            self.lbl_st_ch12_v,
                            self.lbl_st_ch13_v,
                            self.lbl_st_ch14_v,
                            self.lbl_st_ch15_v]

        self.lbl_st_ch_d = [self.lbl_st_ch0_d,
                            self.lbl_st_ch1_d,
                            self.lbl_st_ch2_d,
                            self.lbl_st_ch3_d,
                            self.lbl_st_ch4_d,
                            self.lbl_st_ch5_d,
                            self.lbl_st_ch6_d,
                            self.lbl_st_ch7_d,
                            self.lbl_st_ch8_d,
                            self.lbl_st_ch9_d,
                            self.lbl_st_ch10_d,
                            self.lbl_st_ch11_d,
                            self.lbl_st_ch12_d,
                            self.lbl_st_ch13_d,
                            self.lbl_st_ch14_d,
                            self.lbl_st_ch15_d]

        self.lbl_st_ch_cfg = [self.lbl_st_ch0_cfg,
                              self.lbl_st_ch1_cfg,
                              self.lbl_st_ch2_cfg,
                              self.lbl_st_ch3_cfg,
                              self.lbl_st_ch4_cfg,
                              self.lbl_st_ch5_cfg,
                              self.lbl_st_ch6_cfg,
                              self.lbl_st_ch7_cfg,
                              self.lbl_st_ch8_cfg,
                              self.lbl_st_ch9_cfg,
                              self.lbl_st_ch10_cfg,
                              self.lbl_st_ch11_cfg,
                              self.lbl_st_ch12_cfg,
                              self.lbl_st_ch13_cfg,
                              self.lbl_st_ch14_cfg,
                              self.lbl_st_ch15_cfg]

        self.lbl_st_ch_monoflop_t = [self.lbl_st_ch0_monoflop_t,
                                     self.lbl_st_ch1_monoflop_t,
                                     self.lbl_st_ch2_monoflop_t,
                                     self.lbl_st_ch3_monoflop_t,
                                     self.lbl_st_ch4_monoflop_t,
                                     self.lbl_st_ch5_monoflop_t,
                                     self.lbl_st_ch6_monoflop_t,
                                     self.lbl_st_ch7_monoflop_t,
                                     self.lbl_st_ch8_monoflop_t,
                                     self.lbl_st_ch9_monoflop_t,
                                     self.lbl_st_ch10_monoflop_t,
                                     self.lbl_st_ch11_monoflop_t,
                                     self.lbl_st_ch12_monoflop_t,
                                     self.lbl_st_ch13_monoflop_t,
                                     self.lbl_st_ch14_monoflop_t,
                                     self.lbl_st_ch15_monoflop_t]

        self.cbox_cfg_ch_dir.setItemData(0, self.io.DIRECTION_IN)
        self.cbox_cfg_ch_dir.setItemData(1, self.io.DIRECTION_OUT)

        self.cbox_cfg_ch_v.setItemData(0, True)
        self.cbox_cfg_ch_v.setItemData(1, False)

        self.btn_monoflop_go.clicked.connect(self.btn_monoflop_go_clicked)
        self.btn_cfg_ch_save.clicked.connect(self.btn_cfg_ch_save_clicked)
        self.cbox_cfg_ch.currentIndexChanged.connect(self.cbox_cfg_ch_changed)
        self.cbox_cfg_ch_dir.currentIndexChanged.connect(self.cbox_cfg_ch_dir_changed)

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(16):
            monoflop_value = QComboBox()
            monoflop_value.addItem('High', 1)
            monoflop_value.addItem('Low', 0)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QSpinBox()
            monoflop_time.setRange(1, (1 << 31) - 1)
            monoflop_time.setValue(1000)

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.io,
                                 list(range(16)),
                                 self.monoflop_values,
                                 self.cb_value_change_by_monoflop,
                                 self.monoflop_times,
                                 self.lbl_st_ch_monoflop_t,
                                 self,
                                 handle_get_monoflop_invalid_parameter_as_abort=True)

    def get_configuration_async(self, channel, direction, value):
        self.config_direction[channel] = direction
        self.config_value[channel] = value

        if direction == self.io.DIRECTION_IN:
            self.lbl_st_ch_d[channel].setText('Input')

            if value:
                self.lbl_st_ch_cfg[channel].setText('Pull-Up')
            else:
                self.lbl_st_ch_cfg[channel].setText('Default')
        else:
            self.lbl_st_ch_d[channel].setText('Output')
            self.lbl_st_ch_cfg[channel].setText('-')

        if None not in self.config_direction: # got all channel data
            self.cbox_cfg_ch_changed(self.cbox_cfg_ch.currentIndex())

    def start(self):
        self.config_direction = [None] * 16
        self.config_value = [None] * 16

        for channel in range(16):
            async_call(self.io.get_configuration, channel, self.get_configuration_async, self.increase_error_count,
                       pass_arguments_to_result_callback=True, expand_result_tuple_for_callback=True)

        self.cbe_value.set_period(50)

        self.monoflop.start()

    def stop(self):
        self.cbe_value.set_period(0)

        self.monoflop.stop()

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIO16V2.DEVICE_IDENTIFIER

    def cb_value(self, value):
        for i in range(16):
            if value[i]:
                self.lbl_st_ch_v[i].setText('High')
            else:
                self.lbl_st_ch_v[i].setText('Low')

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.lbl_st_ch_v[channel].setText('High')
        else:
            self.lbl_st_ch_v[channel].setText('Low')

    def btn_monoflop_go_clicked(self):
        channel = self.cbox_cfg_ch.currentIndex()

        if channel < 0:
            return

        self.monoflop.trigger(channel)

    def btn_cfg_ch_save_clicked(self):
        channel = self.cbox_cfg_ch.currentIndex()
        direction = self.cbox_cfg_ch_dir.currentData()
        value = self.cbox_cfg_ch_v.currentData()

        if channel < 0 or direction == None or value == None:
            return

        async_call(self.io.set_configuration, (channel, direction, value), None, self.increase_error_count,
                   pass_arguments_to_result_callback=True, expand_arguments_tuple_for_callback=True)
        async_call(self.io.get_configuration, channel, self.get_configuration_async, self.increase_error_count,
                   pass_arguments_to_result_callback=True, expand_result_tuple_for_callback=True)

    def cbox_cfg_ch_changed(self, channel):
        if channel < 0:
            return

        direction = self.config_direction[channel]
        direction_index = self.cbox_cfg_ch_dir.findData(direction)

        self.cbox_cfg_ch_dir.setCurrentIndex(direction_index)
        self.cbox_cfg_ch_dir_changed(direction_index)

        value = self.config_value[channel]
        value_index = self.cbox_cfg_ch_v.findData(value)

        self.cbox_cfg_ch_v.setCurrentIndex(value_index)

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

        self.btn_monoflop_go.setEnabled(direction == self.io.DIRECTION_OUT)

    def cbox_cfg_ch_dir_changed(self, index):
        channel = self.cbox_cfg_ch.currentIndex()
        direction = self.cbox_cfg_ch_dir.currentData()

        if channel < 0 or direction == None:
            return

        self.cbox_cfg_ch_v.clear()

        if direction == self.io.DIRECTION_IN:
            self.lbl_cfg_ch_v.setText('Configuration:')
            self.cbox_cfg_ch_v.addItem('Pull-Up', True)
            self.cbox_cfg_ch_v.addItem('Default', False)
        else:
            self.lbl_cfg_ch_v.setText('Value:')
            self.cbox_cfg_ch_v.addItem('High', True)
            self.cbox_cfg_ch_v.addItem('Low', False)

        value = self.config_value[channel]
        value_index = self.cbox_cfg_ch_v.findData(value)

        self.cbox_cfg_ch_v.setCurrentIndex(value_index)
class IndustrialDigitalOutHS4(COMCUPluginBase, Ui_IndustrialDigitalOutHS4):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletIndustrialDigitalOutHS4, *args)

        self.setupUi(self)

        self.ido4 = self.device

        self.pixmap_low = load_masked_pixmap('plugin_system/plugins/industrial_digital_out_hs_4/ido4_low.bmp')
        self.pixmap_high = load_masked_pixmap('plugin_system/plugins/industrial_digital_out_hs_4/ido4_high.bmp')

        self.btn_v_c = [self.btn_v_c0, self.btn_v_c1, self.btn_v_c2, self.btn_v_c3]
        self.lbl_s_i_c = [self.lbl_s_i_c0, self.lbl_s_i_c1, self.lbl_s_i_c2, self.lbl_s_i_c3]
        self.cbox_clc_c = [self.cbox_clc_c0, self.cbox_clc_c1, self.cbox_clc_c2, self.cbox_clc_c3]

        self.lbl_vol = [self.lbl_vol0, self.lbl_vol1, self.lbl_vol2, self.lbl_vol3]
        self.lbl_cur = [self.lbl_cur0, self.lbl_cur1, self.lbl_cur2, self.lbl_cur3]

        # Set initial channel status icon
        for lbl in self.lbl_s_i_c:
            lbl.setPixmap(self.pixmap_low)

        # Register value toggle button slots
        for c, b in enumerate(self.btn_v_c):
            b.clicked.connect(functools.partial(self.btn_v_c_clicked, c))

        # Monoflop
        self.cbox_m_c.currentIndexChanged.connect(self.cbox_m_c_changed)
        self.btn_m_go.clicked.connect(self.btn_m_go_clicked)

        self.monoflop_values = []
        self.monoflop_times = []

        for i in range(4):
            self.cbox_m_c.setItemData(i, i)

            monoflop_value = QComboBox()
            monoflop_value.addItem('High', True)
            monoflop_value.addItem('Low', False)

            self.monoflop_values.append(monoflop_value)
            self.monoflop_value_stack.addWidget(monoflop_value)

            monoflop_time = QSpinBox()
            monoflop_time.setRange(1, (1 << 31) - 1)
            monoflop_time.setValue(1000)

            self.monoflop_times.append(monoflop_time)
            self.monoflop_time_stack.addWidget(monoflop_time)

        self.monoflop = Monoflop(self.ido4,
                                 [0, 1, 2, 3],
                                 self.monoflop_values,
                                 self.cb_value_change_by_monoflop,
                                 self.monoflop_times,
                                 None,
                                 self)

        # Channel status LED config
        self.cbox_clc_c0.currentIndexChanged.connect(self.cbox_clc_c0_changed)
        self.cbox_clc_c1.currentIndexChanged.connect(self.cbox_clc_c1_changed)
        self.cbox_clc_c2.currentIndexChanged.connect(self.cbox_clc_c2_changed)
        self.cbox_clc_c3.currentIndexChanged.connect(self.cbox_clc_c3_changed)

        # Measurements
        self.cbe_measurements = CallbackEmulator(self.ido4.get_measurements,
                                                 None,
                                                 self.cb_measurements,
                                                 self.increase_error_count)

    def cb_measurements(self, measurements):
        self.lbl_vol[0].setText('{0:.2f} V'.format(measurements.voltage[0] / 1000.0))
        self.lbl_vol[1].setText('{0:.2f} V'.format(measurements.voltage[0] / 1000.0))
        self.lbl_vol[2].setText('{0:.2f} V'.format(measurements.voltage[1] / 1000.0))
        self.lbl_vol[3].setText('{0:.2f} V'.format(measurements.voltage[1] / 1000.0))

        self.lbl_cur[0].setText('{0} mA'.format(measurements.current[0]))
        self.lbl_cur[1].setText('{0} mA'.format(measurements.current[1]))
        self.lbl_cur[2].setText('{0} mA'.format(measurements.current[2]))
        self.lbl_cur[3].setText('{0} mA'.format(measurements.current[3]))

    def get_value_async(self, value):
        for i, b in enumerate(self.btn_v_c):
            if value[i]:
                b.setText('Set Low')
                self.lbl_s_i_c[i].setPixmap(self.pixmap_high)
            else:
                b.setText('Set High')
                self.lbl_s_i_c[i].setPixmap(self.pixmap_low)

    def get_channel_led_config_async(self, channel, config):
        if channel == 0:
            self.cbox_clc_c0.setCurrentIndex(config)
        elif channel == 1:
            self.cbox_clc_c1.setCurrentIndex(config)
        elif channel == 2:
            self.cbox_clc_c2.setCurrentIndex(config)
        elif channel == 3:
            self.cbox_clc_c3.setCurrentIndex(config)

    def cbox_clc_c0_changed(self, config):
        self.ido4.set_channel_led_config(0, config)

    def cbox_clc_c1_changed(self, config):
        self.ido4.set_channel_led_config(1, config)

    def cbox_clc_c2_changed(self, config):
        self.ido4.set_channel_led_config(2, config)

    def cbox_clc_c3_changed(self, config):
        self.ido4.set_channel_led_config(3, config)

    def start(self):
        async_call(self.ido4.get_value, None, self.get_value_async, self.increase_error_count)

        for channel in range(4):
            async_call(self.ido4.get_channel_led_config, channel, self.get_channel_led_config_async, self.increase_error_count,
                       pass_arguments_to_result_callback=True)

        self.cbe_measurements.set_period(250)

        self.monoflop.start()

    def stop(self):
        self.cbe_measurements.set_period(0)

        self.monoflop.stop()

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialDigitalOutHS4.DEVICE_IDENTIFIER

    def btn_v_c_clicked(self, channel):
        value = 'High' in self.btn_v_c[channel].text().replace('&', '')

        if value:
            self.btn_v_c[channel].setText('Set Low')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_high)
        else:
            self.btn_v_c[channel].setText('Set High')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_low)

        async_call(self.ido4.set_selected_value, (channel, value), None, self.increase_error_count)

    def cb_value_change_by_monoflop(self, channel, value):
        if value:
            self.btn_v_c[channel].setText('Set Low')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_high)
        else:
            self.btn_v_c[channel].setText('Set High')
            self.lbl_s_i_c[channel].setPixmap(self.pixmap_low)

    def cbox_m_c_changed(self):
        channel = self.cbox_m_c.currentIndex()

        if channel < 0:
            return

        self.monoflop_time_stack.setCurrentIndex(channel)
        self.monoflop_value_stack.setCurrentIndex(channel)

    def btn_m_go_clicked(self):
        channel = self.cbox_m_c.currentIndex()

        if channel < 0:
            return

        self.monoflop.trigger(channel)