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)
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)
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)