You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vguz_v2/i2c/i2c_integrated_widget.py

186 lines
6.4 KiB

#!/usr/bin/env python3
"""
I2C Control Widget - Integrated
================================
Command table (left) + I2C core widget (right)
Author: Kynsight
Version: 3.0.0
"""
from PyQt6.QtWidgets import QWidget, QHBoxLayout, QSplitter
from PyQt6.QtCore import Qt, pyqtSignal
from command_table.command_table import CommandTableWidget
from i2c.i2c_kit.i2c_core_widget import I2CWidget
class I2CControlWidget(QWidget):
"""
Integrated I2C control widget.
Layout: Command table (left) | I2C core (right)
Signals:
command_sent: (command_id, operation, register)
reading_received: (reading_info)
connection_changed: (is_connected)
"""
command_sent = pyqtSignal(int, str, str) # command_id, operation, register
reading_received = pyqtSignal(object)
connection_changed = pyqtSignal(bool)
def __init__(self, db_connection, parent=None):
super().__init__(parent)
self.conn = db_connection
self._init_ui()
self._setup_connections()
def _init_ui(self):
"""Initialize UI - side by side layout."""
layout = QHBoxLayout()
self.setLayout(layout)
# Splitter for resizable layout
splitter = QSplitter(Qt.Orientation.Horizontal)
# Left: Command table
self.command_table = CommandTableWidget(self.conn, 'i2c')
splitter.addWidget(self.command_table)
# Right: I2C core widget
self.i2c_core = I2CWidget()
splitter.addWidget(self.i2c_core)
# Set initial sizes (40% table, 60% core)
splitter.setSizes([400, 600])
layout.addWidget(splitter)
# Initialize buses on startup
self.i2c_core._refresh_buses()
# Table always enabled, CRUD buttons disabled initially (not connected)
self._update_table_mode(False)
def _setup_connections(self):
"""Connect signals between table and core."""
# Command table → Execute via I2C (when connected) OR Edit (when disconnected)
self.command_table.command_double_clicked.connect(self._on_command_double_click)
# I2C connection → Change table mode
self.i2c_core.connection_changed.connect(self._on_connection_changed)
# Forward I2C signals
self.i2c_core.reading_received.connect(self.reading_received.emit)
def _update_table_mode(self, is_connected):
"""Update table mode based on connection state."""
if is_connected:
# Connected mode: CRUD buttons disabled, double-click executes
self.command_table.btn_add.setEnabled(False)
self.command_table.btn_edit.setEnabled(False)
self.command_table.btn_delete.setEnabled(False)
else:
# Disconnected mode: CRUD buttons enabled, double-click edits
self.command_table.btn_add.setEnabled(True)
# Edit/Delete enabled only if something selected
has_selection = bool(self.command_table.table.selectedItems())
self.command_table.btn_edit.setEnabled(has_selection)
self.command_table.btn_delete.setEnabled(has_selection)
def _on_command_double_click(self, command_id, cmd_data):
"""Handle double-click: Execute if connected, Edit if disconnected."""
if self.i2c_core.is_connected:
# Connected: Execute command
self._execute_command(command_id, cmd_data)
else:
# Disconnected: Edit command
self.command_table._edit_command()
def _execute_command(self, command_id, cmd_data):
"""Execute I2C command."""
operation = cmd_data.get('operation', '')
register = cmd_data.get('register', '')
hex_string = cmd_data.get('hex_string', '')
device_address = cmd_data.get('device_address', '0x40')
if not operation or not register:
return
try:
# Remove 0x prefix if present for consistency
device_addr_clean = device_address.replace('0x', '').replace('0X', '')
register_clean = register.replace('0x', '').replace('0X', '')
# Populate manual I/O fields (correct field names from i2c_core_widget)
self.i2c_core.edit_io_addr.setText(device_addr_clean)
self.i2c_core.edit_io_reg.setText(register_clean)
if operation == 'read':
# Determine bytes to read
if 'Angle' in cmd_data.get('command_name', ''):
num_bytes = 2
elif 'Magnitude' in cmd_data.get('command_name', ''):
num_bytes = 2
else:
num_bytes = 1
# Set length
self.i2c_core.spin_io_length.setValue(num_bytes)
# Trigger read (use the button's method)
self.i2c_core._on_read()
else: # write
# Parse data value and set write data field
if hex_string:
data_clean = hex_string.replace('0x', '').replace('0X', '')
self.i2c_core.edit_write_data.setText(data_clean)
# Trigger write
self.i2c_core._on_write()
# Emit signal
self.command_sent.emit(command_id, operation, register)
except Exception as e:
print(f"I2C execute error: {e}")
def _on_connection_changed(self, is_connected):
"""Handle connection state change."""
# Update table mode (CRUD buttons, double-click behavior)
self._update_table_mode(is_connected)
# Forward signal
self.connection_changed.emit(is_connected)
def get_i2c_core(self):
"""Get I2C core widget for direct access."""
return self.i2c_core
def get_command_table(self):
"""Get command table for direct access."""
return self.command_table
if __name__ == "__main__":
import sys
from PyQt6.QtWidgets import QApplication
import sqlite3
app = QApplication(sys.argv)
conn = sqlite3.connect("./database/ehinge.db")
widget = I2CControlWidget(conn)
widget.setWindowTitle("I2C Control - Integrated")
widget.resize(1400, 800)
widget.show()
sys.exit(app.exec())