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.
186 lines
6.4 KiB
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())
|